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>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-03-31
|
||||
@@ -0,0 +1,52 @@
|
||||
## Context
|
||||
|
||||
README.md currently serves as a single documentation file for both users and developers. It contains ~290 lines mixing installation/usage instructions with build-from-source steps, release scripts, Docker image internals, and developer notes (e.g., ROCm migration plans). There is no DEVELOPER.md or CONTRIBUTING.md file.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Separate user-facing documentation (README.md) from developer-facing documentation (DEVELOPER.md)
|
||||
- README.md should answer: "What is this? How do I install it? How do I use it?"
|
||||
- DEVELOPER.md should answer: "How do I build from source? How do I release? How do I contribute?"
|
||||
- Provide a clear cross-reference link between the two files
|
||||
|
||||
**Non-Goals:**
|
||||
- Rewriting or improving documentation content itself (just moving it)
|
||||
- Creating additional docs files (CONTRIBUTING.md, architecture docs, etc.)
|
||||
- Changing any code, build scripts, or CI configuration
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Single DEVELOPER.md file (not multiple docs files)
|
||||
|
||||
All developer content goes into one top-level DEVELOPER.md rather than a `docs/` directory or separate CONTRIBUTING.md / BUILDING.md files. The total developer content is small enough (~80 lines) that splitting further would be unnecessary overhead. A single file at the repo root is immediately discoverable.
|
||||
|
||||
**Alternative considered**: `docs/` directory with multiple files. Rejected because the content volume doesn't justify the structure, and root-level DEVELOPER.md is a well-known convention.
|
||||
|
||||
### 2. Content split boundary
|
||||
|
||||
Content stays in README.md if it's needed by someone who just wants to **run** kb. Content moves to DEVELOPER.md if it's only needed by someone who wants to **build, modify, or release** kb.
|
||||
|
||||
Specifically moving to DEVELOPER.md:
|
||||
- "From source" subsections under both engine and client install
|
||||
- Entire "Building and releasing" section (release scripts, version checking, Docker image tags, registry overrides)
|
||||
- "Future: ROCm runtime migration" developer note
|
||||
|
||||
Staying in README.md:
|
||||
- Architecture overview (helps users understand what they're running)
|
||||
- Pre-built image / release install instructions
|
||||
- Client configuration
|
||||
- Usage examples
|
||||
- Engine configuration table
|
||||
- Data portability
|
||||
- API reference
|
||||
- Claude Code skill reference
|
||||
|
||||
### 3. Cross-reference approach
|
||||
|
||||
A short note in README.md's Quick Start section pointing to DEVELOPER.md for building from source. No back-link needed from DEVELOPER.md since developers will naturally find README.md first.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Stale cross-references]** If DEVELOPER.md sections are renamed, the link from README.md could break. Mitigation: link to the file, not to a specific anchor.
|
||||
- **[Discoverability]** Some users who want to build from source might miss DEVELOPER.md. Mitigation: explicit "See DEVELOPER.md" callout in the Quick Start section where "from source" instructions used to be.
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
README.md currently mixes user-facing content (what kb does, how to install and use it) with developer-facing content (building from source, releasing, Docker image internals, architecture deep-dives). Users looking for quick-start instructions have to scroll past release scripts and build commands. Developers looking for contribution/build info have to hunt through user docs. Splitting these into README.md (users) and DEVELOPER.md (developers/contributors) follows standard open-source convention and makes both audiences' experience cleaner.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **Trim README.md** to focus on user-facing content: what kb is, how to install (from pre-built images/releases), how to configure, how to use, engine configuration reference, data portability, and API reference.
|
||||
- **Remove "from source" build instructions** from README.md (both engine and client sections).
|
||||
- **Remove "Building and releasing" section** from README.md entirely.
|
||||
- **Remove "Future: ROCm runtime migration"** developer note from README.md.
|
||||
- **Create DEVELOPER.md** containing: building engine from source, building client from source, release process (client and engine), Docker image details, version checking, ROCm migration notes, and any other contributor-oriented content.
|
||||
- **Add a link** from README.md to DEVELOPER.md for developers who want to build from source or contribute.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `developer-docs`: Developer-facing documentation covering building from source, releasing, and contributing.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(none - no spec-level behavior changes, this is a documentation restructuring)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Files modified**: `README.md` (trimmed)
|
||||
- **Files created**: `DEVELOPER.md` (new)
|
||||
- **No code changes**: purely documentation restructuring
|
||||
- **No API changes**: no functional impact
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: DEVELOPER.md exists at repo root
|
||||
The repository SHALL have a `DEVELOPER.md` file at the project root containing all developer-facing documentation.
|
||||
|
||||
#### Scenario: File exists
|
||||
- **WHEN** a developer navigates to the repository root
|
||||
- **THEN** a `DEVELOPER.md` file SHALL be present
|
||||
|
||||
### Requirement: DEVELOPER.md contains build-from-source instructions
|
||||
DEVELOPER.md SHALL contain instructions for building both the engine and client from source.
|
||||
|
||||
#### Scenario: Engine build from source
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include instructions for starting the engine from source using compose files (both NVIDIA and ROCm)
|
||||
|
||||
#### Scenario: Client build from source
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include instructions for building the client binary from source using `make build` and `make all`
|
||||
|
||||
### Requirement: DEVELOPER.md contains release process
|
||||
DEVELOPER.md SHALL document the release process for both client and engine, including release scripts, version bumping, and Docker image tagging.
|
||||
|
||||
#### Scenario: Client release documentation
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include `release-client.sh` usage with flag options (--gitea, --github, --minor, --no-increment, --dry-run)
|
||||
|
||||
#### Scenario: Engine release documentation
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include `release-engine.sh` usage with flag options and Docker image tag conventions
|
||||
|
||||
#### Scenario: Version checking
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include how to check client and engine versions
|
||||
|
||||
### Requirement: DEVELOPER.md contains developer notes
|
||||
DEVELOPER.md SHALL include any forward-looking developer notes such as migration plans or technical debt items.
|
||||
|
||||
#### Scenario: ROCm migration note
|
||||
- **WHEN** a developer reads DEVELOPER.md
|
||||
- **THEN** it SHALL include the ROCm runtime migration note about onnxruntime and MIGraphX
|
||||
|
||||
### Requirement: README.md excludes developer-only content
|
||||
README.md SHALL NOT contain build-from-source instructions, release processes, or developer-only notes.
|
||||
|
||||
#### Scenario: No from-source build steps in README
|
||||
- **WHEN** a user reads README.md
|
||||
- **THEN** there SHALL be no "From source" subsections under engine or client installation
|
||||
|
||||
#### Scenario: No release section in README
|
||||
- **WHEN** a user reads README.md
|
||||
- **THEN** there SHALL be no "Building and releasing" section
|
||||
|
||||
#### Scenario: No developer notes in README
|
||||
- **WHEN** a user reads README.md
|
||||
- **THEN** there SHALL be no "Future: ROCm runtime migration" section
|
||||
|
||||
### Requirement: README.md cross-references DEVELOPER.md
|
||||
README.md SHALL include a link to DEVELOPER.md for users who want to build from source or contribute.
|
||||
|
||||
#### Scenario: Developer link in quick start
|
||||
- **WHEN** a user reads the Quick Start section of README.md
|
||||
- **THEN** there SHALL be a note pointing to DEVELOPER.md for building from source
|
||||
@@ -0,0 +1,17 @@
|
||||
## 1. Create DEVELOPER.md
|
||||
|
||||
- [x] 1.1 Create DEVELOPER.md at repo root with engine build-from-source instructions (compose.nvidia.yaml and compose.rocm.yaml)
|
||||
- [x] 1.2 Add client build-from-source instructions (make build, make all)
|
||||
- [x] 1.3 Add "Building and releasing" section: release-client.sh and release-engine.sh usage with all flag options
|
||||
- [x] 1.4 Add version checking instructions (kb --version, curl status endpoint)
|
||||
- [x] 1.5 Add Docker image tag conventions and registry override documentation
|
||||
- [x] 1.6 Add "Future: ROCm runtime migration" developer note
|
||||
|
||||
## 2. Trim README.md
|
||||
|
||||
- [x] 2.1 Remove "From source (for development)" subsection under engine quick start
|
||||
- [x] 2.2 Remove "From source (for development)" subsection under client installation
|
||||
- [x] 2.3 Remove entire "Building and releasing" section
|
||||
- [x] 2.4 Remove "Future: ROCm runtime migration" section
|
||||
- [x] 2.5 Add cross-reference note to DEVELOPER.md in the Quick Start section for building from source
|
||||
- [x] 2.6 Move API reference section from README.md to DEVELOPER.md
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-03-31
|
||||
@@ -0,0 +1,51 @@
|
||||
## 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.
|
||||
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
The implicit note shorthand (`kb "some text"`) makes it too easy to accidentally add notes when mistyping commands. Despite the single-word guard, any multi-word typo (e.g. `kb lisst --type pdf`) silently creates a note. The root command doing double-duty as both command dispatcher and note ingester undermines user trust. Reverting to explicit, structured add commands eliminates accidental ingestion and gives every content type a clear, discoverable verb.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **New `addnote` command**: `kb addnote <text>` takes a single quoted positional argument and submits it as a note. Supports `--tags`. The `submitNote()` logic moves from `root.go` to a new `addnote.go` command file.
|
||||
- **Remove implicit note shorthand**: The root command reverts to standard Cobra behaviour — no `ArbitraryArgs`, no special arg-count logic, no `--tags` flag on root. Unknown input gets Cobra's default "unknown command" error.
|
||||
- **Remove custom usage template**: The root command no longer needs the `isRootCmd` template logic. Standard Cobra usage template for all commands.
|
||||
- **Update examples**: `examples.go` updated to show `kb addnote` instead of bare `kb "text"`.
|
||||
- **Update tests**: Remove implicit note shorthand tests, add `addnote` command tests.
|
||||
- **`addfile` unchanged**: Stays exactly as-is.
|
||||
- **BREAKING**: `kb "note text"` no longer works. Users must use `kb addnote "note text"`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
_(none)_
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `go-client`: The "Implicit note shorthand" requirement is removed entirely and replaced by a new "Add note command" requirement. The "Add command (file and note ingestion)" requirement description is updated to reflect `addnote` / `addfile` as the two ingestion commands. The root command reverts to standard Cobra behaviour with no custom arg handling or usage template.
|
||||
|
||||
## Impact
|
||||
|
||||
- `client/cmd/root.go` — remove `ArbitraryArgs`, `RunE` note logic, `--tags` flag, custom usage template, `isRootCmd` template func
|
||||
- `client/cmd/add.go` — `submitNote()` function moves to new `addnote.go` (or stays in `add.go` alongside `addfile` — design decision)
|
||||
- `client/cmd/addnote.go` — new file defining the `addnote` command
|
||||
- `client/cmd/examples.go` — update example text
|
||||
- `client/cmd/root_test.go` — remove implicit note shorthand tests, add standard Cobra behaviour tests
|
||||
- No engine changes — the API contract (`POST /api/v1/jobs` with `note` field) is unchanged
|
||||
@@ -0,0 +1,87 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Add note command
|
||||
|
||||
The client SHALL provide a `kb addnote <text>` command that submits a text note to the engine for ingestion. The command SHALL take exactly one positional argument (the note text) and support a `--tags` flag for comma-separated tags. The note SHALL be submitted via `POST /api/v1/jobs` with the `note` field in a multipart request.
|
||||
|
||||
#### Scenario: Add a note
|
||||
- **WHEN** the user runs `kb addnote "remember to update DNS records"`
|
||||
- **THEN** the client SHALL submit the text as a note via `POST /api/v1/jobs` and print `Queued: note`
|
||||
|
||||
#### Scenario: Add a note with tags
|
||||
- **WHEN** the user runs `kb addnote "server room is building 3" --tags ops`
|
||||
- **THEN** the client SHALL submit the note with the specified tags
|
||||
|
||||
#### Scenario: Add a note with JSON output
|
||||
- **WHEN** the user runs `kb addnote "my note" --format json`
|
||||
- **THEN** the client SHALL output the raw JSON response from the engine
|
||||
|
||||
#### Scenario: Duplicate note detection
|
||||
- **WHEN** the user runs `kb addnote "my note"` and the engine returns HTTP 409
|
||||
- **THEN** the client SHALL display the duplicate information (document ID or job ID) and exit with code 0
|
||||
|
||||
#### Scenario: Missing argument
|
||||
- **WHEN** the user runs `kb addnote` with no arguments
|
||||
- **THEN** the client SHALL display an error indicating that the note text argument is required
|
||||
|
||||
#### Scenario: Too many arguments
|
||||
- **WHEN** the user runs `kb addnote remember to update dns` (unquoted, multiple args)
|
||||
- **THEN** the client SHALL display an error indicating that exactly one argument is required, with a hint to quote the text
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Add command (file and note ingestion)
|
||||
|
||||
The client SHALL provide a `kb addfile` command that uploads files to the engine for async ingestion. The command SHALL validate file extensions before uploading and reject unsupported types. The client SHALL handle duplicate rejection (HTTP 409) and display the existing document information. Notes are handled by the separate `addnote` command — `addfile` is exclusively for file uploads.
|
||||
|
||||
#### Scenario: Add a single file
|
||||
- **WHEN** the user runs `kb addfile report.pdf`
|
||||
- **THEN** the client SHALL validate the file extension, upload the file via `POST /api/v1/jobs` (multipart), print "Queued: report.pdf", and exit
|
||||
|
||||
#### Scenario: Add a file with tags
|
||||
- **WHEN** the user runs `kb addfile manual.pdf --tags car,maintenance`
|
||||
- **THEN** the client SHALL include the tags in the multipart upload metadata
|
||||
|
||||
#### Scenario: Add a directory recursively
|
||||
- **WHEN** the user runs `kb addfile ~/documents/ --recursive`
|
||||
- **THEN** the client SHALL discover all supported files in the directory tree, upload each one sequentially, and print "Queued: N files"
|
||||
|
||||
#### Scenario: Unsupported file extension
|
||||
- **WHEN** the user runs `kb addfile photo.jpg`
|
||||
- **THEN** the client SHALL print an error listing supported extensions and exit with a non-zero code without making any API call
|
||||
|
||||
#### Scenario: Duplicate file rejected (already ingested)
|
||||
- **WHEN** the user runs `kb addfile report.pdf` and the engine returns HTTP 409 with `{"error": "duplicate", "document_id": 42, "title": "report.pdf"}`
|
||||
- **THEN** the client SHALL print "Already imported: report.pdf (doc ID: 42)" and exit with code 0
|
||||
|
||||
#### Scenario: Duplicate file rejected (in-flight job)
|
||||
- **WHEN** the user runs `kb addfile report.pdf` and the engine returns HTTP 409 with `{"error": "duplicate", "job_id": 7, "title": "report.pdf"}`
|
||||
- **THEN** the client SHALL print "Already queued: report.pdf (job ID: 7)" and exit with code 0
|
||||
|
||||
#### Scenario: Duplicate file in recursive add
|
||||
- **WHEN** the user runs `kb addfile ~/documents/ --recursive` and some files are rejected as duplicates
|
||||
- **THEN** the client SHALL print the duplicate message for each rejected file, continue uploading remaining files, and include a summary (e.g., "Queued: 5 files, 2 duplicates skipped")
|
||||
|
||||
#### Scenario: Duplicate with JSON output
|
||||
- **WHEN** the user runs `kb addfile report.pdf --format json` and the engine returns HTTP 409
|
||||
- **THEN** the client SHALL output the raw JSON response from the engine including the document_id and title
|
||||
|
||||
#### Scenario: Add with JSON output
|
||||
- **WHEN** the user runs `kb addfile report.pdf --format json`
|
||||
- **THEN** the client SHALL output the JSON response from the engine including the job_id
|
||||
|
||||
#### Scenario: File not found
|
||||
- **WHEN** the user runs `kb addfile nonexistent.pdf`
|
||||
- **THEN** the client SHALL print an error and exit with a non-zero code without making any API call
|
||||
|
||||
#### Scenario: Upload failure
|
||||
- **WHEN** the upload fails (network error, engine returns 4xx/5xx other than 409)
|
||||
- **THEN** the client SHALL print the error and exit with a non-zero code
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Implicit note shorthand
|
||||
|
||||
**Reason**: The implicit shorthand caused accidental note creation from mistyped commands. Any unrecognized multi-word input was silently ingested as a note. Replaced by the explicit `addnote` command.
|
||||
|
||||
**Migration**: Replace `kb "note text"` with `kb addnote "note text"`. Replace `kb "note text" --tags foo` with `kb addnote "note text" --tags foo`.
|
||||
@@ -0,0 +1,29 @@
|
||||
## 1. Create addnote command
|
||||
|
||||
- [x] 1.1 Create `client/cmd/addnote.go` with `addnoteCmd` using `ExactArgs(1)`, `--tags` flag, and `RunE` calling `submitNote()`
|
||||
- [x] 1.2 Move `submitNote()` function from `client/cmd/add.go` to `client/cmd/addnote.go`
|
||||
|
||||
## 2. Revert root command to standard Cobra behaviour
|
||||
|
||||
- [x] 2.1 Remove `ArbitraryArgs`, custom `RunE` logic, and `--tags` flag from root command in `client/cmd/root.go`
|
||||
- [x] 2.2 Remove custom usage template and `isRootCmd` template function — let Cobra use its default template
|
||||
- [x] 2.3 Set root command to show help when called with no args (standard Cobra `RunE` returning `cmd.Help()` or nil)
|
||||
|
||||
## 3. Update examples and help text
|
||||
|
||||
- [x] 3.1 Update `client/cmd/examples.go` to show `kb addnote` syntax instead of `kb "text"` shorthand
|
||||
- [x] 3.2 Update root command `Long` description to remove reference to note shorthand
|
||||
|
||||
## 4. Update tests
|
||||
|
||||
- [x] 4.1 Remove implicit note shorthand tests from `client/cmd/root_test.go` (`TestRootCmd_SingleWordRejected`, `TestRootCmd_MultipleWordsNotRejected`)
|
||||
- [x] 4.2 Add test for `addnote` command (verify it wires up correctly, takes exactly one arg)
|
||||
- [x] 4.3 Add test that root command with unknown args returns an error (standard Cobra behaviour)
|
||||
- [x] 4.4 Verify `addfile` tests still pass (no changes expected)
|
||||
|
||||
## 5. Build and verify
|
||||
|
||||
- [x] 5.1 Run `go build` and verify all commands appear in `kb --help`
|
||||
- [x] 5.2 Run `go test ./...` and verify all tests pass
|
||||
- [x] 5.3 Verify `kb addnote --help` shows correct usage line and flags
|
||||
- [x] 5.4 Verify `kb addfile --help` is unchanged
|
||||
Reference in New Issue
Block a user