## ADDED Requirements ### Requirement: Add note command The client SHALL provide a `kb addnote ` 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`.