Reindex command, implicit note shorthand, add→addfile rename
- Add `kb reindex` command with confirmation prompt and --yes flag - Add implicit note shorthand: `kb "my note"` submits a note directly - Rename `add` to `addfile`, remove --note/--title/--type flags - Add client-side file extension validation before upload - Add `kb examples` command for common usage patterns - Update README, SKILL.md, and main specs - Archive completed changes and sync delta specs BREAKING: `kb add` renamed to `kb addfile`, `kb add --note` replaced by `kb "text"` Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,7 +67,7 @@ The engine SHALL store all persistent state (SQLite database, HF model cache, st
|
||||
|
||||
### Requirement: Compose files for deployment
|
||||
|
||||
The project SHALL provide Docker Compose files for single-command deployment.
|
||||
The project SHALL provide Docker Compose files for single-command deployment. Compose files SHALL use `build:` context for local development. Release notes SHALL document the versioned image tag for users pulling pre-built images.
|
||||
|
||||
#### Scenario: Start NVIDIA deployment
|
||||
- **WHEN** an admin runs `docker compose -f compose.nvidia.yaml up -d`
|
||||
@@ -85,6 +85,10 @@ The project SHALL provide Docker Compose files for single-command deployment.
|
||||
- **WHEN** an admin sets environment variables in the compose file (KB_MODEL, KB_API_KEY, KB_DEVICE, etc.)
|
||||
- **THEN** the engine SHALL use those values
|
||||
|
||||
#### Scenario: Pre-built image deployment
|
||||
- **WHEN** an admin wants to use a pre-built engine image without building from source
|
||||
- **THEN** the engine release notes SHALL include the exact `docker pull` command with the versioned tag (e.g. `docker.dcglab.co.uk/dcg/kb/engine:engine-v2.1.0-nvidia`)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: CPU-only fallback
|
||||
|
||||
@@ -194,11 +194,11 @@ The engine SHALL provide endpoints to list all tags and manage tags on documents
|
||||
|
||||
### Requirement: Engine status and reindex
|
||||
|
||||
The engine SHALL provide status information and support re-embedding all chunks.
|
||||
The engine SHALL provide status information and support re-embedding all chunks. The `version` field in the status response SHALL always be present and SHALL reflect the engine's release version as read from the `VERSION` file. This field is the contract used by clients for compatibility checking.
|
||||
|
||||
#### Scenario: Get engine status
|
||||
- **WHEN** a client sends `GET /api/v1/status`
|
||||
- **THEN** the engine SHALL return JSON with model_name, embedding_dim, GPU device info, database stats (document count by type, total chunks, DB size), and queue stats (queued/processing job count)
|
||||
- **THEN** the engine SHALL return JSON with `version` (string, from VERSION file), model_name, embedding_dim, GPU device info, database stats (document count by type, total chunks, DB size), and queue stats (queued/processing job count)
|
||||
|
||||
#### Scenario: Trigger reindex
|
||||
- **WHEN** a client sends `POST /api/v1/reindex`
|
||||
|
||||
@@ -8,12 +8,16 @@ The Go client (`kb`) provides a command-line interface for interacting with the
|
||||
|
||||
### Requirement: Single static binary with zero runtime dependencies
|
||||
|
||||
The Go client SHALL compile to a single static binary with no runtime dependencies. It SHALL support cross-compilation for Linux (amd64, arm64), macOS (amd64, arm64), and Windows (amd64).
|
||||
The Go client SHALL compile to a single static binary with no runtime dependencies. It SHALL support cross-compilation for Linux (amd64, arm64), macOS (amd64, arm64), and Windows (amd64). The build SHALL inject both `Version` and `MinEngineVersion` via ldflags.
|
||||
|
||||
#### Scenario: Install on a clean machine
|
||||
- **WHEN** a user downloads the `kb` binary for their platform
|
||||
- **THEN** they SHALL be able to run it immediately with no additional installs (no Python, no Docker, no shared libraries)
|
||||
|
||||
#### Scenario: Version and compatibility info embedded at build time
|
||||
- **WHEN** the client is built with `make all VERSION=2.1.0 MIN_ENGINE_VERSION=2.0.0`
|
||||
- **THEN** `kb --version` SHALL report `2.1.0` and the compatibility check SHALL use `2.0.0` as the minimum engine version
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Client configuration
|
||||
@@ -64,48 +68,82 @@ The client SHALL provide a `kb search <query>` command that sends the query to t
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Implicit note shorthand
|
||||
|
||||
The client SHALL treat bare string arguments (with no subcommand) as an implicit note. `kb "my note"` SHALL behave identically to submitting a note via `POST /api/v1/jobs`. All persistent flags (`--format`, `--engine`, `--api-key`) and the root `--tags` flag SHALL work with the shorthand form.
|
||||
|
||||
#### Scenario: Quick note via bare argument
|
||||
- **WHEN** the user runs `kb "remember to update DNS"`
|
||||
- **THEN** the client SHALL submit the text as a note via `POST /api/v1/jobs` and print `Queued: note`
|
||||
|
||||
#### Scenario: Bare argument with tags
|
||||
- **WHEN** the user runs `kb "server room is building 3" --tags ops`
|
||||
- **THEN** the client SHALL submit the note with the specified tags
|
||||
|
||||
#### Scenario: Bare argument with JSON output
|
||||
- **WHEN** the user runs `kb "my note" --format json`
|
||||
- **THEN** the client SHALL output the raw JSON response from the engine
|
||||
|
||||
#### Scenario: Bare argument duplicate detection
|
||||
- **WHEN** the user runs `kb "my note"` and the engine returns HTTP 409
|
||||
- **THEN** the client SHALL handle the duplicate response identically to the previous `kb add --note` behaviour
|
||||
|
||||
#### Scenario: Multiple unquoted words
|
||||
- **WHEN** the user runs `kb remember to update dns` (without quotes)
|
||||
- **THEN** the client SHALL join all arguments into a single note string and submit it
|
||||
|
||||
#### Scenario: No interference with subcommands
|
||||
- **WHEN** the user runs `kb search "query"` or any other existing subcommand
|
||||
- **THEN** the client SHALL route to the subcommand as before — the implicit note shorthand SHALL NOT interfere
|
||||
|
||||
#### Scenario: No arguments
|
||||
- **WHEN** the user runs `kb` with no arguments
|
||||
- **THEN** the client SHALL display the help text
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Add command (file and note ingestion)
|
||||
|
||||
The client SHALL provide a `kb add` command that uploads files or notes to the engine for async ingestion. The client SHALL exit immediately after a successful upload. The client SHALL handle duplicate rejection (HTTP 409) and display the existing document information.
|
||||
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. The command SHALL NOT handle notes — notes are submitted via the implicit note shorthand (`kb "text"`).
|
||||
|
||||
#### Scenario: Add a single file
|
||||
- **WHEN** the user runs `kb add report.pdf`
|
||||
- **THEN** the client SHALL upload the file via `POST /api/v1/jobs` (multipart), print "Queued: report.pdf", and exit
|
||||
- **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 add manual.pdf --tags car,maintenance`
|
||||
- **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 add ~/documents/ --recursive`
|
||||
- **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: Add a text note
|
||||
- **WHEN** the user runs `kb add --note "The server room is in building 3, floor 2"`
|
||||
- **THEN** the client SHALL submit the note text via `POST /api/v1/jobs` (multipart with note field), print "Queued: note", and exit
|
||||
#### 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 add report.pdf` and the engine returns HTTP 409 with `{"error": "duplicate", "document_id": 42, "title": "report.pdf"}`
|
||||
- **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 add report.pdf` and the engine returns HTTP 409 with `{"error": "duplicate", "job_id": 7, "title": "report.pdf"}`
|
||||
- **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 add ~/documents/ --recursive` and some files are rejected as duplicates
|
||||
- **THEN** the client SHALL print the duplicate message for each rejected file (distinguishing "Already imported" from "Already queued"), continue uploading remaining files, and include a summary (e.g., "Queued: 5 files, 2 duplicates skipped")
|
||||
- **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 add report.pdf --format json` and the engine returns HTTP 409
|
||||
- **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 add report.pdf --format json`
|
||||
- **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 add nonexistent.pdf`
|
||||
- **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
|
||||
@@ -186,6 +224,62 @@ The client SHALL provide a `kb status` command to display engine status.
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Reindex command
|
||||
|
||||
The client SHALL provide a `kb reindex` command that triggers re-embedding of all chunks on the engine. The command SHALL prompt for confirmation before proceeding.
|
||||
|
||||
#### Scenario: Reindex with confirmation
|
||||
- **WHEN** the user runs `kb reindex`
|
||||
- **THEN** the client SHALL display a warning that all chunks will be re-embedded and prompt `Reindex all chunks? This will re-embed everything. [y/N]`. If confirmed, it SHALL POST to `/api/v1/reindex` and display the result.
|
||||
|
||||
#### Scenario: Reindex with skip confirmation
|
||||
- **WHEN** the user runs `kb reindex --yes`
|
||||
- **THEN** the client SHALL skip the confirmation prompt and POST to `/api/v1/reindex` immediately
|
||||
|
||||
#### Scenario: Reindex cancelled
|
||||
- **WHEN** the user runs `kb reindex` and responds with anything other than `y` or `yes`
|
||||
- **THEN** the client SHALL print `Cancelled.` and exit with code 0
|
||||
|
||||
#### Scenario: Reindex human output
|
||||
- **WHEN** the reindex completes successfully with default format
|
||||
- **THEN** the client SHALL print `Reindexed N chunks (model: <model_name>)`
|
||||
|
||||
#### Scenario: Reindex JSON output
|
||||
- **WHEN** the user runs `kb reindex --yes --format json`
|
||||
- **THEN** the client SHALL output the raw JSON response from the engine
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Engine version compatibility check
|
||||
|
||||
The client SHALL verify that the connected engine meets a minimum version requirement before executing any API command. The minimum required engine version SHALL be embedded in the client binary at build time. If the engine version is below the minimum, the client SHALL print an error message and exit with a non-zero code. There SHALL be no flag to skip or suppress this check.
|
||||
|
||||
#### Scenario: Compatible engine version
|
||||
- **WHEN** the client connects to an engine reporting version `2.1.5` and `MinEngineVersion` is `2.1.0`
|
||||
- **THEN** the client SHALL proceed with the command normally
|
||||
|
||||
#### Scenario: Incompatible engine version
|
||||
- **WHEN** the client connects to an engine reporting version `2.0.3` and `MinEngineVersion` is `2.1.0`
|
||||
- **THEN** the client SHALL print to stderr: `Error: kb client vX.Y.Z requires engine v2.1.0+ (connected engine is v2.0.3)` followed by an upgrade hint, and exit with code 1
|
||||
|
||||
#### Scenario: Engine unreachable during version check
|
||||
- **WHEN** the client cannot reach the engine's `/api/v1/status` endpoint
|
||||
- **THEN** the client SHALL skip the version check and proceed with the original command (the actual API call will surface the connectivity error)
|
||||
|
||||
#### Scenario: Version check is cached per session
|
||||
- **WHEN** the client has already verified engine compatibility during the current invocation
|
||||
- **THEN** subsequent API calls within the same invocation SHALL NOT repeat the version check
|
||||
|
||||
#### Scenario: Client version command does not check engine
|
||||
- **WHEN** the user runs `kb --version`
|
||||
- **THEN** the client SHALL print the client version without contacting the engine
|
||||
|
||||
#### Scenario: MinEngineVersion not set
|
||||
- **WHEN** the client binary has `MinEngineVersion` set to empty string or `dev`
|
||||
- **THEN** the client SHALL skip the version check entirely (development builds)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Global output format flag
|
||||
|
||||
All commands SHALL support a `--format` flag accepting `human` (default) or `json`. The default MAY be changed via the `default_format` config value.
|
||||
|
||||
Reference in New Issue
Block a user