--- # nbd-d9dh title: Add 'nbd graph' CLI subcommand status: completed type: feature priority: normal created_at: 2026-03-10T23:30:31Z updated_at: 2026-03-10T23:30:32Z blocked_by: - nbd-csdh - nbd-17dp --- Wire up the `graph` subcommand in `src/main.rs` to expose the ASCII dependency graph and JSON output. ## Motivation With `src/graph.rs` and the rendering functions in `display.rs` implemented, this ticket connects them to the CLI so users (and agents) can invoke `nbd graph`. ## CLI interface ```sh nbd graph # full dependency forest (all tickets) nbd graph # subtree rooted at the given ticket ID (or unique prefix) nbd graph --json # machine-readable adjacency list (all tickets) nbd graph --json # machine-readable subtree nbd graph --filter type=bug # forest of only bug tickets and their deps ``` ## Clap definition (add to `Commands` enum in main.rs) ```rust /// Draw an ASCII dependency graph of all tickets, or a subtree rooted at a /// specific ticket. /// /// Without an ID, renders every ticket as a dependency forest (roots first, /// dependencies indented below). With an ID, renders only the subtree reachable /// from that ticket via its dependencies. Graph { /// Optional ticket ID or unique prefix to use as the graph root. /// /// When omitted, the full dependency forest is rendered. id: Option, /// Filter tickets by field before building the graph: repeatable `key=value` pairs. /// /// Applied to the full ticket list before graph construction. /// Keys: `status`, `type`, `priority`, `title`. Values support globs. #[arg(long = "filter", value_name = "KEY=VALUE")] filter: Vec, } ``` ## Handler: `cmd_graph` ```rust async fn cmd_graph(id: Option, filter_args: Vec, json: bool) -> store::Result<()> ``` Steps: 1. `find_nbd_root()` and `list_tickets(&root).await?`. 2. Apply `parse_filters(&filter_args)?` to narrow the ticket list. 3. `let graph = TicketGraph::build(&tickets);` 4. If `id` is `Some`: a. Resolve `id` via `resolve_id(&root, &id).await?`. b. If `json`: print `graph.to_subtree_json_value(&id)` (or similar — see graph.rs ticket for the JSON shape). c. Else: `display::print_subtree(&graph, &id)`. 5. If `id` is `None`: a. If `json`: print `graph.to_json_value()`. b. Else: `display::print_graph(&graph)`. ## JSON output shapes **Full graph (`nbd graph --json`):** ```json { "nodes": [ {"id": "a3f9c2", "title": "Fix login bug", "status": "todo", "priority": 8, "dependencies": ["b7d41e"]}, ... ], "edges": [ {"from": "a3f9c2", "to": "b7d41e"}, ... ] } ``` **Subtree (`nbd graph --json`):** Same shape as full graph but only including nodes and edges reachable from ``. ## Files touched - `src/main.rs` — `Commands::Graph` variant, `cmd_graph`, dispatch in `dispatch()` ## Depends on - `9c9ebe` — graph computation module - `e14172` — ASCII rendering functions