CLI
khiipd is the primary way to drive Khiip. Most commands talk to a running daemon, so
start khiipd serve first. khiipd <command> --help is always authoritative.
The daemon address
The client commands (capture / recall / refetch) resolve which daemon to talk to in
this order (first match wins):
- explicit
--host/--portflags KHIIP_DAEMON_URL(a full base URL, e.g.http://127.0.0.1:8500; passing either flag suppresses it entirely)[daemon] host/portinconfig.toml127.0.0.1:8478
khiipd serve binds from the same chain minus the env var — KHIIP_DAEMON_URL is a
client dial address, never a bind address. See
Configuration for the
dual-use key and the allow_non_loopback gate.
khiipd serve
Run the FastAPI daemon.
| Flag | Default | Purpose |
|---|---|---|
--host | [daemon] host in config.toml, else 127.0.0.1 | bind address |
--port | [daemon] port in config.toml, else 8478 | port |
--log-level | info | debug / info / warning / error |
--reload | off | auto-reload on code changes (dev only) |
A non-loopback host from config.toml additionally requires
[daemon] allow_non_loopback = true — without it, serve binds 127.0.0.1 and warns.
An explicit --host flag needs no key. See
Configuration → binding beyond localhost.
khiipd capture <url>
Capture a URL via the running daemon.
| Flag | Default | Purpose |
|---|---|---|
--source-hint | — | force a source: x / web / wiki / pdf / youtube |
--host / --port | resolved | daemon address |
--timeout | 120 | request timeout (seconds; slow sources like YouTube need headroom) |
khiipd recall "<query>"
Semantic recall over the embedded corpus. Quote multi-word queries.
| Flag | Default | Purpose |
|---|---|---|
--limit | 10 | max results |
--min-score | no filter | drop hits below a cosine floor in [-1, 1] — see score interpretation |
--view | lean | hit shape: lean (flat id/score/title/url/excerpt rows) or full (nested {capture, score} records — the pre-0.2.4 output). Note: the CLI defaults to lean, but the daemon REST default is full (so the shipped Obsidian plugin keeps working) |
--host / --port | resolved | daemon address |
--timeout | 30 | request timeout (seconds) |
The lean view prints one flat row per hit — score, title, the capture id,
the url, and a short excerpt (head of the primary text). full restores the
pre-0.2.4 two-line score/url layout. A pre-0.2.4 daemon that doesn’t
understand view=lean returns full nested hits regardless; the CLI renders those
correctly.
khiipd refetch <capture_id> [dimension flag]
Re-run one dimension of a capture. The four dimension flags are mutually exclusive;
with none of them, refetch re-fetches from the network and creates a new superseding
capture (append-only). See the refetch guide for what each
dimension does.
| Flag | Behaviour |
|---|---|
| (none) | network re-fetch → a new superseding capture |
--re-extract | offline: re-derive the typed payload from preserved source bytes, in place (no network) |
--re-render | offline: re-render the Markdown body from the existing typed payload, in place |
--media | re-walk the media-fetcher registry in place |
--wayback | re-submit to the Wayback Machine in place |
--force | overwrite the vault note even if you hand-edited it since Khiip last wrote it (the edit guard otherwise refuses in-place rewrites with a 409); with --media it also re-attempts already-successful downloads. Only valid with an in-place dimension (--re-extract / --re-render / --media / --wayback) — --force with no dimension flag (network re-fetch) is rejected by the daemon with a 400 and the CLI exits 4 |
--timeout | request timeout (seconds; default 120 — re-extraction can be as slow as the original capture) |
--media --force re-downloads only photo-class (httpx-fetched) media in
full; video / gallery downloads (yt-dlp, gallery-dl) are NOT re-downloaded when
the file already exists on disk, even under --force — those fetchers are
pinned skip-if-exists because their writers aren’t atomic. --force still lets
the media walk re-attempt items that previously failed or were skipped.
When a forced photo re-download returns changed bytes, the old binary is not
destroyed — it is kept alongside the new one under a versioned name
(<stem>.khiip-v<UTCstamp><ext>) and the fresh bytes land back at the original
filename. Identical bytes are a no-op (the file is left untouched, zero churn).
khiipd validate
Check vault ↔ SQLite invariants — see the validate guide
for what’s checked. Read-only unless you pass --fix --apply (below). Exits 0 when clean, 1 on violations.
| Flag | Default | Purpose |
|---|---|---|
--vault-path | from config.toml | vault root override |
--db-path | from config.toml | SQLite path override |
--json | off | emit a machine-readable report instead of text |
--fix | off | preview the re-link plan for vault_path_stale rows (notes you renamed/moved in your vault). Writes nothing without --apply |
--apply | off | with --fix: apply the plan. Daemon-first (per-capture relink API); direct-SQLite fallback when the daemon is down. --apply without --fix is an argparse error |
--fix only re-links vault_path_stale rows that have exactly one matching
note by capture id in the vault. Rows with 0 matches (the note is gone —
vault_missing) or ≥2 matches (duplicate ids — vault_id_duplicate) are
counted as skipped and left untouched. After --fix --apply, validate re-runs
and the exit code reflects the post-fix state (0 clean / 1 residual
violations).
khiipd auth show | rotate
Manage the daemon API key (stored in ~/.config/khiip/auth.toml, mode 600):
khiipd auth show— print the key fingerprintkhiipd auth rotate— generate a new key
khiipd version
Print the package version and the active tier.
Exit codes
Scriptable across all commands:
| Code | Meaning |
|---|---|
0 | success (including a recall with zero results, and a clean validate) |
1 | validate found invariant violations |
2 | cannot reach the daemon (connection refused / connect timeout); malformed config.toml; validate given a missing vault/db path. (Mistyped flags also exit 2 — argparse’s convention.) Exception: validate --fix --apply does not exit 2 when the daemon is unreachable — it falls back to direct-SQLite and exits 0/1 on the post-fix result. |
3 | API key mismatch (daemon returned 401) — try khiipd auth show |
4 | any other daemon error (e.g. 404 capture not found, 409 conflict) — the detail is printed |
5 | refetch given more than one dimension flag |
6 | the request timed out after connecting — the daemon may still be finishing server-side; raise --timeout for slow sources |
7 | any other transport error |
The relink calls made by validate --fix --apply use the same exit codes: 3
(daemon 401), 4 (unexpected relink error — a non-200/404/409 status), 6
(timed out after connecting), 7 (other transport error). Per-link 404/409
during relink are skipped and reported, not fatal — the post-fix re-validate
surfaces any residue.
Daemon-unreachable errors (exit 2) print the address they tried (noting when it came
from KHIIP_DAEMON_URL) and link the Autostart page — so a rebooted
machine stops costing you captures.