Skip to content

Taskbook 2.0: subcommands, bare ids, 1 = high priority, typed errors - #4

Draft
alycda wants to merge 4 commits into
masterfrom
feat/v2-cli
Draft

alycda wants to merge 4 commits into
masterfrom
feat/v2-cli

Conversation

@alycda

@alycda alycda commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Removes quirks inherited from the Node.js taskbook. This is a breaking change and should ship as 2.0.0: after merge, run scripts/release.sh 2.0.0, which bumps the Cargo and overlay versions. This PR does not bump them. User-facing details are in docs/upgrading-to-2.0.md.

What changes

Subcommands. Actions are clap subcommands now: tb check 1 instead of tb --check 1, and tb board instead of tb --cli. The 1.x flags still parse. cli::rewrite_legacy_args rewrites them to the matching subcommand and prints a deprecation warning, and they are slated for removal in 3.0. The shim translates only the flag, so the arguments must already follow the 2.0 rules below. When a legacy invocation mentions a priority, it also warns that the scale is inverted.

One id grammar. Ids are always bare numbers, and @ always means a board. Previously @ meant an id for edit, move, priority, due, tag and edit-note, and a board everywhere else. @3 in an id position is rejected with a hint (use 3). move, priority, due and tag accept several ids. The grammar lives in taskbook_common::id, and the item-input parser board::parse_item_input is shared by the CLI and the TUI.

Priority 1 is the highest. The scale is 1 = high, 2 = medium, 3 = normal (the default). It is represented by a Priority enum, so the CLI, TUI, sort and MCP no longer carry raw u8 values with magic numbers. Storage:

  • 2.x writes the new _priority field and keeps writing the legacy priority field (the 1.x and Node.js scale). Existing data needs no migration, and older clients sharing a directory or sync server keep working.
  • When both fields are present, 2.x reads the legacy one, because the Node.js taskbook edits its JSON in place and can leave _priority stale. _priority alone is read once 3.0 stops writing the legacy field.

Errors. Taskbook no longer prints anything. Every mutation validates all of its ids (existence, and whether the item is a task) before changing anything. Errors are returned as a typed TaskbookError, which main prints once:

  • Operation failures exit with status 1.
  • Malformed command lines exit with status 2.
  • 1.x printed a specific message, then Invalid item ID: 0.

Input that 1.x silently ignored is now an error:

  • non-numeric ids;
  • p:4;
  • p: or due: on a note;
  • unknown list filters or boards;
  • stray tag tokens;
  • task-only commands on notes;
  • wrongly typed MCP arguments ("tags": "x" used to clear all tags).

TUI. Errors from slash commands, shortcuts, view switches and sync refreshes go to the status bar. Previously /delete 99 ended the TUI. Only terminal failures still exit.

New: look up by id.

  • tb show <ID>... [--archived] prints every field of the given items, including note bodies.
  • In the TUI, /show <ID>... narrows the view to those items, and Esc clears it.

MCP.

  • priority uses the new scale.
  • edit_item validates every field and then applies them all in one write, so a failing field no longer leaves a partial update.

Docs. docs/cli-reference.md is rewritten for the subcommands. It also fixes two stale claims: clear archives tasks rather than deleting them, and move has no board picker. The PR adds docs/upgrading-to-2.0.md and updates the README, CLAUDE.md and the other docs.

Known and not changed

  • Ids still change on delete and restore (archive ids are a separate namespace). This is inherited behavior.
  • auth::logout ignores the server's logout error. This is pre-existing and outside this PR.
  • p: is now a reserved token prefix, so a description word like p:foo is an error.

Verification

  • cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace pass: 153 tests, 78 in the client and 72 in common. New tests cover the id grammar, the priority serde round-trip and legacy reads, atomic validation, the shim rewrites, clap parsing, the TUI parser, and MCP type strictness.
  • A 1.x storage.json with priority: 3 reads as p1 and is saved back with both fields.
  • An independent review pass found ten real issues: +2 parsed as an id, the stale-_priority read, the silent priority inversion through the shim, MCP type coercion, and others. All of them are fixed in dffe0f9.

Generated by Claude Code

…rrors

Breaking changes to the CLI, TUI command line and MCP tools; see
docs/upgrading-to-2.0.md (next commit).

- CLI: actions are clap subcommands (`tb check 1`). The 1.x flags are
  rewritten to the matching subcommand by cli::rewrite_legacy_args and
  print a deprecation warning (removal planned for 3.0).
- Ids are always bare numbers; `@` always names a board. `@3` in an id
  position is rejected with a hint. move/priority/due/tag accept several
  ids. Shared grammar lives in taskbook_common::id and
  board::parse_item_input (used by both CLI and TUI).
- Priority: new Priority enum, 1 = high, 2 = medium, 3 = normal
  (default). Stored in `_priority`; the legacy `priority` field (1.x and
  Node.js scale) is still written for old readers and read only when
  `_priority` is absent, so existing data needs no migration.
- Errors: Taskbook no longer prints. Every mutation validates all ids
  (existence, task-ness) before changing anything and returns a typed
  TaskbookError; main prints it once and exits 1. Previously-ignored
  input is now an error: non-numeric ids, invalid p: tokens, p:/due: on
  notes, unknown list filters/boards, stray tag tokens, task-only ops on
  notes.
- TUI: slash-command and shortcut errors go to the status bar instead
  of exiting the TUI.
- MCP: priority uses the new scale; edit_item validates all fields and
  applies them in one write; non-integer ids are rejected.
- delete/restore write the archive once per call instead of per item.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014rB6uhLWQEZyDE3XSNsyTZ
Rewrites docs/cli-reference.md for subcommands (also fixing two stale
claims: clear archives rather than deleting, and move has no board
picker), adds docs/upgrading-to-2.0.md, and updates README, CLAUDE.md
and the remaining docs to the new syntax.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014rB6uhLWQEZyDE3XSNsyTZ
`tb show <ID>... [--archived]` prints every field of the given items,
including note bodies. In the TUI, `/show <ID>...` narrows the current
view to those ids (Esc clears; switching views clears it since archive
ids differ).

The three copies of the TUI visibility filter (board/timeline, journal
ordering, journal widget) now all go through App::should_show_item; the
journal widget's copy only searched descriptions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014rB6uhLWQEZyDE3XSNsyTZ
- ids: require all-digit tokens. u64::from_str accepts "+2", so
  `tb tag 1 +2 +work` tagged item 2 instead of adding tag "2".
- priority: when both fields are present, read the legacy `priority`.
  The Node.js taskbook edits JSON in place, so it can change `priority`
  and leave a stale `_priority`; 2.x always writes them consistently, so
  a disagreement means an older writer changed it. Out-of-range
  `_priority` now reads as normal instead of high.
- legacy shim: warn that priority levels are inverted when a legacy
  invocation mentions a priority; drop `--cli` anywhere (1.x accepted
  any order); `tb --cli check 1` now names `tb check`. Restore `-V`.
- MCP: reject wrongly typed arguments instead of reading them as empty
  (`"tags": "x"` on edit_item cleared all tags).
- list: dedupe named boards (non-adjacent duplicates were shown twice);
  find prints no stats and list prints stats of all items, as in 1.x.
- TUI: route every non-terminal error (view switches, sync refreshes)
  to the status bar; terminal errors still end the TUI. /search and
  board filtering clear an active /show filter.
- toggles report map keys rather than stored `_id`s; rename_board
  dedupes when an item already has the target board.
- docs: the legacy flags translate only the flag, not `@id` or the
  priority scale; document the priority read rule.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014rB6uhLWQEZyDE3XSNsyTZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants