okfsmith logo okfsmith Docs EN Open okfsmith
On this page

CLI reference

CLI reference

CLI reference

One page, every command. New here? Start with the quickstart to learn by doing — this page is the cheat sheet you keep open afterwards.

All examples assume a bundle at ./kb created with init (paths like kb and big.md come straight from verified runs — adapt them to your own files).


Global flags

These work on every command, including with no subcommand:

FlagWhat it does
--helpShow help for the CLI or a specific command (okfsmith ingest --help).
--versionPrint the version (e.g. 0.3.0) and exit.
--format jsonWhere supported (list, read, validate, graph, sync): emit machine-readable JSON instead of rich text.
--no-llmWhere supported (ingest, sync, chat): run fully deterministic, no LLM involved.
--install-completionInstall shell completion for the current shell.
--show-completionPrint the completion script instead of installing it.

okfsmith init

Create a new, empty OKF bundle in BUNDLE.

okfsmith init [OPTIONS] {bundle}
okfsmith init ./kb

Real output — init scaffolds exactly two files, index.md and log.md, nothing else:

Initialized OKF bundle in kb
  index: /path/to/kb/index.md
  log:   /path/to/kb/log.md
Next: add sources with 'okfsmith ingest kb <file-or-dir> --no-llm'.

Common options

FlagWhat it does
--forceScaffold even if the bundle exists and is non-empty (asks for confirmation).
--yes, -yAnswer "yes" to the --force prompt — for non-interactive use.

okfsmith ingest

Ingest documents into BUNDLE as draft concepts.

okfsmith ingest [OPTIONS] {bundle} {sources}...
# Deterministic, no-LLM path — the recommended first run
okfsmith ingest ./kb big.md --no-llm

# Ingest a whole directory tree
okfsmith ingest ./kb ./docs --recursive --no-llm

Real output (the table and summary line are exactly what you see):

    Ingest summary — sectioning (no LLM)
┏━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━┓
┃ File   ┃ SHA-256      ┃ Concepts ┃ Status ┃
┡━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━┩
│ big.md │ 34a0dca378f8 │       18 │ ok     │
└────────┴──────────────┴━━━━━━━━━━┴━━━━━━━━┘
ingested 18 concept(s) from 1 file(s) into kb

Common options

FlagWhat it does
--no-llmDeterministic sectioning, no LLM needed. Start here.
--dry-runParse and plan only — write nothing.
--quiet, -qOnly warnings, errors, and the final summary line.
--recursiveRecurse into subdirectories when a SOURCE is a directory.
--provider, --model, --api-base, --api-keyLLM extraction settings (default path when --no-llm is not passed). See Providers & API keys.
Advanced - Re-ingesting the same file is deduplicated via per-file SHA-256 (manifest-tracked). - `--no-llm` files below ~1000 characters are **skipped** with `skipped (below 1000-char minimum; stub prevention)` — tiny files are never ingested. - Without `--no-llm`, `ingest` calls an LLM; if none is reachable it **errors** — there is no silent fallback. See [Ingesting documents](ingesting.html) and [Troubleshooting](troubleshooting.html) (`llm-unavailable`). - `--model` cannot be combined with `--no-llm`.

okfsmith sync

Incrementally sync a bundle with its source documents — only new, changed, renamed, or deleted files are processed. This is the command to reach for when your sources keep changing: run it after every edit instead of re-ingesting everything.

okfsmith sync [OPTIONS] {bundle} {sources}...
# One-shot: ingest what's new, update what's changed, drop what's deleted
okfsmith sync ./kb ./docs --no-llm

# Keep watching: re-sync whenever sources change (Ctrl-C stops)
okfsmith sync ./kb ./docs --no-llm --watch --interval 10

# Preview without writing anything
okfsmith sync ./kb ./docs --no-llm --dry-run

Real output (the table and summary line are exactly what you see):

                 Sync summary — kb
┏━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ File         ┃ Change ┃ Concepts ┃ Detail       ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ src/guide.md │ added  │        1 │ 1 concept(s) │
│ src/notes.md │ added  │        1 │ 1 concept(s) │
└──────────────┴────────┴──────────┴──────────────┘
sync: 2 added, 0 updated, 0 renamed, 0 removed, 0 unchanged, 0 skipped, 0 failed → kb

How it works

Each source file is fingerprinted with SHA-256 and recorded in <bundle>/.okfsmith/sync-state.json. On every run, sync diffs the live files against that state and classifies each file:

ChangeWhat happens
addedIngested (LLM or --no-llm path, same as ingest).
updatedOld concepts are replaced — re-ingested under the same ids, never duplicated as name-2.
renamedDetected by identical content hash; concepts keep their ids and history, only the resource provenance is updated.
removedConcepts are deleted from the bundle.
unchangedSkipped entirely — no parsing, no LLM calls.

Additions are applied before deletions, so a rename or replace can never leave the bundle momentarily empty. Writes are atomic and resumable: if a sync is interrupted (Ctrl-C, power loss), the state is marked incomplete and the next run picks up where it stopped — already-ingested concepts are adopted, never duplicated.

A few safety rules worth knowing:

  • Pre-flight on updates. If a changed file's new content would be skipped (unparseable, below the ~1000-char minimum, sectioning fails), the old concepts are kept instead of being wiped — you get a skipped row, not data loss.
  • Shared content is reference-counted. Two identical files share one set of concepts; deleting one source only drops the concepts when the last file with that content is gone.
  • Deletions are scoped. sync ./kb ./docs only ever removes concepts that came from ./docs — other source trees are untouched.
  • Unreadable files fail per-file (failed row) instead of aborting the whole run.

See Syncing sources for the full guide, including --watch mode, --format json for scripts, and the state-file format.


okfsmith list

List concepts in the bundle: id, type, title, trust tier, temporal validity.

okfsmith list [OPTIONS] {bundle}
okfsmith list ./kb

# JSON output only, for scripts
okfsmith list ./kb --format json | jq '.concepts[].id'

# Only human-reviewed concepts
okfsmith list ./kb --tier human-reviewed

Real output (trimmed — the real table had 18 rows):

                      Concepts in kb
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┓
┃ ID                 ┃ Type  ┃ Title        ┃ Trust tier ┃ Valid ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━┩
│ big/first-bundle   │ Draft │ First Bundle │ unverified │ —     │
│ big/installation   │ Draft │ Installation │ unverified │ —     │
│ big/trust-tiers    │ Draft │ Trust Tiers  │ unverified │ —     │
│ ...                │ ...   │ ...          │ ...        │ ...   │
└────────────────────┴───────┴──────────────┴────────────┴───────┘
18 concept(s)

The Valid column shows the temporal status: — for concepts with no temporal fields, current / expired / future / superseded otherwise (see Temporal model). JSON output adds temporal_status per concept.

Common options

FlagWhat it does
`--format <text\json>`Output format (default text).
--type <str>Only concepts of this type.
--tier <str>Only this trust tier: unverified, machine-confirmed, human-reviewed.
Advanced - `--no-llm` ingested concepts are `type: Draft`, tier `unverified`. - Concept ids look like `/` (e.g. `big/first-bundle`); duplicates get `-2`, `-3` suffixes.

okfsmith read

Print a concept: frontmatter as YAML, then the body.

okfsmith read [OPTIONS] {bundle} {concept_id}
okfsmith read ./kb big/first-bundle
okfsmith read ./kb big/first-bundle --format json

Real output (frontmatter, then body):

---
type: Draft
title: First Bundle
description: Draft concept extracted without LLM; needs review
resource: big.md
generated:
  by: okfsmith/0.3.0
  at: '2026-09-26T12:18:20.100846+00:00'
status: draft
tags:
- draft
- no-llm
---
Run `okfsmith init ./kb` to create a new bundle, then ingest documents.

When a concept carries temporal frontmatter (or is superseded by another concept), text output appends a one-line badge such as [temporal: superseded by policy/refunds-v2] or [temporal: expired (valid_until 2025-06-30 has passed)]; plain current concepts print exactly as before. JSON output adds temporal_status.

Common options

FlagWhat it does
`--format <text\json>`Output format (default text).
Advanced - Unknown concept ids produce an error — `read` never fabricates a concept.

Full-text search over a bundle: id, title, description, tags, and body, ranked with BM25 (stdlib-only, no new dependencies). The same engine powers the MCP server's search tool and chat's /search, so all three rank identically. See Searching a bundle for the query syntax (phrases, exclusions, stemming) and scoring details.

okfsmith search [OPTIONS] {bundle} {query}
okfsmith search ./kb "knowledge graph"
okfsmith search ./kb "quarterly revenue" --tier human-reviewed -n 5
okfsmith search ./kb "api design" --format json

# Replay the search as of a past instant (validity + supersession at that time)
okfsmith search ./kb "refund policy" --as-of 2025-06-01

# Also show superseded concepts (hidden by default, never deleted)
okfsmith search ./kb "refund policy" --include-superseded

Results print as a Score | ID | Type | Title | Tier | Valid table (IDs never truncated) plus an N result(s) line; zero results exit 0 with 0 result(s) and a stderr hint. An empty query is a usage error (exit 2).

Retrieval is conflict-aware (see Temporal model): current concepts rank first, concepts outside their validity window are demoted but still shown (marked expired / future), and superseded concepts are hidden unless --include-superseded is given (shown last, marked superseded→<id>). JSON rows carry temporal_status and superseded_by; the envelope adds as_of (the instant evaluated) and superseded_hidden (how many superseded results were filtered out).

Common options

FlagWhat it does
--limit <n> / -nMaximum results (default 10, must be ≥ 1).
`--format <text\json>`Output format (default text).
--type <str>Only concepts of this type.
--tier <str>Only this trust tier: unverified, machine-confirmed, human-reviewed.
`--as-of <date\datetime>`Replay search at an ISO-8601 instant: validity windows and supersession chains are evaluated then, not now.
--include-supersededAlso show superseded concepts (demoted, ranked last).

okfsmith validate

Validate a bundle against OKF v0.2 (E001–E004 / W001–W020).

okfsmith validate [OPTIONS] {bundle}
okfsmith validate ./kb

# Treat warnings as failures (exit code != 0 if any warning exists)
okfsmith validate ./kb --strict

# Machine-readable, for CI
okfsmith validate ./kb --format json

Real output — a conformant bundle exits with code 0 (verified with --strict too):

       Errors (0)
┏━━━━━━┳━━━━━━┳━━━━━━━━━┓
┃ Code ┃ File ┃ Message ┃
┡━━━━━━╇━━━━━━╇━━━━━━━━━┩
└──────┴──────┴━━━━━━━━━┘
      Warnings (0)
┏━━━━━━┳━━━━━━┳━━━━━━━━━┓
┃ Code ┃ File ┃ Message ┃
┡━━━━━━╇━━━━━━╇━━━━━━━━━┩
└──────┴──────┴━━━━━━━━━┘
Conformant: no errors, no warnings.

Common options

FlagWhat it does
`--format <text\json>`Output format (default text).
--strictTreat warnings as failures.

okfsmith graph

Show the concept link graph (nodes, edges, orphans, dead links).

okfsmith graph [OPTIONS] {bundle}
okfsmith graph ./kb

# Interactive viewer — writes <bundle>/viz.html by default
okfsmith graph ./kb --format html

# Mermaid diagram to stdout
okfsmith graph ./kb --format mermaid

Real output:

18 concept(s), 0 link(s), 0 dead link(s).

Orphans (0):
  (none)

Dead links (0):
  (none)

Common options

FlagWhat it does
`--format <text\json\mermaid\html>`Output format (default text). html writes an interactive visualization — colorblind-safe palette, backlinks, search.
--output <path>Write to a file instead of stdout.
Advanced - Default HTML output lands at `/viz.html`. - Mermaid output emits `flowchart LR` with one node per concept, e.g. `big_first_bundle["big/first-bundle — First Bundle"]`. - Deterministic (`--no-llm`) sectioning produces zero inter-concept links, so a fresh bundle reports 0 links — that still validates fine.

okfsmith doctor

Check the environment: dependencies, extras, Ollama, writability.

okfsmith doctor

That's it — doctor takes no arguments, just run it whenever something looks wrong.

Real output (this machine: no Ollama, no mcp/ocr extras — trimmed):

                                okfsmith doctor
┏━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Check          ┃ Status  ┃ Detail                                            ┃
┡━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ python >= 3.10 │ OK      │ 3.12.3                                            │
│ okfsmith       │ OK      │ 0.3.0                                             │
│ extra: mcp     │ MISSING │ Install the 'mcp' extra: pip install              │
│                │         │ 'okfsmith[mcp]' ...                               │
│ extra: ocr     │ MISSING │ Install the 'ocr' extra: pip install              │
│                │         │ 'okfsmith[ocr]' ...                               │
│ ollama         │ WARN    │ not reachable at http://localhost:11434 — use     │
│                │         │ --no-llm or set OPENAI_API_KEY                    │
│ llm api key    │ OK      │ set (hidden) (via OKFSMITH_API_KEY)               │
│ tmp writable   │ OK      │ /tmp                                              │
└────────────────┴━━━━━━━━━┴━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┘

doctor takes no options other than --help. If anything here looks wrong, head to Troubleshooting.


okfsmith chat

Chat with a bundle in natural language (Claude Code / Gemini CLI style).

okfsmith chat [OPTIONS] [bundle]

The bundle is optional — if you omit it, the current directory is used (when it is a bundle).

# Extractive mode: keyword-matched answers, zero setup, no LLM
okfsmith chat ./kb --no-llm

# Generative answers via a hosted provider preset (needs OKFSMITH_API_KEY set)
okfsmith chat ./kb --provider openrouter --model anthropic/claude-sonnet-4

# Non-interactive: pipe slash commands
printf '/list\n/exit\n' | okfsmith chat ./kb

Real startup banner (ASCII logo first, then the version line):

 ███  █   █ █████  ████ █   █ █████ █████ █   █
█   █ █  █  █     █     ██ ██   █     █   █   █
█   █ ███   ████   ███  █ █ █   █     █   █████
█   █ █  █  █         █ █   █   █     █   █   █
 ███  █   █ █     ████  █   █ █████   █   █   █
okfsmith chat v0.3.0
Bundle: kb (18 concepts) · extractive mode
Extractive mode — no LLM reachable. Answers are keyword-matched excerpts. Start
Ollama, set OKFSMITH_API_KEY + OKFSMITH_PROVIDER, or pass --provider, for
generative answers.

Tips for getting started:
  1. Ask questions about your documents.
  2. Type /help for chat commands.
  3. Type /ingest <path> to add more documents.

kb ›

Common options

FlagWhat it does
--no-llmExtractive mode: keyword-matched excerpts, no LLM involved.
--provider <str>Hosted provider preset (15 presets: ollama, lmstudio, openai, groq, mistral, deepseek, openrouter, together, fireworks, deepinfra, anyscale, perplexity, xai, gemini, agentrouter).
--model <str>Model id for generative answers.
--api-base <url>Any OpenAI-compatible endpoint (overrides --provider).
--api-key <str>API key — prefer OKFSMITH_API_KEY, since --api-key lands in shell history.

Full REPL walkthrough on Interactive chat; providers and keys on Providers & API keys.


okfsmith mcp

Serve the bundle over MCP (Model Context Protocol) so agents can read it.

okfsmith mcp [OPTIONS] {bundle}
# Default stdio transport — for Claude Code / Desktop config
okfsmith mcp ./kb

# Server-sent events
okfsmith mcp ./kb --transport sse

# Streamable HTTP
okfsmith mcp ./kb --transport streamable-http

Requires the optional extra (flagged MISSING by doctor):

pip install "okfsmith[mcp]"

Without the extra, the command tells you exactly what to do:

error [missing-extra]: The MCP server requires the 'mcp' extra: install it with `pip install "okfsmith[mcp]"`.
hint: Install it with: pip install "okfsmith[mcp]" (or pipx: pipx install "okfsmith[mcp]", or uvx: uvx --with "okfsmith[mcp]" okfsmith mcp ./kb)

Common options

FlagWhat it does
`--transport <stdio\sse\streamable-http>`Transport (default stdio).

The server exposes eight MCP tools — index, list, search, get, neighbors, traverse, provenance, diff. These are tools for connected agents; search is also a CLI command (okfsmith search), while get remains MCP-only (the CLI analogue is read). Client config examples for Claude Code/Desktop, Cursor, Copilot, and Gemini are on MCP server.


okfsmith eval

Score a bundle against a golden Q&A set — the RAG Triad, per question, with retrieval-vs-generation diagnosis for every failure.

okfsmith eval ./kb --init-sample
okfsmith eval ./kb --no-llm
okfsmith eval ./kb --format json
okfsmith eval ./kb --fail-under 70
FlagWhat it does
--init-sampleWrite a starter <bundle>/eval/golden.json from the bundle's own concepts, then exit.
--top-k / -nConcepts retrieved per question (default 5).
--fail-under <0-100>CI gate: exit 1 when the overall score misses it (exit 0 = pass).
--metric-threshold <0-1>Per-metric pass bar (default 0.6 context relevancy / faithfulness, 0.4 answer relevancy).
--no-llmForce heuristic scoring even when a provider is configured.
--model / --provider / --api-base / --api-keyLLM judge backend (same plumbing as chat).
--as-of <date>Replay retrieval at a past/future instant.
--include-supersededAlso retrieve superseded concepts.
`--format text\json`Human table + diagnosis, or the full machine-readable report.

The report scores each question per metric with 🤖 (llm-judge) or ⚙ (heuristic) markers, then prints the diagnosis for every failing question. Malformed golden files fail as error [golden-invalid] / error [golden-schema] — never a traceback. Full guide on Evaluating bundles.


Exit codes

ExitMeaning
0Success — validate prints Conformant: no errors, no warnings.
1Validation failed (errors, or warnings under --strict); or a general command error.
2CLI usage error — e.g. No such command for okfsmith get.

Next: MCP server → — bundle built, now serve it to agents.