#+TITLE: Design: AI Knowledge Base (ai-kb) #+AUTHOR: Craig Jennings #+DATE: 2026-05-24 #+OPTIONS: toc:nil num:nil * Status Ready. Five reviews incorporated (=ai-kb-review.org= through =-review5.org=; all 2026-05-24). The four original blockers (version control + recovery, switch-state safety, startup surface, project-awareness) and review 4's two write-loop caveats (push-failure contract, index regeneration) have decisions. Review 3's operational shape (a repo-resident agent-neutral contract, a minimal CLI, maintenance commands, multi-agent provenance) is adopted. Review 5's implementation-hardening is folded in: the commit gate runs the *full* =ai-kb lint= (not just node org-lint), an explicit org-lint fatal-check list, observable push failures, a testable =ai-kb query= contract, a Step 1a/1b split, and ID-first durable pointers. Cross-agent is *not a near-term goal* (Craig, 2026-05-24): v1 ships the Claude adapter over the neutral contract, and other-agent adapters (Codex/Ollama, MCP) are deferred to [[*vNext][vNext]]. All open decisions are resolved (see [[*Agreed decisions][Agreed decisions]]); the spec is fully decided and Step 1 is buildable. In scope: Step 1 (store + contract/CLI + global rule + provisioning) and Step 2 (Emacs browsing layer). Step 3 (migrating =.ai/sessions= and workflows in) and the full LLM-Wiki layer are *deferred to their own specs* — see [[*vNext][vNext]]. * Scope decision: memory store, not (yet) an LLM Wiki ai-kb v1 is a *global, durable, cross-project memory store* for AI coding agents (Claude Code today; agent-neutral by contract): org-roam nodes holding lessons, principles, Craig's preferences, reusable procedures, and durable observations. It is the concrete first slice of the broader "org-roam as agent memory" vision in [[file:agentic-knowledgebase.org][agentic-knowledgebase.org]]. It is *not* a Karpathy-style LLM Wiki in v1. That pattern — immutable =raw/= sources, compiled =wiki/= synthesis pages, =schema.org=, source hashes, and full ingest/query/lint pipelines — is a larger product whose value is *grounding compiled knowledge in re-checkable sources*. v1 adopts the one piece that pays off immediately: a =raw/= capture for *external* sources (see [[*Grounding external sources][Grounding external sources]]). The rest of that machinery is the documented evolution path (see [[*vNext][vNext]]); v1's structure is chosen so it can grow that way without a rewrite. * Problem AI coding agents start every session cold. Continuity today is per-project and flat. There is no home for durable, *general* knowledge that should follow the agent into every repo — engineering lessons, Craig's cross-project preferences, reusable procedures (e.g. "move a local repo to git.cjennings.net with a mirror-to-GitHub hook") — and no link structure relating one piece of knowledge to another. A flat shared lessons file would solve "knowledge that follows the agent" alone; org-roam is chosen over it for *link structure*, *first-class browsing* (node-find, backlink buffer, graph), and a substrate that grows toward the agentic-KB vision. The complexity is earned by those three. * Memory tiers Naming the tiers (after Nexus's vocabulary) so every agent routes consistently: - *T1 — session scratch:* the current chat, spawned-agent handoffs. Ephemeral. - *T2 — project memory:* per-project =~/.claude/projects//memory/=, =.ai/notes.org=, active project decisions. Minor or project-specific. - *T3 — ai-kb:* global, durable, cross-project. Significant and general: lessons, principles, preferences, reusable procedures, durable observations. T2's =MEMORY.md= shrinks toward an index: for significant items it points at the T3 (ai-kb) node rather than holding the content. ai-kb is *not* a dump for T1/T2 breadcrumbs — the proactive-write bar (below) keeps it T3-only. * Concept: two layers - *Store* — a git repository of org files (each a valid org-roam node). The agent reads/writes these directly and never touches the SQLite database; the files are the source of truth. - *Emacs/org-roam integration* — so Craig can browse with backlinks and the graph. org-roam keys off one global =org-roam-directory= + =org-roam-db-location= per session, so ai-kb cannot be live alongside the personal roam; the integration is a *switch* with a guard contract (see [[*The Emacs switch: guard contract][guard contract]]). * Storage, version control, and recovery ai-kb is its *own git repository* — not in =~/sync/org= (Syncthing has proven unreliable for backup/restore: no history, silent =.sync-conflict= files) and *not* in =~/.emacs.d= (publicly mirrored to GitHub; ai-kb holds personal/work-private knowledge that would leak). - *Location:* =~/.local/share/ai-kb= (XDG =$XDG_DATA_HOME/ai-kb=). - *Origin:* a bare repo on =git.cjennings.net= (=git@cjennings.net:ai-kb.git=), *private — no public GitHub mirror*. This is the recovery layer: full history, clone-to-restore. - *No Syncthing.* git is the sole sync and backup; multi-machine concurrency surfaces as ordinary git merges, not silent conflict files. - *org-roam scope:* =org-roam-directory= points at the repo root; =raw/= is *excluded* from the scan (=org-roam-file-exclude-regexp= matching =/raw/=) so raw captures never become noisy roam nodes. The LLM-Wiki vNext would add a compiled =wiki/= layer; v1 keeps compiled nodes flat at root. * Write protocol and synchronization The agent writes nodes from the shell, possibly from several machines or concurrent processes, so the write path is a defined protocol, not a bare =git push=. Encapsulated in the =ai-kb remember= operation (see [[*The agent contract and operations][operations]]): 1. *Before write:* =git fetch=; if behind and clean, =git pull --ff-only=; if diverged or the tree is dirty with unrelated changes, *abort and surface* — don't auto-merge. 2. *Write/edit the node.* 3. *Regenerate the index* from node properties (see [[*Startup surface and retrieval contract][Startup surface]]). 4. *Validate the whole change, not just the node — this is the safety boundary.* Run the full =ai-kb lint= over the change set before committing: =org-lint= fatal checks on *both* the edited node and the regenerated index, index freshness/completeness, duplicate =:ID:=, broken =[[id:...]]= links (excl =raw/=), missing required properties, invalid project slugs, and a credential/secret scan of nodes *and* =raw/=. Any failure aborts the commit. (Gating only on single-node org-lint would let a stale index or a leaked secret through — then the write protocol isn't the boundary the spec claims.) 5. *Commit locally — always.* The local commit is the durable record. 6. *Push — best-effort, non-blocking, never fatal, and observable.* =remember= commits locally and does *not* push; a background =systemd --user= timer (~15 min) pushes when the repo is ahead. A failed push (offline, network blip, gpg-agent SSH key not loaded — observed this session) is *logged to a state file* (under the repo or =$XDG_STATE_HOME/ai-kb=) and ignored, never erroring or hanging the agent. Visibility comes from three surfaces so the KB can't go quietly local-only: the log, =ai-kb doctor= (reports "ahead N", "push failed", or "remote diverged"), and a one-line startup/adapter nudge when there are unpushed commits or a recorded rejection. 7. *On push rejection* (remote moved): do *not* blind-retry. Fetch, record the divergence, leave the local commit intact for resolution. 8. *Same-machine concurrency:* =flock= around =remember= serializes concurrent agents (Claude + Codex + an Emacs save) so they don't race. A v1 file lock; not a daemon. * Why a separate database org-roam supports one active =org-roam-directory= / =org-roam-db-location= at a time. ai-kb gets its own directory (the repo above) and its own database (=~/.emacs.d/org-roam-ai.db= — a regenerable cache). The personal roam (=~/sync/org/roam/= + =~/.emacs.d/org-roam.db=, recipes etc.) is never scanned or modified. * The sync model The =.org= files are truth; the SQLite db is a cache indexing nodes and =[[id:...]]= links that powers Emacs's backlink buffer, node-find, and graph. Editing in Emacs updates the cache on save (=org-roam-db-autosync-mode=); agent shell writes don't, so =org-roam-db-sync= re-scans. The key consequence: *the agent never needs the db to check links* — they live in the files and are grepped (always current). *Craig's Emacs browsing* needs the cache current, so the switch-to-ai-kb command syncs on entry; the agent may also fire =emacsclient -e '(cj/ai-kb-db-sync)'= for immediacy, but agent correctness never depends on Emacs running. * Proactive-write rule The agent writes a node *unprompted* when something is **durable** (true beyond this session) *and* **general** (T3, not tied to the current repo; project-specific knowledge goes to T2). The bar, to keep out noise: genuinely worth recalling or linking later — a principle, a reusable procedure, a preference, a non-obvious lesson — not routine status or anything re-derivable from code or git. New nodes link to related existing ones (grep candidates by title/tag first) and trigger an index regeneration. *Contradiction guard:* if a write would contradict an existing node that affects agent behavior or a stated preference, the agent does *not* silently overwrite. It marks both =:STATUS: contested=, records the conflict, and asks Craig before changing the canonical node. * Node format and conventions #+begin_src org :PROPERTIES: :ID: :PROJECTS: :general: ; or :deepsat: :emacs: ... (see slug rule below) :CREATED: 2026-05-24 :UPDATED: 2026-05-24 :CREATED_BY: claude-code ; claude-code | codex | ollama | human :CONFIDENCE: user-stated ; user-stated | observed | inferred | external :VISIBILITY: personal ; personal | work-private :SOURCE: chat 2026-05-24 ; free-form, or a raw/ path for external sources :STATUS: current ; current | contested | superseded :END: #+title: Concise node title #+filetags: :principle:emacs: Body. Link related nodes with [[id:OTHER-UUID][Their title]], optionally prefixed with a relation label: SUPERSEDES, CONTRADICTS, RELATES_TO, IMPLEMENTS, DERIVED_FROM. #+end_src - *Filename:* org-roam convention — =YYYYMMDDHHMMSS-slug.org= (or =slug.org= for stable, frequently-linked nodes). Filenames are for humans and can change during curation, so they are *not* the durable identity. - *ID:* a real UUID (=uuidgen=) — org-roam won't index a node without one, and the =:ID:= is the *durable identity*. External pointers (a per-project =MEMORY.md= → an ai-kb node) are *ID-first*: =ai-kb: (<UUID>)=, resolved by ID with title as fallback, so a rename or curation merge doesn't dangle the pointer. - *Type tags* (=#+filetags:=): =:principle:= =:preference:= =:procedure:= =:observation:= =:reference:=. - *Project slugs* (=:PROJECTS:=): derived from the project directory basename (so =~/.emacs.d= → =:emacs:=, the DeepSat repo → =:deepsat:=), with =:general:= for cross-cutting nodes. The derivation rule lives in the contract so every agent produces the same slug; new slugs are recorded in the index's project list. - *Provenance:* =:CREATED_BY:= and =:CONFIDENCE:= let later curation and trust policy distinguish "Craig stated this" from "a model inferred it." =:CONFIDENCE:= here is *provenance* (how the claim was obtained), not a numeric grounding score — the latter is vNext. =:VISIBILITY:= is two-valued in v1 (the full =public|work-private|secret= taxonomy is vNext); secrets are never stored at all (see [[*Security and privacy][Security]]). - *Relation labels:* a small fixed vocabulary used in link context now; full typed-link catalog storage is vNext. * Grounding external sources The one LLM-Wiki piece adopted in v1: keep compiled knowledge re-checkable where an external source exists. - *Node authored from an external source* (web article, fetched doc, transcript, API result): capture under =raw/= and point =:SOURCE:= at that path. *By default store the URL, retrieval date, and the relevant excerpt* — store full external text only when it is user-owned, licensed for the use, or operationally necessary (this is a private KB, but copyright still applies). A later agent can re-ground a suspicious node against the source instead of trusting its own prior summary. - *Node authored from the conversation or direct observation*: only the free-form =:SOURCE:= pointer; no raw capture (the source is not an external artifact). - =raw/= is append-only in spirit and excluded from org-roam's scan. * Startup surface and retrieval contract Passive grep-on-demand gets under-used; loading the whole KB wastes context. Two tiers: - *L1 — always loaded:* the global rule adapter (=claude-rules/ai-kb.md= for Claude), tiny. It carries the path, routing rule, link-grep recipes, and: *when a task may involve durable knowledge, read the index first.* Include concrete example triggers so it actually fires — e.g. "before choosing a formatter/test/lint convention," "before a multi-step procedure you've likely done before (repo setup, release, deploy)," "when Craig states a preference," "when you hit a non-obvious gotcha worth keeping." - *L2 — on demand:* =index.org= at the repo root, read at session start only when L1's condition applies. - *Full nodes* read only when the index points at them or Craig asks. =index.org= is *generated output*, never hand-maintained — that is what keeps it from drifting from the nodes. A regeneration script greps node properties (=#+title:=, =:ID:=, type tag, =:PROJECTS:=, =:UPDATED:=, =:STATUS:=) and rebuilds the file with a "generated, do not edit" marker. It runs in provisioning, in the curation pass, on demand, and as step 3 of every =remember=. =lint --index= checks: every listed id resolves, every =current= node is listed, contested/superseded sections are accurate, the size budget holds (split into =index-procedures.org= etc. when exceeded). #+begin_src org * Procedures | Title | ID | Summary | Projects | Updated | * Preferences | Title | ID | Summary | Projects | Status | * Contested / needs review | Title | Issue | Last touched | #+end_src * Checking links (agent recipes) No database needed; grep the files (excluding =raw/=): - *Backlinks to a node* — =rg -l "id:<UUID>" ~/.local/share/ai-kb --glob '*.org' --glob '!raw/**'=. - *Forward links from a node* — grep that node's file for =id:= links. - *Find a node to link to* — grep titles/tags. * Node validity (org-lint) The agent writes raw org from the shell, bypassing Emacs's structural editing, so malformed org (broken drawer, bad property, broken timestamp) can slip in and make =org-roam-db-sync= choke or mis-index. Distinct from the semantic link/credential checks; both run. - *On write:* =org-lint= via =emacs --batch=, gating on a concrete *fatal-check* list (not the vague "error-level," so a future org-lint behavior change can't silently weaken or over-tighten the gate, and tests target the list directly): - malformed property drawer - missing or duplicate =:ID:= - an invalid required-property line - missing =#+title:= - structurally invalid org that prevents parse/index Style warnings stay non-fatal. A node hitting a fatal check is not committed. - *In curation:* an =org-lint= sweep over all nodes catches drift or bad Emacs-side hand-edits. Cheap (sub-second batch on one small file); the safety net that makes "the agent writes raw org" trustworthy. Reuses/extends the project's =scripts/lint-org.el=. This node-level gate is run as part of the full =ai-kb lint= the write protocol invokes before commit (step 4 above) — it never stands alone as the only check. * The agent contract and operations The access layer is an *agent-neutral contract*, not a Claude-only prompt snippet. Cross-agent use is not a near-term goal (deferred to vNext), but making the contract repo-resident and neutral *in shape* costs nothing now, future-proofs that path, and — more importantly for v1 — the CLI earns its place on Claude-only grounds: it is the clean, atomic, testable home for the write protocol, index regeneration, and lint, far better than scattering them across prose rules. - *Canonical contract:* lives *in the repo* (=~/.local/share/ai-kb/AGENT_CONTRACT.org=) — the source of truth for the node format, routing rule, write protocol, and operations. It travels with the store. - *Adapters* point at it: =claude-rules/ai-kb.md= (symlinked into =~/.claude/rules/= by rulesets =make install=) is the Claude adapter. Other agents get their own thin adapter when wanted (deferred — see [[*Open decisions][Open decisions]]). - *Operations* — a small =ai-kb= CLI (shell, calling =emacs --batch= for org-lint/index work) is the canonical surface, so humans and every agent share one contract: - =ai-kb doctor= — repo present, remote reachable + private, branch state, org-roam db buildable, required tools installed, adapter linked, no obvious secrets. - =ai-kb index= — regenerate =index.org= from node properties. - =ai-kb query <context>= — read the index, return relevant nodes. It is the surface adapters call before spending context on full nodes, so it has a *testable contract* even though v1 retrieval is plain lexical: default output is plain text (one node per line), with =--json= for tests and tools; fields are title, ID, summary, projects, status, updated, path; it searches index rows + title/tags/properties/body; a default max-result count and ordering (most-recently-updated first); =raw/= paths appear only as source references, never as primary results; exit codes distinguish no-match, invalid/missing KB, and a lint/index failure. - =ai-kb remember= — the write protocol above (fetch/ff, write, regenerate index, full lint gate, commit; push is the timer's job; under =flock=). - =ai-kb lint= — org-lint fatal checks, duplicate ids, broken id-links (excl =raw/=), missing required properties, bad project slugs, stale/incomplete index, credential scan of nodes and =raw/=. This is what =remember= runs before commit and what curation runs as a sweep. - =ai-kb curate --dry-run= — report duplicates, orphans, contested/superseded nodes, raw captures with no compiled node, nodes untouched past a horizon. - =ai-kb sync= — =org-roam-db-sync= against ai-kb (Emacs-side helper). - *Admin split:* destructive operations — merge nodes, delete a node or raw capture, rewrite backlinks, mark superseded — are *human-confirmed only*, never automatic. - *Capability levels* (named so adapters know their lane): =file-only= (read/grep/template-write), =cli= (call =ai-kb=), =mcp= and =semantic= are vNext. Claude v1 uses =cli= with the rule adapter; until the CLI exists, =file-only= following the contract template is the bootstrap path. * The Emacs switch: guard contract =org-roam-db-autosync-mode= is on, and a global =org-after-todo-state-change-hook= (=cj/org-roam-copy-todo-to-today=) copies completed tasks into the *active* roam's daily. Naive rebinding means a task completion or capture while switched lands in the wrong roam. - *On entry* (=cj/org-roam-switch-to-ai-kb=): rebind =org-roam-directory= + =org-roam-db-location=; *rescope or disable* the completed-task→daily hook; =org-roam-db-sync=; surface the active KB in the modeline/echo. - *On exit* (=cj/org-roam-switch-to-personal=): restore both variables *exactly* and restore the hook. - *Abnormal exit:* if Emacs is killed while switched, on-exit never runs. The config re-asserts personal-roam state at startup (or detects a stale switched state), so a crash can't leave the completed-task hook rescoped into ai-kb. - Tests assert the completed-task hook does not fire into ai-kb while switched. * Maintenance and curation The proactive-write bar controls intake; nothing controls rot, and the system creates memories unprompted, so a minimal maintenance loop is v1 (read-only commands; destructive execution human-gated): - =ai-kb doctor= / =ai-kb lint= — health and validity (above). - =ai-kb curate --dry-run= surfaces four buckets — duplicates to merge, stale/superseded nodes, orphans (no back- or forward-links), over-broad nodes to split. Craig decides; the agent executes *human-confirmed* merges/splits, repointing =[[id:]]= backlinks (grep + rewrite) and re-linting. A =:LAST_CURATED:= stamp rotates the pass through least-recently-touched nodes. - *Trigger (node-count):* curation is "due" when roughly N nodes have been added or gone untouched since the last =:LAST_CURATED:=; =ai-kb doctor= and the session-startup surface emit a one-line nudge when due (mirroring the existing task-review habit). The interactive pass itself is a global workflow at =~/code/rulesets/.ai/workflows/ai-kb-curate.org=, available from every project's session. - *Pointer integrity:* external pointers are ID-first, so a rename is safe; but a merge or supersede *changes the canonical ID*, so before merging/deleting, grep for inbound references (other nodes' =[[id:]]= and per-project =MEMORY.md= =ai-kb: ... (UUID)= pointers) and repoint the old ID to the new. * Security and privacy ai-kb lives in a *private* repo (cjennings.net only, no public mirror), removing the main leak surface. v1 rule: *private but not a secret store* — no credentials/tokens/keys in nodes or =raw/=; =ai-kb lint= scans both for common credential patterns before commit and *fails* on a hit (secrets move to a secure reference, not ai-kb). =:VISIBILITY:= is two-valued (=personal= / =work-private=) in v1; the full =public|work-private|secret= taxonomy and a public/private split are vNext, for when sharing or publishing a subset is real. * Provisioning The pieces span the rulesets repo, this repo, and the ai-kb repo. =make ai-kb-init= (wrapping =scripts/setup-ai-kb.sh=) is idempotent. *One-time server bootstrap* (distinct from the per-machine clone, and not doable by the local script): =sudo git init --bare /var/git/ai-kb.git && chown= on cjennings.net, plus the github-mirror hook left *off* for this repo. Per-machine, ordered: 1. Clone =git@cjennings.net:ai-kb.git= to =~/.local/share/ai-kb= (or =git init= + add remote on the very first machine). 2. =make ai-kb-init=: seed =index.org= + a README/index node with a generated =:ID:=; install the =ai-kb= CLI onto =PATH=; =ai-kb index=; install and =systemctl --user enable --now= the =ai-kb-push.timer= + =.service= units (the debounced background push); best-effort =ai-kb sync= if an Emacs server is up. 3. =cd ~/code/rulesets && make install= — symlinks the =claude-rules/ai-kb.md= adapter into =~/.claude/rules/= (and syncs the =ai-kb-curate.org= workflow into projects via the usual startup rsync). 4. =ai-kb doctor= to confirm the machine is wired correctly (repo, remote, CLI on PATH, push timer active, adapter linked, db buildable, no secrets). * Build plan Step 1 splits into two slices by dependency — =remember= needs =index= + =lint=, and the adapter needs =remember=, so the safe write path (1a) lands first and the read/maintenance/timer pieces (1b) follow. Same scope, cleaner sequencing. *** Step 1a — the safe write path (minimum usable) - The =ai-kb= git repo (bare on cjennings.net + clone at the XDG path), seed =index.org=, =AGENT_CONTRACT.org=. - =ai-kb index= (regenerate from properties), =ai-kb lint= (the full check set + org-lint fatal gate + credential scan), =ai-kb remember= (write protocol: fetch/ff, write, regen index, full-lint gate, commit, =flock=), =ai-kb doctor= (health + push-state report). - =claude-rules/ai-kb.md= adapter (points at the contract; routing + proactive + contradiction rules + concrete L1 triggers + "use =ai-kb remember=, never bypass =ai-kb lint="); =make install= links it. - =scripts/setup-ai-kb.sh= + =make ai-kb-init=; the one-time server bootstrap documented. After 1a the agent can remember, lint, and check health — the safe write path exists. *** Step 1b — retrieval, maintenance, push - =ai-kb query= (the testable retrieval contract above) and ranking polish. - =ai-kb curate --dry-run= and =ai-kb sync=. - =ai-kb-push.timer= + =ai-kb-push.service= =systemd --user= units (debounced background push) installed and enabled by =setup-ai-kb.sh=, plus the push-failure log + =doctor=/startup surfacing. - =~/code/rulesets/.ai/workflows/ai-kb-curate.org= — the human-gated curation workflow, surfaced when the node-count trigger makes it due. ** Step 2 — Emacs browsing layer In =org-roam-config.el=: ai-kb dir constant + =org-roam-ai.db=; =cj/org-roam-switch-to-ai-kb= / =…-to-personal= with the guard contract (incl. abnormal-exit re-assert); =cj/ai-kb-db-sync=; =C-c n= keybindings (e.g. =C-c n a= / =C-c n A=, avoiding the dense existing set); which-key labels; ERT tests + =/review-code=. ** Step 3 and the LLM-Wiki layer — deferred Separate specs. See [[*vNext][vNext]]. * Test strategy - *CLI / write path:* a write with the remote unreachable still commits locally and does *not* error the agent (push deferred); =flock= serializes concurrent =remember=; each fatal org-lint check (malformed drawer, missing/dup =:ID:=, invalid required property, missing =#+title:=, unparseable org) rejects the commit while a style warning does not; and — the safety boundary — =remember= aborts the commit when the full =ai-kb lint= fails (stale index, broken link, leaked secret in =raw/=), not only on node org-lint. - *Index:* regeneration from a fixture KB produces the expected entries; a node added out-of-band appears only after regeneration (proves no drift); =lint --index= flags a missing/stale entry. - *query contract:* =ai-kb query --json= returns the specified fields, ordering, and exit codes on a fixture KB; =raw/= paths appear only as source references. - *Push observability:* a simulated push failure is recorded to the state file and surfaced by =ai-kb doctor= ("ahead"/"push failed"). - *Link recipes* (fixture KB): backlink-by-grep (excluding =raw/=) and forward-link-by-grep return correct sets. - *Step 2 ERT:* switch sets the ai-kb dir+db; switch-back restores personal exactly; the completed-task hook does not fire into ai-kb while switched; startup re-asserts personal state. - *Provisioning* (bats): =setup-ai-kb.sh= idempotent; seeds a node with a valid =:ID:=; =doctor= passes on a freshly-provisioned repo. * Scaling path (planned, not built) - v1: =rg= over org files + a generated =index.org=. - v1.5: =ai-kb query= grows richer ranking over title/tags/properties/body. - vNext: a local BM25/vector tool (=qmd= or similar) over the nodes, preserving links; no embeddings in v1. * Review dispositions Everything not listed was accepted as written and woven in. Listed: modified, rejected, or owner-deferred recommendations, with reasons. - *Review 2 core reframe → MODIFIED (scope).* v1 is the memory store, not a full LLM Wiki; per Review 2's own off-ramp and Craig's stated intent. - *Review 2 #1 (raw/wiki/schema) → PARTIALLY ADOPTED.* =raw/= for external sources only; compiled =wiki/= + =schema.org= stay vNext (most memories have no external source). - *Review 2 #2 (ingest/query/lint) → MODIFIED.* query = index + =rg= (now =ai-kb query=); lint = =ai-kb lint= + curation; org-lint is the write-time validity gate; the heavy ingest pipeline → vNext. - *Review 2 #3 (provenance + hashes + numeric confidence) → MODIFIED to provenance-lite,* reconciled with Review 3: adopted =:CREATED_BY:/:CONFIDENCE:(provenance)/:VISIBILITY:/:SOURCE:/:STATUS:=; dropped source *hashes* and numeric confidence scoring (raw-corpus grounding machinery → vNext). - *Review 2 #8 (exclude =raw/= from scan) → ADOPTED.* - *Review 2 #10 (full visibility taxonomy + lint) → MODIFIED:* v1 = private repo + no-secrets rule + credential lint; four-level taxonomy → vNext. - *Review 3 #1 (agent-neutral contract + CLI) → ADOPTED (contract + CLI); cross-agent ADAPTERS deferred to vNext (Craig, 2026-05-24).* The contract lives in the repo and a minimal CLI is the operation surface — justified on Claude-only correctness (atomic safe writes), with neutrality as cheap future-proofing. Codex/Ollama adapters + MCP wait until cross-agent is actually adopted. - *Review 3 capability levels =mcp=/=semantic= → DEFERRED.* vNext. - *Review 4 #1 (push-failure contract) → ADOPTED,* and strengthened to debounced best-effort push (commit always; push never blocks/fails the agent) — directly informed by the gpg-agent SSH failure observed this session. - *Review 4 #2 (index regeneration) → ADOPTED:* generated by =ai-kb index=, never hand-maintained. - *Storage location → Option 1 (emacs home) REJECTED* (public mirror leaks); *XDG dedicated private repo ADOPTED;* Syncthing dropped. - *Curation full workflow → kept v1-minimal:* read-only =curate --dry-run= ships v1; the interactive merge/split flow is human-gated. - *Review 5 (all six) → ACCEPTED.* #1 (the only blocker): =remember= runs the *full* =ai-kb lint= — index freshness, dup IDs, broken links, secret scan — before commit, not just node org-lint. #2: an explicit org-lint fatal-check list (tests target it). #3: push failures are observable (state-file log + =doctor= + startup nudge). #4: =ai-kb query= gets a testable contract (text/=--json=, fixed fields, ordering, exit codes). #5: Step 1 split into 1a (safe write path) / 1b (query/curate/sync/timer/workflow). #6: durable pointers are ID-first (=ai-kb: <Title> (<UUID>)=), not filename-first. Nothing rejected — all six were sound hardening. * Agreed decisions - Building from the rulesets session is sanctioned cross-project work (Craig, 2026-05-24). - ai-kb is intentionally global; the one sanctioned exception to =cross-project.md=. - Scope: memory store v1; LLM Wiki deferred. - Storage: dedicated private git repo, XDG path, no Syncthing. - Write path: commit always, push best-effort/non-blocking/debounced; safe-fetch before; =flock=. - Operations are an agent-neutral contract fronted by a minimal =ai-kb= CLI; destructive ops human-only. - Cross-agent is not a near-term goal (Craig, 2026-05-24): v1 ships the Claude adapter; other-agent adapters + MCP are deferred to vNext. The contract stays neutral in shape so they are additive later. - *Resolved 2026-05-24:* store path = =~/.local/share/ai-kb= (XDG); CLI = a shell wrapper calling =emacs --batch= for the org-lint/sync steps; push = a background =systemd --user= timer (~15 min, push only if ahead), commits always local; curation = node-count trigger surfaced by =ai-kb doctor= + startup, workflow at =~/code/rulesets/.ai/workflows/ai-kb-curate.org=. * Open decisions None — all four resolved 2026-05-24 (Craig). See [[*Agreed decisions][Agreed decisions]]. The spec is fully decided and buildable. * vNext Each is valuable but out of v1 scope; the v1 bar is token-efficient, safe, and fully recoverable. Reasons given so a future reader need not re-litigate. - *Step 3 — migrate =.ai/sessions/= + workflows into ai-kb.* Its own spec. *Why not v1:* moving working systems is a migration with its own tradeoffs; prove ai-kb first. - *Other-agent adapters (Codex, Ollama) + MCP server.* *Why not v1:* cross-agent is not a near-term goal (Craig, 2026-05-24). The contract is already repo-resident and neutral in shape, so adapters are purely additive when a second agent is actually adopted. Ollama specifically will need a host wrapper (run =ai-kb query= before the turn; =remember --confirm= human-gated) since a model runtime won't curate on its own. - *Compiled =wiki/= layer + =schema.org=, source hashes, numeric confidence.* *Why not v1:* pay off only with a substantial external-source corpus to compile and drift-check; v1 captures sources selectively under =raw/= already. - *Formal ingest pipeline.* *Why not v1:* the external-corpus workflow that triggers the wiki layer; premature without it. - *Semantic / embedding retrieval, =qmd=.* *Why not v1:* find-by-meaning pays off above ~hundreds of nodes; =rg= + index is faster and dependency-free below that. - *Event-sourced JSONL catalog + SQLite projection; typed-link graph traversal + content-addressed spans.* *Why not v1:* Nexus-scale infrastructure; org-roam's db + grep cover v1, and clean links/properties now let this be built later without rewriting nodes. - *Plan library / operator-DAG execution* (AgenticScholar, Plan*RAG). *Why not v1:* the near-term lesson is only "don't hide retrieval procedure in prose" — met by the =ai-kb query= contract; multi-hop planning waits. - *=log.org= op-log.* *Why not v1:* git history already records every write; add later if the git log is too coarse. - *Full =:VISIBILITY:= taxonomy + public/private split.* *Why not v1:* the private repo + no-secrets rule cover the floor. - *Full agentic-knowledgebase vision* (project hubs; person/decision/thread/meeting/problem/runbook types; =cj/agent-*= commands). *Why not v1:* a much larger product; ai-kb is its first slice. - *Live dual-roam browsing* (no switch). *Why not v1:* org-roam supports one active db per session today. * Relationship to existing mechanisms - *Per-project claude memory (T2)* — stays the session-recall layer; shrinks to an index pointing into ai-kb (T3) for significant items. - *.ai/notes.org and .ai/sessions/* — unchanged in v1 (migration is deferred Step 3). - *Personal org-roam (recipes, etc.)* — never touched; reached by switching. - *agentic-knowledgebase.org* — the broader vision; ai-kb is its first concrete slice.