Files
kb/openspec/changes/archive/2026-03-31-structured-add-commands/design.md
T
steve afbe270181 Replace implicit note shorthand with explicit addnote command and split README
Two changes:

1. structured-add-commands: The implicit note shorthand (kb "text") caused
   accidental note creation from mistyped commands. Replaced with explicit
   kb addnote <text> command. Root command reverts to standard Cobra
   behaviour. Updated examples, tests, SKILL.md, and specs.

2. split-readme-developer-docs: Moved build-from-source instructions, release
   process, API reference, and ROCm migration notes from README.md into a
   new DEVELOPER.md. README now links to DEVELOPER.md for dev workflows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 20:48:22 +01:00

3.0 KiB

Context

The kb client currently overloads the root Cobra command to handle both command dispatch and implicit note ingestion. Any unrecognized multi-word input is silently submitted as a note via POST /api/v1/jobs. This was introduced to reduce friction for note-taking but has proven error-prone — typos in commands create unwanted notes. A single-word guard was added but multi-word typos still slip through.

The root command has: custom ArbitraryArgs validation, a RunE with arg-count branching, a --tags flag for the note shorthand, a custom usage template with isRootCmd template function, and submitNote() living in add.go.

Goals / Non-Goals

Goals:

  • Eliminate accidental note creation from mistyped commands
  • Provide a clean, explicit addnote command that pairs with existing addfile
  • Revert root command to standard Cobra behaviour (no custom args, no custom template)
  • Keep the same API contract — POST /api/v1/jobs with note field unchanged

Non-Goals:

  • Changing the engine API
  • Modifying addfile behaviour
  • Adding new content types (url, bookmark, etc.)
  • Backward compatibility shim for kb "text" syntax

Decisions

1. New addnote command in its own file

Create client/cmd/addnote.go with a cobra.Command that takes ExactArgs(1) — a single quoted string. This mirrors addfile which also takes ExactArgs(1).

Rationale: Keeps each command in its own file (consistent with the existing pattern). ExactArgs(1) means the user must quote multi-word notes, which is unambiguous and avoids the flag-parsing edge cases that plagued the implicit shorthand.

Alternative considered: Joining ArbitraryArgs like the old shorthand. Rejected — this is exactly the ambiguity we're removing.

2. Move submitNote() from add.go to addnote.go

The function is only used by the addnote command, so it belongs in the same file.

Rationale: add.go becomes purely about file operations (it already is, aside from hosting submitNote()). Clean separation.

3. Fully revert root command to Cobra defaults

Remove: ArbitraryArgs, custom RunE (replace with nil — Cobra shows help by default), --tags flag on root, custom usage template, isRootCmd template function.

Rationale: The root command should do one thing — dispatch to subcommands. All the custom logic was there to support the implicit shorthand which is being removed.

4. addnote gets its own --tags flag

The --tags flag moves from the root command to addnote, matching how addfile already has its own --tags flag.

Risks / Trade-offs

  • Breaking change for existing users → Mitigated by clear error messaging. If someone types kb "some text", Cobra will say "unknown command". The examples command will show the new syntax.
  • Slightly more typing for notes (kb addnote "text" vs kb "text") → Acceptable trade-off for eliminating accidental ingestion. Tab-completion helps.
  • Scripts using old syntax will break → This is intentional. The old syntax was a foot-gun.