# 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: ```sh nbd init ``` Analogous to `git init` — safe to run multiple times. ### Create a ticket ```sh 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 ```sh nbd read a3f9c2 nbd read a3f9c2 --json ``` ### List all tickets By default, `done`, `closed`, `archived`, and `backlog` tickets are excluded. ```sh 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. ```sh nbd archive a3f9c2 nbd archive a3f9c2 --json ``` `nbd archive` is shorthand for `nbd update --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 --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). ```sh 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: ```sh 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: ```sh 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: ```sh nbd graph # full dependency forest nbd graph # subtree rooted at the given ticket nbd graph --json # machine-readable adjacency list nbd graph --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": , "to": }` — 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: ```sh 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. ```sh 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: ```sh nix run github:elijah/vibed?dir=nbd -- --help ``` Or add to a Nix devShell: ```nix { inputs.nbd.url = "github:elijah/vibed?dir=nbd"; # then use nbd.packages.${system}.nbd in your devShell packages } ``` Build locally from the `nbd/` directory: ```sh nix build # builds the nbd binary nix run -- init # run nbd init via nix run ``` ### Cargo ```sh cargo install --path . ``` ## Running ```sh # 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 cargo run -- update --status in_progress cargo run -- archive cargo run -- list --json cargo run -- graph cargo run -- graph cargo run -- graph --json cargo run -- claude-md cargo run -- claude-md --json ``` ## Testing ```sh 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: ```sh cargo fmt cargo check cargo clippy cargo test ``` ## License Dual-licensed under [Apache License, Version 2.0](../LICENSE-APACHE) and [MIT License](../LICENSE-MIT), consistent with the rest of the `vibed` mono-repo. --- *This software was written with [Claude Code](https://claude.com/claude-code) using the claude-sonnet-4-6 model.*