You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Elijah Voigt 3c0665314a tickets(nbd): triage TODO.md → 818598 scope next/ready by subtree
- 818598: Scope nbd next and nbd ready by dependency subtree

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 months ago
..
.claude Update triage skill 3 months ago
.nbd tickets(nbd): triage TODO.md → 818598 scope next/ready by subtree 3 months ago
docs docs(nbd): add README, PLANNING, ARCHITECTURE, and complete Phase 6 3 months ago
src fix(nbd): fix graph orientation to show goals at root, prerequisites as leaves 3 months ago
tests fix(nbd): fix graph orientation to show goals at root, prerequisites as leaves 3 months ago
CLAUDE.md docs: improve CLAUDE.md structure and clarity 3 months ago
Cargo.lock feat(nbd): add Turso/libsql cache for list performance [833807] 3 months ago
Cargo.toml feat(nbd): add Turso/libsql cache for list performance [833807] 3 months ago
PLAN.md docs(nbd): add README, PLANNING, ARCHITECTURE, and complete Phase 6 3 months ago
README.md fix(nbd): change graph repeat-node marker from [cycle] to * [8b4041] 3 months ago
TODO.md tickets(nbd): triage TODO.md → 818598 scope next/ready by subtree 3 months ago
build.rs feat(nbd): add --version flag with X.Y.Z+GitSha format [c24ee8] 3 months ago
flake.lock claude skill tweaks, bugs triaged, projects updated 3 months ago
flake.nix feat(nbd): add Nix flake for building and running nbd [6e4239] 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 010 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

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.