# okf-kb — Design

audience: AI coding agents first. Contract-level: seams + decisions, NOT code bodies.
slug: `okf-kb` · date: 2026-06-30

## Purpose

Give the mega-plan-harness a shared **Open Knowledge Format (OKF) 2nd brain** — a curated, single-source-of-truth
knowledge base that every CLI agent (claude, codex, cursor, opencode) reads from in its own native context
mechanism, so all agents stay current on global / project / job knowledge. This is sub-project **2 of 3** from
the Mega Plan Harness brief (1 = Control & Observability API `harness-control-api`, 3 = Web UI).

**OKF is master; native memories are projections** (resolved decision). OKF projects OUT into each CLI's
native context and CAPTURES BACK facts agents write to native memory, then re-projects — one canonical store,
conflict-free. The Web UI's "OKF management page" (sub-project 3) binds this CLI + format; nothing rendered here.

Read first, do not duplicate: the harness invariants (`spec/FORK.md` — "runs anywhere, zero-dep"), the global
hook dispatcher (commit `e178459`), and the OKF Repository Navigation Protocol in `docs/design.txt` (lines 19–38,
the canonical projected text).

## Ground truth (probed 2026-06-30 — do not re-derive from memory)

The four CLIs have **asymmetric memory substrates** — the design's central constraint:

| CLI | Native substrate | OKF relationship |
|---|---|---|
| claude | `~/.claude/projects/<enc>/memory/*.md` curated per-fact + `MEMORY.md` index + YAML frontmatter; global `~/.claude/CLAUDE.md` | **subsumed via continuous normalization** — OKF makes its schema canonical for this dir (resolved). Claude Code's native protocol is harness-injected and CANNOT be disabled, so it keeps writing native-format files; every `sync` captures those, re-migrates them, and overwrites `MEMORY.md` wholesale — the native protocol runs *upstream* of OKF, never replaced |
| codex | `~/.codex/AGENTS.md` global + repo-level `AGENTS.md` | **1-way** project → `AGENTS.md` nav block |
| opencode | `AGENTS.md` convention + `opencode.json` | **1-way** project → `AGENTS.md` (shared artifact) |
| cursor | `~/.cursor/chats/` raw history (uncurated) + `.cursor/rules/*.mdc` / `AGENTS.md` | **1-way** project → `AGENTS.md`; chats NEVER captured (not curated facts) |

- `<enc>` = repo abs-path with `/`→`-` (e.g. `-home-user-Projects-mega-plan-harness`). **Verify-at-build:** this
  `/`→`-` rule is inferred from one path with no `.`/`_`; before pinning, confirm Claude Code's exact encoder
  against a repo path containing `.` or `_` (e.g. an `achiron.download`-style root) — path encoders often touch
  more than `/`. Probed native frontmatter: `name` / `description` / `metadata.type ∈ user|feedback|project|reference`.
- **Subsume migration runs EVERY capture (not one-time):** Claude Code's native protocol is harness-injected and
  cannot be turned off, so it keeps emitting native-format files (`name`/`description`/`metadata.type`) — legacy
  files on the first run, freshly agent-written files on every subsequent run. Each `capture` re-migrates any
  native-format file it finds: OKF's canonical frontmatter (component 1) absorbs it losslessly — `metadata.type`
  → OKF `type` (open enum legitimately includes `user|feedback|project|reference`), `name` → slug/`okf_id`,
  `description` → `description`, and `title` is synthesized from `name`/`description` (native has no `title`).
  Net effect: OKF continuously normalizes the dir to one schema; the native taxonomy survives as OKF `type` values.
- **One `AGENTS.md` artifact serves codex + opencode + cursor at once** — the de-facto cross-CLI standard. No
  per-CLI duplication.
- No OKF exists anywhere yet → clean build.

## Non-goals (YAGNI)

- **No Web UI** — sub-project 3 (the OKF management page binds this format/CLI).
- **No cursor chat-history mining** — `~/.cursor/chats/` is raw, uncurated; capturing it would pollute the KB.
- **No semantic / vector search** — retrieval is the brief's **progressive `index.md` navigation** (metadata
  filtering by frontmatter), explicitly NOT grep-first or embeddings. Stated as the retrieval contract.
- **No daemon / fs-watcher** — sync is trigger-driven (CLI + hooks), matching the harness "runs anywhere" rule.
- **No remote / multi-machine sync** — global tier is machine-local. Cross-machine = later, separate.
- **No platform-modules.** Like `harness-control-api`, the OKF core is zero-dep Node stdlib so it runs in any
  headless/cron agent context. Markdown-editor / search UI packages belong to the Web UI sub-project.

## Architecture

```
            OKF STORE (master, plain markdown + YAML frontmatter, 3 tiers)
  ~/.local/share/okf/            global  (XDG, machine-wide)
  <repo>/.okf/                   project (committed — travels w/ repo, code-reviewed)
  <repo>/runstate/<slug>/okf/    job     (per-run, ephemeral → promotable to project)
        │                                   ▲
        │ project (render, OKF schema)      │ capture (ingest native edits, dedup, provenance-tag)
        ▼                                   │
  ~/.claude/.../memory/*.md + MEMORY.md  ───┘   (claude: SUBSUMED — OKF owns dir + MEMORY.md, OKF schema, FULL regen)
  ~/.claude/CLAUDE.md  (managed block)          (claude global: 1-way)
  <repo>/AGENTS.md + ~/.codex/AGENTS.md (managed block)  (codex/cursor/opencode: 1-way)

  triggers: CLI session-start ⇒ `okf project`   ·   harness wave-boundary + session-end ⇒ `okf sync`
            (sync = capture-THEN-project; capture always precedes project — see ordering invariant)
```

**Ordering invariant (load-bearing):** `sync` = **capture before project**, always. Native edits are ingested
into OKF first, then OKF re-renders the projection — so projection never clobbers an un-captured native edit.

**Loop prevention:** every projected/captured fact carries provenance frontmatter (`okf_source`, `okf_id`).
Capture skips files whose content is byte-identical to what OKF last projected (tracked by `okf_id` + hash), so
project→capture→project never oscillates.

**Managed-region discipline:** projected content in shared docs (`CLAUDE.md`, `AGENTS.md`) lives ONLY between
sentinels `<!-- okf:begin id=<scope> -->` … `<!-- okf:end -->`. Hand-written content outside the markers is
never touched. Re-projection replaces only the managed region.

## Components & seams

### 1. OKF store format — the data contract (`spec/okf-format.md`)

The on-disk KB contract every tier + every agent obeys (the brief's OKF rules, pinned):

- **Single concept per file** — `<concept-slug>.md`, one minimal topic.
- **Frontmatter (required)** — pin:
  ```yaml
  ---
  type: <concept|guide|reference|decision|...>   # open enum; REQUIRED
  title: <one line>
  description: <one sentence — used by index + metadata filtering>
  tags: [<kebab>, ...]
  scope: global|project|job                        # tier this file belongs to
  okf_id: <stable uuid>                            # identity across project/capture
  okf_source: authored|claude-memory|<cli>         # provenance (loop prevention)
  ---
  ```
- **`index.md` per directory** — markdown links to each child (file or subdir) + a one-sentence summary each.
  This IS the navigation surface (progressive descent). Pin the line shape: `- [Title](path) — <one sentence>`.
- **Links between concepts** — relative markdown links; `okf doctor` validates none dangle.

### 2. `okf` CLI — `bin/okf` (zero-dep Node stdlib; fail-closed, exit 0/2/3 like the wrapper contract)

Verbs (pin signatures; `--repo` defaults to cwd's git root, `--run` to the active run slug):
```
okf project [--scope global|project|job|all] [--repo <root>] [--run <slug>] [--target claude|agents|all]
okf capture [--from claude-memory] [--repo <root>] [--run <slug>]
okf sync    [--repo <root>] [--run <slug>]          # capture THEN project (the reconcile)
okf new <concept-slug> --scope <s> [--type <t>]     # scaffold a frontmatter'd file + update index
okf index   [--scope <s>]                            # regenerate index.md from dir contents
okf promote <concept-slug> --from job --to project   # job→project promotion (self-improvement path)
okf doctor  [--scope all]                            # validate frontmatter, index coverage, dangling links, orphans
```
Exit: `0` ok · `2` usage/validation error · `3` target-unwritable / integrity failure (fail-closed, never
silent partial write — write to temp + atomic rename per target).

### 3. Projection engine — `lib/okf-project` (the deepest outbound seam)

Maps OKF concept files → each CLI's native context. Callers can't tell which target format is produced.
```
okf-project <scope> <repo?> <run?> <target> → writes native artifacts; returns {written:[...], skipped:[...]}
```
Per target:
- **claude project memory (SUBSUMED — OKF owns this dir)** — render each in-scope concept to
  `~/.claude/projects/<enc>/memory/<okf_id-or-slug>.md` writing OKF frontmatter **verbatim** (NO type→metadata
  mapping — OKF schema is canonical here post-migration). OKF **fully owns `MEMORY.md`**: regenerate it wholesale
  from the in-scope set (NOT a managed-region merge — there is no native co-owner to preserve, the native protocol
  is replaced). The generated `MEMORY.md` keeps the harness-readable line shape `- [Title](file.md) — <hook>`
  (identical to the `index.md` line shape) so the harness-injected index stays parseable. `<enc>` derived from
  `--repo` abs-path (see verify-at-build encoder note). Output filename =
  the concept's recorded origin filename if it has one (captured facts), else `<okf_id-or-slug>.md` — so
  capture→project round-trips to the same path (see component 4 reconciliation; no duplicate-file divergence).
- **claude global** — refresh the managed block in `~/.claude/CLAUDE.md` (global-scope facts + nav pointer).
- **AGENTS.md** (`<repo>/AGENTS.md` for project scope, `~/.codex/AGENTS.md` for global) — refresh the managed
  block: the **Repository Navigation Protocol** (component 5) + a tier-pointer index. One artifact, all three CLIs.
- Idempotent: re-projecting unchanged OKF is a no-op (hash-compared managed region).

### 4. Capture engine — `lib/okf-capture` (inbound reverse map)

Detect facts an agent wrote to native memory that did NOT originate from OKF, ingest as OKF concepts, dedup.
```
okf-capture <from> <repo?> <run?> → new/updated OKF concept files; returns {ingested:[...], skipped:[...]}
```
- **Source = claude memory only** (the only structured store; OKF-owned under subsume). For each
  `~/.claude/projects/<enc>/memory/*.md` whose `okf_source` is absent or ≠ a value OKF wrote (i.e. agent-authored
  this turn, possibly in legacy native frontmatter): migrate frontmatter (subsume mapping above), create/update
  the matching OKF concept in the master store (assign `scope` from project context, mint `okf_id`, set
  `okf_source: claude-memory`).
- **Filename reconciliation (no duplicate fact)** — a captured native file lands at its descriptive native name
  (e.g. `project_megaplan_subprojects.md`), but projection re-emits keyed by `okf_id`. Capture records the
  origin filename in the concept and projection writes back to **that same path** (origin filename wins over a
  fresh `okf_id`-slug when one exists), so one fact = one file across the round-trip — never two.
- **Dedup / loop guard** — skip if an OKF concept with the same `okf_id` already holds byte-identical body, or
  if the memory file's content hash matches OKF's last projection (provenance + hash). Prevents re-ingest churn.
- **AGENTS.md / codex / cursor are NOT capture sources** — they are freeform instruction docs / raw chats, not
  fact stores. Capture is claude-memory→OKF only; everything else is project-only (1-way). Stated explicitly.

### 5. Navigation protocol — the canonical projected text (`spec/okf-nav-protocol.md`)

The fixed reminder block projected verbatim into `CLAUDE.md` / `AGENTS.md` managed regions. Content = the brief's
**Repository Navigation Protocol** (progressive `index.md` descent; metadata filtering on frontmatter `type`/`tags`;
upkeep rules — single concept, required frontmatter, immediate index update). Pinned as one canonical literal so
every CLI gets identical guidance; edited in one place, re-projected everywhere.

### 6. Tier resolution + promotion — `lib/okf-scope`

- **Resolve** active scopes at any call: `global` always; `project` if cwd is in a git repo containing `.okf/`
  (auto-`okf new` bootstraps it); `job` if a run slug is active (`runstate/<slug>/okf/`).
- **Precedence on read/projection** — `job` overrides `project` overrides `global` for same-`okf_id` concepts
  (most-specific wins); pin this so the projected MEMORY/AGENTS view is deterministic.
- **Promotion** — `okf promote` moves a job-tier concept to project tier (re-homes the file, re-mints scope,
  updates both indexes). This is the **self-improvement-on-failure** durable path: a lesson learned in a run
  (job knowledge) is promoted to travel with the repo. Promotion is the only job→project write (explicit, audited).

### 7. Harness hook integration — attaches to the existing global dispatcher

No new daemon. Pin which event fires which verb:
- **CLI session-start** (claude/codex/cursor/opencode entry) → `okf project --scope all` (agent opens with fresh KB).
- **harness wave-boundary + session-end** → `okf sync` (capture any in-run native edits, re-project; job knowledge
  persisted). Wave-boundary tie-in is where run-learned facts enter the job tier.
- Hooks are thin shells calling `bin/okf`; the dispatcher (commit `e178459`) routes them. Failure of a hook is
  logged, non-fatal to the agent turn (projection is best-effort-fresh, never blocks work) — EXCEPT `okf doctor`
  integrity failures surface as warnings (no-ignored-signals).

## Data flow

agent/harness triggers `okf sync` → **capture** ingests agent-authored claude-memory facts into the right OKF
tier (dedup by `okf_id`+hash) → **project** re-renders all in-scope OKF concepts into claude memory + MEMORY.md +
the CLAUDE.md/AGENTS.md managed blocks → next agent (any CLI) opens with the merged, current KB and navigates it
via `index.md` progressive descent.

## Error handling

Fail-closed (repo invariant). Every target write is temp-file + atomic rename — no partial projection. Missing
`okf_id`/frontmatter on a concept ⇒ `okf doctor` flags it, projection skips it (visible, never silent). Capture
conflict (same `okf_id`, divergent bodies) ⇒ keep OKF master copy, record the native variant as a
`needs-merge` sibling + warn (never auto-clobber an agent's words). Managed-region sentinels missing/corrupted
in a target ⇒ re-emit the full block, never append a duplicate. Hook failure ⇒ logged, agent turn proceeds.

## Testing strategy

- **Format/doctor**: fixture KB with a dangling link, a missing-frontmatter file, an index omission → `okf doctor`
  flags each; a clean KB passes.
- **Projection** (deepest seam): fixture OKF tier set → assert exact claude `memory/*.md` + `MEMORY.md` output and
  the exact `AGENTS.md` managed block; re-project unchanged → no-op (byte-identical); hand-written content outside
  sentinels survives.
- **Capture**: seed an agent-authored claude memory file → `okf capture` ingests it with `okf_source:claude-memory`;
  re-run → skipped (loop guard); a byte-identical OKF-origin file is never re-captured.
- **Round-trip**: `okf sync` twice in a row → second run is a no-op (capture+project idempotent, no oscillation).
- **Scope/precedence**: same `okf_id` in job+project+global → projected view shows job copy (precedence).
- **Promotion**: `okf promote --from job --to project` re-homes file + updates both indexes.
- **Hook smoke**: session-start fires `okf project`; wave-boundary fires `okf sync`; hook failure is non-fatal.

## Architecture Decisions

- **Claude memory dir is SUBSUMED, not co-owned (resolved decision).** The native dir `~/.claude/.../memory/`
  is governed by Claude Code's own autonomous memory protocol — two managers in one directory collide three ways:
  incompatible frontmatter (native `name`/`metadata.type` closed vs OKF `title`/`type` open), both regenerate
  `MEMORY.md`, divergent filename conventions → duplicate facts. Resolution: **OKF subsumes via continuous
  normalization** — the native protocol is harness-injected and cannot be disabled, so OKF does NOT replace it; it
  runs *downstream* of it. Every `sync` captures whatever native-format files the agent wrote, re-migrates them to
  one canonical schema (native taxonomy absorbed losslessly into OKF `type`), and overwrites `MEMORY.md` wholesale.
  The discriminating fact: a directory under another tool's autonomous protocol cannot be co-owned NOR can the
  other protocol be switched off — so the only conflict-free path is to let it write and continuously normalize
  after it, which IS the single-source-of-truth the brief asks for (every reader sees the OKF-normalized view).
  **Cost accepted:** OKF must track Claude Code's memory-dir layout/encoder and re-migrate native writes on every
  capture (cheap, hash-gated). *Rejected alternative — separate-surface (project to an OKF-only subdir +
  treat native dir as 1-way capture-source):* avoids the migration but is NOT single-source (the native dir stays
  native, agents reading it bypass OKF), so it loses the brief's "all agents always up to date" guarantee. Deep.
- **OKF master + project/capture, NOT bidirectional merge.** Only claude has a structured store to merge against;
  codex/cursor have nothing structured → a "merge" would be lopsided and conflict-prone. One master + 1-way
  projection + a narrow claude-memory capture path is deterministic and conflict-free. Capture-before-project
  ordering + provenance/hash loop-guard make it safe. Deep.
- **Zero-dep CLI + hooks, NOT a watcher daemon.** Inherits the harness "runs anywhere, anthropic-less" invariant
  (FORK.md) — a daemon can't run in every headless/cron agent context. Triggers are explicit; the repo already
  has a global hook dispatcher to attach to. Freshness is trigger-bound (acceptable: curated knowledge, not
  telemetry). Reversible (a watcher is addable later if needed). Deep vs the rejected daemon.
- **One `AGENTS.md` artifact for codex+cursor+opencode.** Probed: all three honor the AGENTS.md convention →
  projecting once serves three CLIs, no per-CLI format. Deep (hides 3 consumers behind one render target).
- **Retrieval = progressive `index.md` navigation, NOT search.** The brief's OKF protocol is the contract;
  index-descent + frontmatter filtering keeps token cost low and prevents blind grep. Vector/semantic search is
  an explicit non-goal. Medium.
- **Project tier committed in-repo, job tier run-scoped + promotable.** Project knowledge travels with the repo
  and is code-reviewed; job knowledge is ephemeral per-run and promotes to project only via explicit `okf promote`
  (the self-improvement durable path). Global tier is XDG machine-wide. Medium.
- **cursor chats + AGENTS.md are NOT capture sources.** Raw history / freeform instruction docs are not curated
  facts; capturing them pollutes the KB. Capture is claude-memory→OKF only. Medium.
- **Rejected — store OKF only in claude's memory dir (option C).** Would not give codex/cursor/opencode a real
  shared 2nd-brain (they'd just read claude's), and couples the KB to one CLI's private layout. Rejected: the
  brief's intent is cross-CLI shared knowledge. 
- **Rejected — per-CLI native format adapters for codex/cursor/opencode.** They share AGENTS.md; separate adapters
  would be three single-adapter seams (YAGNI) with no second implementation behind them. Collapsed into one
  AGENTS.md projector.
