kadence
Decisions

ADR-006 — The limits of cac, and loading the TUI lazily

Two limits found in practice, and why the interactive board must never be in the fast path.

Date: 2026-09-03 · Status: accepted; amends ADR-004 · Scope: stack

Context

ADR-004 chose cac for its 3.3 ms import and predicted one risk: abandonment. Practice produced two different ones, and both cost time.

  1. cac does not match multi-word commands. cli.command('task add <title>') shows up in help, but the action never fires. Only found by running the binary by hand: the tests called command functions directly and saw nothing wrong.
  2. cac treats any value with a leading - as a flag. --estimate -5 and task log KAD-1 -30m never reach our code; they fail with Unknown option.

Separately: a TUI on blessed costs ~28 ms to import, and Ink costs 146 ms out of a 200 ms budget.

Options considered

OptionForAgainst
Move to cittySupports nested commands+5 ms; rewriting the whole CLI layer for two workarounds
Own parserFull control--help, subcommands and error messages are permanent debt
Keep cac, work around both limitsZero migration; the workarounds are local and documentedTwo places in the code you have to remember

Decision

Keep cac, with two explicit workarounds:

  • Commands are declared as task <action> and the action is dispatched by a switch. This also produced better messages: on a missing argument cac says "missing required args", which tells a user nothing.
  • Arguments with a leading - are intercepted before cli.parse(). For --estimate that is an error with an explanation; for task log it is a legitimate negative value.

The TUI is loaded dynamically and stays out of the main bundle. The 200 ms guardrail is about commands run dozens of times a day; an interactive session starts once and lives for minutes.

Consequences

  • Zero migration, and dist/cli.js stayed 30 KB with no trace of blessed in it — CI greps for that on every push.
  • Two non-obvious places in src/cli/index.ts, both with a comment. A new contributor will not guess them.
  • What would make us revisit it: a third cac limit stops being a workaround and becomes a mismatched tool, and then citty is justified.

On this page