- 668150: Fix graph orientation: show goals at root, prerequisites as leaves - 06ca62: Fix nbd graph <id>: show ancestry path through ticket, not just subtree Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
3 months ago | |
|---|---|---|
| .. | ||
| .claude | 3 months ago | |
| .nbd | 3 months ago | |
| docs | 3 months ago | |
| src | 3 months ago | |
| tests | 3 months ago | |
| CLAUDE.md | 3 months ago | |
| Cargo.lock | 3 months ago | |
| Cargo.toml | 3 months ago | |
| PLAN.md | 3 months ago | |
| README.md | 3 months ago | |
| TODO.md | 3 months ago | |
| build.rs | 3 months ago | |
| flake.lock | 3 months ago | |
| flake.nix | 3 months ago | |
README.md
nbd
A CLI tool for managing work tickets, primarily targeted at agent workflows.
Tickets are stored as JSON files in .nbd/tickets/ inside the nearest ancestor
directory that contains a .nbd/ folder, discovered by traversing upward from
the current working directory — just like git finds .git/.
How it works
Each ticket is a JSON file named {id}.json, where id is a unique
6-character lowercase hex string (e.g. a3f9c2). Tickets carry:
| Field | Type | Default |
|---|---|---|
id |
6-char hex string | auto-generated |
title |
string | (required) |
body |
string | "" |
priority |
integer 0–10 | 5 |
status |
todo | in_progress | done | closed | archived | backlog |
todo |
ticket_type |
project | feature | task | bug |
task |
dependencies |
list of ticket IDs | [] |
Tickets can be stored in multiple formats, selected at creation time with
--ftype:
| Format | Extension | Description |
|---|---|---|
json |
.json |
Pretty-printed JSON (default) |
md |
.md |
Markdown body with TOML frontmatter |
toml |
.toml |
TOML |
jsonb |
.jsonb |
CBOR binary |
All commands accept --json for machine-readable output.
Usage
Initialise
Create the ticket store in your project root:
nbd init
Analogous to git init — safe to run multiple times.
Create a ticket
nbd create --title "Fix login bug" --priority 8 --type bug
nbd create --title "Add rate limiting" --body "Protect public endpoints" --deps a3f9c2
nbd create --title "Long-form spec" --body "# Section\n\nDetails..." --ftype md
nbd create --title "Config ticket" --ftype toml
Read a ticket
nbd read a3f9c2
nbd read a3f9c2 --json
List all tickets
By default, done, closed, archived, and backlog tickets are excluded.
nbd list # todo + in_progress only (done/closed/archived/backlog excluded)
nbd list --all # all tickets including done, closed, archived, and backlog
nbd list --filter status=* # all tickets (alias for --all via filter)
nbd list --filter status=done # only completed tickets
nbd list --filter status=archived # only archived tickets (set by nbd archive)
nbd list --filter status=closed # only closed/cancelled tickets
nbd list --filter status=backlog # only backlog tickets
nbd list --filter type=bug # non-done, non-closed, non-archived, non-backlog bug tickets
nbd list --json
Archive a ticket
Soft-delete a ticket by setting its status to archived. The file is preserved
on disk but hidden from normal listings.
nbd archive a3f9c2
nbd archive a3f9c2 --json
nbd archive is shorthand for nbd update <id> --status archived. Archived
tickets count as resolved for dependency purposes — any ticket that depends on
an archived ticket becomes unblocked.
The closed status is distinct from archived: use closed (via
nbd update <id> --status closed) for tickets that will not be completed
(cancelled, superseded, won't-fix). Both archived and closed are excluded
from normal listings and both count as resolved for dependencies.
Update a ticket
Only the flags you supply are changed; all other fields retain their current
values. Use --ftype to convert to a different storage format (the old file
is removed automatically).
nbd update a3f9c2 --status in_progress
nbd update a3f9c2 --priority 9 --type bug
nbd update a3f9c2 --ftype md # convert to markdown format
Find the next ticket to work on
Returns the single highest-priority ticket that is ready to work on — not done and with all dependencies completed:
nbd next
nbd next --json
nbd next --filter type=bug # highest-priority ready bug
nbd next --filter priority=9 # highest-priority ready ticket at priority 9
Exits 0 even when no ready ticket exists ({"next": null} in JSON mode).
Find all actionable tickets
List all tickets that are ready to work on — not done and with all dependencies completed:
nbd ready
nbd ready --json
Visualise dependencies
Draw an ASCII dependency graph showing which tickets block which others. Roots (tickets with no dependencies) appear at the top; tickets that depend on them are indented below using box-drawing characters:
nbd graph # full dependency forest
nbd graph <id> # subtree rooted at the given ticket
nbd graph --json # machine-readable adjacency list
nbd graph <id> --json # machine-readable subtree
nbd graph --filter type=bug # only bug tickets and their dependents
Example output:
a3f9c2 [done] Fix login bug
├── b7d41e [in_progress] Add rate limiting
│ └── c9e823 [todo] Write tests
└── d1f302 [done] Update docs
When a ticket appears in multiple subtrees it is rendered as * on its
second occurrence to keep the output finite. Edges in JSON output use
{"from": <blocker>, "to": <blocked>} — the blocking ticket is from.
Print a CLAUDE.md snippet
Print a ready-to-paste section for adopting nbd in any project's CLAUDE.md:
nbd claude-md # raw markdown, suitable for redirect
nbd claude-md >> CLAUDE.md # append to your project's CLAUDE.md
nbd claude-md --json # machine-readable {"snippet": "..."}
The snippet is embedded in the binary at compile time, so it is always in sync
with the installed version of nbd.
Migrate ticket files
Re-serialise all ticket files through the current schema. Use this after
upgrading nbd to remove stale fields, add new fields with defaults, and
normalise formatting.
nbd migrate
nbd migrate --dry-run # preview changes without writing
nbd migrate --json # machine-readable summary
Installation
Nix (recommended)
Run directly without installing, using the bundled Nix flake:
nix run github:elijah/vibed?dir=nbd -- --help
Or add to a Nix devShell:
{
inputs.nbd.url = "github:elijah/vibed?dir=nbd";
# then use nbd.packages.${system}.nbd in your devShell packages
}
Build locally from the nbd/ directory:
nix build # builds the nbd binary
nix run -- init # run nbd init via nix run
Cargo
cargo install --path .
Running
# From the nbd/ directory
cargo run -- --version # prints e.g. nbd 0.1.0+7e311d6
cargo run -- init
cargo run -- create --title "Test ticket" --priority 7 --type bug
cargo run -- list
cargo run -- list --all
cargo run -- ready
cargo run -- read <id>
cargo run -- update <id> --status in_progress
cargo run -- archive <id>
cargo run -- list --json
cargo run -- graph
cargo run -- graph <id>
cargo run -- graph --json
cargo run -- claude-md
cargo run -- claude-md --json
Testing
cargo test
Unit tests live in src/tests.rs. Integration tests (full command flows against
a temporary directory) live in tests/integration.rs.
Development
Run these commands in order before committing:
cargo fmt
cargo check
cargo clippy
cargo test
License
Dual-licensed under Apache License, Version 2.0 and
MIT License, consistent with the rest of the vibed mono-repo.
This software was written with Claude Code using the claude-sonnet-4-6 model.