chore(nbd): triage TODO into 9 tickets
- d9713b: open/start/complete/close convenience sub-commands - 53fdbe: list <status> positional arg shortcuts - 1c686c: next <type> positional arg shortcuts - 4aceeb: nbd init adds cache.db to .nbd/.gitignore - 1c5783: VERSION file + nbd version subcommand + /work skill bump - 3ba7f9: .nbd/config.toml per-project defaults - e222cd: triage status (new default, excluded from ready/next/list) - 67209c: [backlog] investigate project-based ticket filtering - 0f577a: [backlog] investigate user-configurable type/status strings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>quotesdb
parent
5ddf9a56e1
commit
3ce8b16581
@ -0,0 +1,48 @@
|
||||
+++
|
||||
title = "Investigate: user-configurable type and status strings with lifecycle phases"
|
||||
priority = 3
|
||||
status = "backlog"
|
||||
ticket_type = "task"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
`type` and `status` are currently hard-coded Rust enums. Users cannot add custom values (e.g., `status = "review"` or `type = "spike"`) without modifying the codebase. But certain status values (`done`, `archived`, `closed`) have special semantics (excluded from `list`/`ready`/`next`; counted as resolved for deps). Making these extensible requires a design that lets users declare which values are "pre-work", "in-work", and "post-work".
|
||||
|
||||
## Design questions
|
||||
|
||||
### Lifecycle phases (proposed)
|
||||
|
||||
Instead of hard-coding which statuses are excluded, introduce a three-phase model:
|
||||
|
||||
| Phase | Examples | Behaviour |
|
||||
|---|---|---|
|
||||
| `pre` | `triage`, `backlog` | Excluded from `list`, `ready`, `next`. Not resolved. |
|
||||
| `during` | `todo`, `in_progress`, `review` | Included in `list`, `ready`, `next`. Not resolved. |
|
||||
| `post` | `done`, `archived`, `closed` | Excluded from `list`, `ready`, `next`. Counted as resolved. |
|
||||
|
||||
Users would configure phases in `.nbd/config.toml`:
|
||||
|
||||
```toml
|
||||
[nbd.status]
|
||||
pre = ["triage", "backlog"]
|
||||
during = ["todo", "in_progress", "review", "qa"]
|
||||
post = ["done", "archived", "closed"]
|
||||
default = "triage"
|
||||
```
|
||||
|
||||
### Type extensibility
|
||||
|
||||
Allow `type` to be any string. Keep built-in types (`project`, `feature`, `task`, `bug`) but do not reject unknown values; validate only that the string is non-empty.
|
||||
|
||||
## Questions to answer
|
||||
|
||||
1. Is TOML config the right place for lifecycle phase definitions, or should there be a separate schema file?
|
||||
2. How does serialisation/deserialisation change? `Status` can no longer be an enum if it is user-defined.
|
||||
3. What is the migration path for existing tickets serialised with the current enum values?
|
||||
4. Are there cases where a single status should belong to multiple phases (e.g., `review` might be both `during` and gating some post-processing)?
|
||||
5. What is the minimum viable change? Could we start by making status a `String` internally while keeping the built-in values and their semantics, then layer config-driven phases on top?
|
||||
|
||||
## Expected output
|
||||
|
||||
Create one or more follow-up tickets with a concrete implementation plan and migration strategy.
|
||||
@ -0,0 +1,76 @@
|
||||
+++
|
||||
title = 'VERSION file: compile into binary via include_str\! and add nbd version subcommand'
|
||||
priority = 5
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
The current version string is assembled in `main.rs` from `CARGO_PKG_VERSION` (Cargo.toml) and `GIT_SHORT_SHA` (build.rs). There is no `nbd version` subcommand — only `--version`. And the `/work` skill does not bump any version on completion.
|
||||
|
||||
## Changes required
|
||||
|
||||
### 1. Create `VERSION` file
|
||||
|
||||
Create a `VERSION` file at the crate root (`nbd/VERSION`) containing the initial version:
|
||||
|
||||
```
|
||||
0.1.0
|
||||
```
|
||||
|
||||
### 2. Use `VERSION` in the binary
|
||||
|
||||
In `src/main.rs`, replace `CARGO_PKG_VERSION` with an `include_str\!` of the `VERSION` file (trimmed):
|
||||
|
||||
```rust
|
||||
const VERSION: &str = concat\!(
|
||||
env\!("CARGO_PKG_VERSION"), // keep for crate metadata
|
||||
"+",
|
||||
env\!("GIT_SHORT_SHA"),
|
||||
);
|
||||
```
|
||||
|
||||
Actually, use `include_str\!("../VERSION")` trimmed and concatenated with the git SHA:
|
||||
|
||||
```rust
|
||||
const VERSION_FILE: &str = include_str\!("../VERSION");
|
||||
const VERSION: &str = /* VERSION_FILE.trim() + "+" + GIT_SHORT_SHA at runtime or via concat */ ;
|
||||
```
|
||||
|
||||
Note: `include_str\!` and `concat\!` cannot trim at compile time. Use a `build.rs` approach: read `VERSION` in `build.rs`, trim it, and emit it via `cargo:rustc-env=NBD_VERSION=...`. Then:
|
||||
|
||||
```rust
|
||||
const VERSION: &str = concat\!(env\!("NBD_VERSION"), "+", env\!("GIT_SHORT_SHA"));
|
||||
```
|
||||
|
||||
Update `build.rs` to read `VERSION` and emit `NBD_VERSION`.
|
||||
|
||||
### 3. Add `nbd version` subcommand
|
||||
|
||||
Add a `Version` variant to the `Commands` enum:
|
||||
|
||||
```rust
|
||||
/// Print the nbd version string and exit.
|
||||
Version,
|
||||
```
|
||||
|
||||
Handler prints the same string as `--version`. With `--json`, output `{"version": "X.Y.Z+sha"}`.
|
||||
|
||||
### 4. Update `/work` skill
|
||||
|
||||
Edit `.claude/skills/work/SKILL.md` to add a version-bump step after marking a ticket complete:
|
||||
|
||||
- Breaking changes (major rework, API change) → bump major: `X.0.0`
|
||||
- Features (`ticket_type == feature`) → bump minor: `X.Y.0`
|
||||
- Tasks and bugs (`ticket_type == task | bug`) → bump patch: `X.Y.Z`
|
||||
|
||||
The skill should read `VERSION`, parse the semver, increment the appropriate component, and write it back. Also update `Cargo.toml` `version` to match (keep in sync).
|
||||
|
||||
## Relevant files
|
||||
|
||||
- `nbd/VERSION` (new)
|
||||
- `nbd/build.rs` (update: emit `NBD_VERSION`)
|
||||
- `nbd/src/main.rs` (update: use `NBD_VERSION`, add `Version` subcommand)
|
||||
- `nbd/Cargo.toml` (keep version in sync with `VERSION` file)
|
||||
- `.claude/skills/work/SKILL.md` (update: add version-bump step)
|
||||
@ -0,0 +1,44 @@
|
||||
+++
|
||||
title = "Add next <type> filtered sub-commands (next bug, next feature, next task)"
|
||||
priority = 4
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
`nbd next --filter type=bug` is verbose. When an engineer wants the highest-priority ready bug, they should be able to say `nbd next bug`.
|
||||
|
||||
## Sub-commands to add (positional arg to `next`)
|
||||
|
||||
Accept an optional positional `<type>` argument to `nbd next`:
|
||||
|
||||
```sh
|
||||
nbd next feature # equivalent to: nbd next --filter type=feature
|
||||
nbd next task # equivalent to: nbd next --filter type=task
|
||||
nbd next bug # equivalent to: nbd next --filter type=bug
|
||||
nbd next project # equivalent to: nbd next --filter type=project
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
**`src/main.rs`** — `Commands::Next`
|
||||
|
||||
Add an optional positional argument `ticket_type` to the `Next` variant:
|
||||
|
||||
```rust
|
||||
Next {
|
||||
ticket_type: Option<String>, // new: positional shorthand
|
||||
filter: Vec<String>,
|
||||
}
|
||||
```
|
||||
|
||||
In `cmd_next`, when `ticket_type` is `Some(t)`:
|
||||
- Validate it is one of `project`, `feature`, `task`, `bug` (return an error otherwise)
|
||||
- Prepend `format!("type={t}")` to the effective filter list before calling `parse_filters`
|
||||
|
||||
Explicit `--filter type=...` values are ORed with the positional shorthand, consistent with `TicketFilter` behaviour.
|
||||
|
||||
**`tests/integration.rs`**
|
||||
|
||||
Add tests verifying that `next bug` returns only bug-type ready tickets and that `next` with no argument still works as before.
|
||||
@ -0,0 +1,73 @@
|
||||
+++
|
||||
title = "Add .nbd/config.toml for per-project defaults"
|
||||
priority = 5
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
All defaults (output format, file type, default status) are hard-coded in the CLI. Users in a project that always uses `--json` or always creates `md`-format tickets must pass these flags repeatedly. A per-project config file would let them set these once.
|
||||
|
||||
## Config file
|
||||
|
||||
Location: `.nbd/config.toml` (inside the `.nbd/` root, alongside `tickets/` and `cache.db`).
|
||||
|
||||
Format (all keys optional — missing keys fall back to compiled defaults):
|
||||
|
||||
```toml
|
||||
[nbd]
|
||||
json = false # default: false — use tabular output
|
||||
ftype = "json" # default: "json" — ticket storage format
|
||||
status = "todo" # default: "todo" — initial status for new tickets
|
||||
```
|
||||
|
||||
## Precedence (highest to lowest)
|
||||
|
||||
1. Explicit CLI flag (e.g., `--json`, `--ftype md`)
|
||||
2. Environment variable (not in scope for this ticket)
|
||||
3. `.nbd/config.toml`
|
||||
4. Compiled-in default
|
||||
|
||||
## Implementation
|
||||
|
||||
**`src/store.rs`** (or a new `src/config.rs`)
|
||||
|
||||
Add a `NbdConfig` struct and a `load_config(root: &Path) -> NbdConfig` function:
|
||||
|
||||
```rust
|
||||
pub struct NbdConfig {
|
||||
pub json: bool,
|
||||
pub ftype: FileFormat,
|
||||
pub status: Status,
|
||||
}
|
||||
|
||||
impl Default for NbdConfig { /* compiled-in defaults */ }
|
||||
|
||||
pub fn load_config(root: &Path) -> NbdConfig { /* read .nbd/config.toml, fall back to Default */ }
|
||||
```
|
||||
|
||||
Parse with the `toml` crate (already in `Cargo.toml`). Errors in the config file should produce a helpful message to stderr and fall back to defaults rather than aborting.
|
||||
|
||||
**`src/main.rs`** — `dispatch()`
|
||||
|
||||
After `find_nbd_root()`, call `load_config`. Merge config values with CLI flags:
|
||||
|
||||
- `cli.json = cli.json || config.json` (CLI flag wins)
|
||||
- For `--ftype`: if the user did not pass `--ftype`, use `config.ftype`
|
||||
- For `--status` in `create`: if the user did not pass `--status`, use `config.status`
|
||||
|
||||
**`src/main.rs`** — `cmd_init`
|
||||
|
||||
After creating the tickets directory, write `.nbd/config.toml` with default values if it does not already exist.
|
||||
|
||||
**`tests/integration.rs`**
|
||||
|
||||
- Test that a config with `json = true` causes tabular commands to emit JSON.
|
||||
- Test that a config with `ftype = "md"` causes `create` to write `.md` files.
|
||||
- Test that explicit CLI flags override config values.
|
||||
- Test idempotency of `nbd init` (does not overwrite existing config).
|
||||
|
||||
## Dependencies
|
||||
|
||||
None. Can be implemented independently of other tickets.
|
||||
@ -0,0 +1,33 @@
|
||||
+++
|
||||
title = "nbd init: add cache.db to .nbd/.gitignore"
|
||||
priority = 5
|
||||
status = "todo"
|
||||
ticket_type = "task"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
`.nbd/cache.db` is a Turso/libsql SQLite cache file created automatically by `list_tickets_cached`. It should never be committed to git. Currently `nbd init` does not create a `.gitignore` to exclude it.
|
||||
|
||||
## Implementation
|
||||
|
||||
**`src/main.rs`** — `cmd_init`
|
||||
|
||||
After `ensure_tickets_dir` succeeds, write (or append to) `.nbd/.gitignore`:
|
||||
|
||||
```
|
||||
cache.db
|
||||
```
|
||||
|
||||
Use idempotent logic: read the file if it exists, check whether `cache.db` is already listed, and only append/create if it is absent. This keeps `nbd init` safe to run multiple times.
|
||||
|
||||
Suggested helper (can be inline in `cmd_init`):
|
||||
1. Read `.nbd/.gitignore` if it exists.
|
||||
2. If `cache.db` is not a line in the file, append `cache.db\n`.
|
||||
3. If the file does not exist, create it with `cache.db\n`.
|
||||
|
||||
The JSON output for `--json` should include a `gitignore` key indicating the path that was created/updated (or unchanged).
|
||||
|
||||
**`tests/integration.rs`**
|
||||
|
||||
Add a test that runs `nbd init` and asserts `.nbd/.gitignore` contains `cache.db`. Run `nbd init` a second time and assert the file is unchanged (idempotent).
|
||||
@ -0,0 +1,49 @@
|
||||
+++
|
||||
title = "Add list status sub-commands (list todo, list backlog, etc.)"
|
||||
priority = 4
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
Filtering by status requires the verbose `--filter status=X`. Common patterns like listing only backlog or only completed tickets should have ergonomic shortcuts.
|
||||
|
||||
## Sub-commands to add (positional arg to `list`)
|
||||
|
||||
Accept an optional positional `<status>` argument to `nbd list`:
|
||||
|
||||
```sh
|
||||
nbd list backlog # equivalent to: nbd list --filter status=backlog
|
||||
nbd list closed # equivalent to: nbd list --filter status=closed
|
||||
nbd list completed # equivalent to: nbd list --filter status=done
|
||||
nbd list todo # equivalent to: nbd list --filter status=todo
|
||||
nbd list in_progress # equivalent to: nbd list --filter status=in_progress
|
||||
```
|
||||
|
||||
Note: `completed` is an alias for `done` (avoids the awkward `nbd list done`).
|
||||
|
||||
## Implementation
|
||||
|
||||
**`src/main.rs`** — `Commands::List`
|
||||
|
||||
Add an optional positional argument `status` to the `List` variant:
|
||||
|
||||
```rust
|
||||
List {
|
||||
status: Option<String>, // new: positional shorthand
|
||||
filter: Vec<String>,
|
||||
all: bool,
|
||||
}
|
||||
```
|
||||
|
||||
In `cmd_list`, when `status` is `Some(s)`:
|
||||
- Map `"completed"" → "done"`, others pass through
|
||||
- Treat it as if the caller had passed `--filter status=<s>`
|
||||
- The explicit `--filter` and `--all` flags should still override as today
|
||||
|
||||
If both `status` and `--filter status=...` are given, merge them (OR behaviour within the status group, consistent with `TicketFilter`).
|
||||
|
||||
**`tests/integration.rs`**
|
||||
|
||||
Add tests for each status shorthand.
|
||||
@ -0,0 +1,31 @@
|
||||
+++
|
||||
title = "Investigate: filtering tickets by project / stream of work"
|
||||
priority = 3
|
||||
status = "backlog"
|
||||
ticket_type = "task"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
When multiple streams of work coexist (e.g., refactoring vs. new feature), there is no way to select tickets for one stream only. `nbd next` and `nbd list` operate across all tickets.
|
||||
|
||||
## Questions to answer
|
||||
|
||||
1. Does the existing `project`-type ticket + `deps` mechanism serve this need? Could a project ticket act as a grouping node, and filtering by `--filter type=project` or by the project ticket's subtree (`nbd graph <project-id> --json`) provide what is needed?
|
||||
|
||||
2. Are there cases where a ticket belongs to multiple projects? If so, a single-parent `deps` tree cannot represent the relationship.
|
||||
|
||||
3. Is a dedicated `project` or `label` field (multi-valued) preferable? What are the trade-offs?
|
||||
|
||||
4. How does this interact with `nbd ready` and `nbd next`? Would a `--project <id>` flag on these commands be sufficient?
|
||||
|
||||
## Approach
|
||||
|
||||
Investigate by:
|
||||
1. Manually modelling two parallel workstreams using `project`-type tickets and `deps`.
|
||||
2. Evaluating whether `nbd graph <project-id> --json` provides enough to extract a project-scoped ticket list.
|
||||
3. Writing up findings and creating actionable implementation tickets.
|
||||
|
||||
## Expected output
|
||||
|
||||
Create one or more follow-up tickets with a concrete implementation plan, or close this ticket with a rationale if the existing tools are sufficient.
|
||||
@ -0,0 +1,48 @@
|
||||
+++
|
||||
title = "Add status convenience sub-commands (open, start, complete, close)"
|
||||
priority = 5
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
`nbd update <id> --status <x>` is verbose for the most common lifecycle transitions. `nbd archive` already exists as a top-level convenience — the same pattern should apply to all transitions.
|
||||
|
||||
## Sub-commands to add
|
||||
|
||||
| Command | Status set |
|
||||
|---|---|
|
||||
| `nbd open <id>` | `todo` |
|
||||
| `nbd start <id>` | `in_progress` |
|
||||
| `nbd complete <id>` | `done` |
|
||||
| `nbd close <id>` | `closed` |
|
||||
|
||||
(`nbd archive` already exists — do not duplicate it.)
|
||||
|
||||
## Implementation
|
||||
|
||||
**`src/main.rs`**
|
||||
|
||||
Add four variants to the `Commands` enum, following the existing `Archive` pattern (line 183):
|
||||
|
||||
```rust
|
||||
Open { id: String },
|
||||
Start { id: String },
|
||||
Complete { id: String },
|
||||
Close { id: String },
|
||||
```
|
||||
|
||||
Add handler functions `cmd_open`, `cmd_start`, `cmd_complete`, `cmd_close`. Each handler should:
|
||||
1. Call `resolve_id` (supports partial IDs)
|
||||
2. `find_ticket_path` + `detect_format` to preserve existing file format
|
||||
3. `read_ticket`
|
||||
4. Set `ticket.status` to the target status
|
||||
5. `write_ticket` in the same format
|
||||
6. Print the ticket (tabular or JSON via `--json`)
|
||||
|
||||
Wire up in `dispatch()` following the same pattern as `Commands::Archive`.
|
||||
|
||||
**`tests/integration.rs`**
|
||||
|
||||
Add integration tests for each command analogous to the existing archive test.
|
||||
@ -0,0 +1,82 @@
|
||||
+++
|
||||
title = "Add triage status: new default for tickets lacking implementation detail"
|
||||
priority = 6
|
||||
status = "todo"
|
||||
ticket_type = "feature"
|
||||
dependencies = []
|
||||
+++
|
||||
## Problem
|
||||
|
||||
New tickets are created with `status=todo`, implying they are ready to work on. But many tickets need further research or implementation details before work can begin. The TODO describes a `triage` status for exactly this case — tickets that need an LLM or human to fill in details before they become `todo`.
|
||||
|
||||
## Status semantics
|
||||
|
||||
- `triage` — the ticket exists but lacks sufficient detail to begin implementation. An LLM or human should flesh out the body and move it to `todo` when ready.
|
||||
- `triage` is excluded from `nbd ready` and `nbd next` (not actionable yet).
|
||||
- `triage` is excluded from `nbd list` by default (like `backlog`).
|
||||
- `triage` is the new **default status** for `nbd create` (replaces `todo`).
|
||||
|
||||
## Changes
|
||||
|
||||
### `src/ticket.rs`
|
||||
|
||||
Add `Triage` variant to `Status`:
|
||||
|
||||
```rust
|
||||
/// The ticket needs more detail before it can be worked on.
|
||||
///
|
||||
/// A triage ticket should have its body updated with implementation
|
||||
/// details and then moved to `todo`.
|
||||
Triage,
|
||||
```
|
||||
|
||||
Change the `#[default]` attribute from `Todo` to `Triage`.
|
||||
|
||||
### `src/main.rs`
|
||||
|
||||
- `parse_status`: add `"triage" => Ok(Status::Triage)` and update the error message.
|
||||
- `Commands::Create`: change the default value for `--status` from `"todo"` to `"triage"`.
|
||||
- **Note:** If `.nbd/config.toml` support (separate ticket) is implemented first, the default should be settable via config; fall back to `"triage"` if config is absent.
|
||||
- `cmd_ready` and `cmd_next`: add `Status::Triage` to the exclusion list.
|
||||
- `cmd_list`: add `Status::Triage` to the default exclusion list.
|
||||
|
||||
### `src/filter.rs`
|
||||
|
||||
- `status_str`: add `Status::Triage => "triage"`.
|
||||
|
||||
### `src/display.rs`
|
||||
|
||||
- `status_str`: add `Status::Triage => "triage"`.
|
||||
- Column widths: `STATUS` column is currently 13 chars (`"in_progress" + 2`). `"triage"" is 6 chars — no width change needed.
|
||||
|
||||
### `src/graph.rs`
|
||||
|
||||
- `status_str`: add `Status::Triage => "triage"`.
|
||||
|
||||
### `src/claude_md_snippet.md`
|
||||
|
||||
Update the embedded snippet to document the triage workflow:
|
||||
- `triage` tickets need implementation details added to their body before they can be worked on.
|
||||
- When creating a ticket that is ready to work on immediately, pass `--status todo` explicitly.
|
||||
- Default: `nbd create --title "..."` creates a `triage` ticket.
|
||||
|
||||
### `CLAUDE.md` (project-level)
|
||||
|
||||
Update the workflow section to reflect the new default and document when to use `--status todo` vs. leaving the default.
|
||||
|
||||
### `src/tests.rs`
|
||||
|
||||
Add unit tests:
|
||||
- `Status::Triage` serialises to `"triage"`
|
||||
- Round-trip deserialisation
|
||||
- Default `Ticket::new` has `status == Status::Triage`
|
||||
|
||||
### `tests/integration.rs`
|
||||
|
||||
- `nbd create` with no `--status` flag creates a `triage` ticket.
|
||||
- `nbd create --status todo` creates a `todo` ticket.
|
||||
- `nbd ready` does not include `triage` tickets.
|
||||
- `nbd next` does not include `triage` tickets.
|
||||
- `nbd list` does not include `triage` tickets by default.
|
||||
- `nbd list --filter status=triage` shows only triage tickets.
|
||||
- `nbd list --all` includes `triage` tickets.
|
||||
Loading…
Reference in New Issue