--- # nbd-mkkm title: Add --xml output format that wraps each ticket section in XML tags status: todo type: feature priority: low created_at: 2026-03-10T23:30:30Z updated_at: 2026-03-10T23:30:30Z --- ## Background From `nbd/TODO.md`: > Add a `--xml` output format that prints tickets with XML around each section to make it easier to parse metadata. Unlike `--json` (which is a complete, structured parse), the XML format adds lightweight tags around each metadata field in the human-readable output. This makes it trivial for scripts to extract specific fields using simple text tools (e.g., `grep`, `sed`, XPath) without pulling in a full JSON parser. ## Intended XML format For a single ticket (`nbd read --xml`): ```xml a3f9c2 Fix login bug 8 in_progress bug b7d41e c9e823 Users cannot log in with email addresses containing + ``` For a list (`nbd list --xml`): ```xml ... ... ``` ## Implementation ### `src/main.rs` Add a global `--xml` flag to the `Cli` struct, parallel to `--json`: ```rust /// Output XML instead of a human-readable table. #[arg(long, global = true)] xml: bool, ``` Precedence: if both `--json` and `--xml` are supplied, `--json` wins (or return an error — TBD, but JSON-first is simpler). Pass `cli.xml` through `dispatch` to every command handler, alongside `cli.json`. Each command handler signature gains an `xml: bool` parameter. When `xml` is true and `json` is false, call the new `display::print_ticket_xml` / `display::print_list_xml` functions. ### `src/display.rs` Add: - `format_ticket_xml(ticket: &Ticket) -> String` — serialises a single ticket as XML - `print_ticket_xml(ticket: &Ticket)` — wraps `format_ticket_xml` + `println!` - `format_list_xml(tickets: &[Ticket]) -> String` — wraps list in `` - `print_list_xml(tickets: &[Ticket])` XML escaping: at minimum, escape `&`, `<`, `>`, `"`, `'` in field values. Use a small helper `xml_escape(s: &str) -> String` rather than pulling in an XML crate. For `dependencies`: render each as a `` child element. ### `src/tests.rs` Add unit tests: - `format_ticket_xml` with a ticket that has special characters in the title and body (`&`, `<`, `>`) - `format_ticket_xml` with empty dependencies - `format_ticket_xml` with multiple dependencies - `format_list_xml` with zero and multiple tickets ### `tests/integration.rs` Add integration tests: - `nbd read --xml` returns valid XML containing the ticket's fields - `nbd list --xml` returns valid XML wrapping multiple tickets - `nbd create ... --xml` returns the created ticket as XML - `nbd update ... --xml` returns the updated ticket as XML ## Scope All commands that support `--json` should also support `--xml`: - `nbd create` - `nbd read` - `nbd list` - `nbd update` - `nbd ready` - `nbd next` - `nbd archive` - `nbd migrate` - `nbd graph` (the JSON graph format has a defined structure; XML should mirror it) - `nbd claude-md` (wrap snippet in `` tag) - `nbd init` (wrap root path in ``)