Every wkp subcommand and its flags. For a narrative walkthrough of the
read/write paths and when to call what, see AGENTS.md
(written for an agent, but equally useful to a human). This doc is the
flat reference: one entry per subcommand, what it does, exact syntax.
wkp --help prints the short form of this list from the CLI itself;
wkp --version/-V prints the version. Every subcommand also accepts
its own --help/-h (wkp search --help, wkp hub register --help,
wkp bundle export --help, ...), printing that subcommand's usage text
and exiting 0 rather than being parsed as a positional argument.
Flags shown in [brackets] are optional. --path <dir> defaults to the
current directory everywhere it appears, unless noted otherwise.
Makes path (default: cwd) a git repository with a .wkp/ directory,
wires SSH commit signing, registers the merge driver and clean/smudge
filter, and runs wkp import once. Idempotent — safe to re-run.
One-shot, idempotent migration of pre-existing memory into
inbox/import/: CLAUDE.md/AGENTS.md at the store root, and every
~/.claude/projects/*/memory/*.md file. Runs automatically as part of
wkp init; call it again by hand if new source files show up later. An
existing destination file is never overwritten.
BM25 full-text search over index.db. --budget stops once estimated
token cost exceeds N. --format paths is the form to feed into a
Read-tool call.
<query> is a plain-language lookup, not an FTS5 query expression: every
character in it (., -, :, quotes, bareword AND/OR/NOT, ...)
is matched as literal text, so wkp search "RHOAI 3.6 release dates" or
wkp search "file-name.ext" works exactly as typed rather than raising
an FTS5 syntax error or being parsed as a boolean/column-filter
expression. An empty or whitespace-only query returns no results rather
than erroring.
Each term also matches as a prefix, not just an exact token: wkp search "ubi" finds UBI8/UBI9-minimal even though the tokenizer stores those
as single tokens distinct from ubi — an exact-only match would
silently return nothing for a query most users mean as "starts with." A
document containing the full word still ranks ahead of one matched only
by prefix (BM25's own term-frequency weighting).
Also accepts --embed-url URL [--embed-model NAME] [--embed-key-file PATH]
for opt-in hybrid search (Reciprocal Rank Fusion between BM25 and
embedding cosine similarity against an OpenAI-compatible endpoint) —
requires a binary built with the embed Cargo feature and embeddings
already computed via wkp index --embed-url .... Never called by
default — the only network call anywhere in the read path (search/
context/traverse/materialize/index). sync, bundle, and
hub register are network operations too, by design (that's their
whole job); this flag is specifically about the read/search path never
reaching out unless you opt in.
Same non-embedding flags as search (--embed-url/--embed-model/
--embed-key-file are search-only — context rejects them explicitly,
not just silently ignores them). Adds a graph traversal of the
refs:/wikilink edges from each hit, so you also get directly-linked
neighbors, not just
the hits themselves.
Walks refs:/[[wikilink]] edges outward from one specific file, no
search query involved. --depth defaults to 2.
Writes .wkp/tier{N}.md atomically (temp file + rename). --tier is
required — no default, deliberately, so a session-start hook never
materializes "whatever tier" by accident. This is what a SessionStart
hook reads for tier 0.
--routing-table (--tier 0 only — rejected on any other tier) splices
a <wkp-routing-table> block into tier 0's own output: every tier-1
item's title and path, no body content. Tier 1 specifically, never tier
2 — using tier 2 would put unreviewed/inbox/ content into a channel
that's supposed to carry only human-signed items, the same guarantee
tier 0's own content already relies on. If tier 1 is empty, the block
says so honestly instead of being silently omitted.
Rescans the store and updates index.db incrementally, using git's own
change detection to hash only what changed. Only .md files are
indexed. Safe to run any time; cheap after a single-file edit.
Reads .wkp/metrics.db back: per-tool invocation count, error count,
and avg/min/max latency for every subcommand run against this store (a
gauge, like an indexed-item count, instead reports sample count, last
value, and min/max). --window defaults to 1d; --tool filters to
one metric by name.
Recorded automatically for every subcommand invocation against an already-initialized store — on by default, nothing to opt into, and nothing ever leaves the machine (a fixed-size local SQLite ring buffer, never synced, never transmitted even when a hub is configured). A metric with no activity in the requested window is omitted rather than shown as a misleading row of zeros.
wkp remember --type <type> --principal <principal> --signing-key-file <path> [--scope <scope>] [--title <title>] [--session <session>] [--path <dir>]
Writes one SSH-signed item to inbox/, body read from stdin (never
argv). --type, --principal, and --signing-key-file are required.
Always lands at confidence: proposed, tier 2, regardless of --type —
nothing self-promotes to tier 0/1.
wkp remember --type knowledge --principal agent:claude --signing-key-file ~/.ssh/id_ed25519 <<'EOF'
Whatever you learned, as plain markdown.
EOFwkp promote <inbox-path> [--to <dest-path>] --principal <principal> --signing-key-file <path> [--path <dir>]
Moves one inbox/ item into the durable tree with a human-signed commit.
The one opt-in exception to "human-signed": a principal explicitly listed
under [promote] auto = [...] in .wkp/config.toml.
or
Two operations under one verb: the first form removes one tracked item;
the second revokes a device's encryption-recipient entry and
re-encrypts every currently-tracked visibility: private file. Both
always require role: human — no auto-forget escape hatch, unlike
promote.
Erases a path from git history entirely, wrapping the upstream
git-filter-repo tool (not vendored — install it separately:
apt install git-filter-repo / brew install git-filter-repo /
pip install git-filter-repo).
Fetches and pushes this device's branch, converging with peer devices through the merge driver.
Reports unresolved conflicts without changing anything.
Writes a git bundle for air-gapped sync — everything, or everything
since --since.
Applies a bundle produced by bundle export on another device.
Resolves modify/delete conflicts (design 6.2: a deletion always loses to
a modification) by keeping the modification and proposing the deletion
as an inbox/ item instead of silently dropping either side.
Registers this device with a wkp-hub (RFC 8628 device flow), issuing
an mTLS device certificate. --ca-cert is the hub's own CA root
(wkp-hub ca-cert).
wkp wkpd --principal <p> --signing-key-file <path> [--path <dir>] [--remote <name>] [--socket-path <path>] [--debounce-ms <n>]
Watch-triggered sync daemon: debounced auto-commit of local changes,
incremental re-index, opportunistic sync. Binds a Unix domain socket
only (never TCP), peer-UID verified on every connection — Linux only;
refuses to start elsewhere rather than running with no peer check. See
deploy/systemd/wkpd.service for a
ready-to-edit systemd --user unit.
Prints text for a harness to apply — never writes a file itself.
claude_code— JSON covering three hooks at once:SessionStart(unchanged — materializes and injects tier 0),UserPromptSubmit(runswkp prompt-hook, below), andPostToolUse(matcher: "Write|Edit", re-runswkp indexafter every edit). See the README for the merge command.codex,opencode,hermes,agents_md— all four print the identical plain-textAGENTS.mdinstruction (wkp index && wkp materialize --tier 0 && cat .wkp/tier0.md, plus a second line namingwkp context "<topic>"as the manual fallback for these harnesses' lack of aUserPromptSubmit-equivalent hook). Codex and OpenCode are confirmedAGENTS.mdauto-readers. Hermes Agent is too, verified against its own source (agent/prompt_builder.py,NousResearch/hermes-agent) — but with one real caveat: Hermes loads at most one project-context file, first match wins, in this order —.hermes.md/HERMES.md(walking up to the git root) →AGENTS.mdchain →CLAUDE.md→.cursorrules. SoAGENTS.mdreaches Hermes exactly like it reaches Codex/OpenCode unless the project also has its own.hermes.md/HERMES.md, which wins instead.agents_mdis the generic name for any other AGENTS.md-reading harness.
Claude Code UserPromptSubmit plumbing, registered by wkp hooks --framework claude_code above — not meant to be typed by hand. Reads
the hook's JSON payload from stdin, runs a best-effort, any-term BM25
search (wkp-core's search_any_term, not plain search's
implicit-AND — a whole prompt needs partial-overlap matching, not a
literal match on every word) against its prompt field, and prints up
to 5 candidate paths when the top hits clear WKP_PROMPT_HOOK_MIN_SCORE
(default 0.0 — any real match; BM25 scores are corpus-dependent and
unbounded by orders of magnitude, so a fixed positive cutoff reliably
swallows real hits in a small store — tune this up once a real
golden-query set makes a better number knowable). Also reads
CLAUDE_PROJECT_DIR (set by Claude Code for every hook invocation) in
preference to its own working directory, so it finds the project-root
index even when the triggering tool call touched a subdirectory.
Always exits 0 and
writes nothing — a missing index, a malformed payload, or nothing
clearing the threshold all mean "print nothing," never a visible
failure.
Re-execs <command> inside a container instead of natively. See
docs/sandboxed-mode.md for what this is for, what
it needs, and how it's safe from the self-invocation risk a native
macOS sandbox would have had.
wkp merge-driver <ancestor> <ours> <theirs> and wkp filter clean|smudge
are invoked by git itself, per its own merge-driver and clean/smudge
filter protocols (wkp init registers both). Not commands a human or
harness runs directly.