Seven repositories build one thing. A knowledge graph that lives as Markdown in Git, that many agents write concurrently without colliding, and that any single agent can read a small, ranked slice of. This page explains how, and links 16 validated diagrams and 33 interactive playgrounds.
Three cross-cutting explorers. Per-plugin pages are further down. Each playground is a single HTML file with no external dependencies. Adjust the controls, watch the preview, then copy the generated prompt back into Claude.
One concept is one Markdown file. Nothing else is durable.
The YAML frontmatter is the envelope. The Markdown body is free-form prose that a human reads
without tooling. BaseConcept in okf-plugin requires exactly two
fields, type and title, and it keeps
additionalProperties: true forever on v1. Old files must produce zero errors.
---
type: Feature
title: User authentication
verified: false
truth_state: current
links:
- target: /decisions/use-jwt-for-session.md
rel: designed_by
- target: /acceptance/session-expires-within-15-minutes.md
rel: verified_by
---
# User authentication
Shaped by [Use JWT for session management](/decisions/use-jwt-for-session.md).
A directory is a catalog. Its index.md is a typed Catalog concept,
and a post-edit hook regenerates it. Treat catalogs as derived, not authored, and merge
conflicts stay rare.
Everything above Git is an accelerator you may delete. The SQLite index lives at
<bundle>/.dekc/index.sqlite, it is gitignored, and deleting it is always
valid recovery.
A body Markdown link is the universal edge. A rel in frontmatter types
that same target.
Both forms point at the same file, so a human reading the prose and an agent walking the graph
see the same structure. An unknown rel is allowed and reported as information,
never an error.
Direction is a claim, and it does not reverse. A
DecisionRecord mitigates a Risk. A risk mitigates nothing. The
capture script therefore writes the mitigates edge on the decision, not on the
risk. Because pack() reads inbound edges as well as outbound ones, you write an
inverse edge only when the source genuinely asserts it.
Three rungs. Each attacks a different cost, and each keeps the rung below it as a runtime fallback.
def retrieve(bundle, query):
if index_ok(bundle): # rung 2: SQLite FTS5, incremental
return from_index(bundle, query)
if find_rg(): # rung 1: ripgrep prefilter
return from_rg(bundle, query)
return from_scan(bundle, query) # rung 0: pure Python scan
| Rung | Cost it attacks | Why it is safe |
|---|---|---|
| 2. SQLite FTS5 | Re-parsing files that did not change since the last invocation. | Every reader stats the tree and compares mtime+size itself, so the index
self-heals after a hand edit, a git checkout, a branch switch, or a
disabled hook. |
| 1. ripgrep | Reading and lowercasing files that cannot possibly match. | It only decides which files get read. Over-selection is harmless because the Python scorer re-checks, and it cannot under-select for plain substring terms. |
| 0. Python scan | Nothing. It is the correctness baseline. | Always available. A missing rg is not an error. |
Scores stay identical across rungs by design. The default engine uses the
index to pick candidates and the same Python scorer to rank them
(title x10, description x5, tags x4, min(body, 8)). Only the opt-in
--engine fts switches to FTS5 bm25(), which is a different function.
The ladder does not help everything. Validation, the curate hook, orphan listings, and the Mermaid graph builder must parse frontmatter and resolve links, so they still walk the tree.
An agent cannot read a whole second brain. A ContextPack is the smallest subgraph that is still useful, and it is deliberately lossy.
Catalog links to every child, so it is a
hub. Walking it undirected dumps the whole bundle into context. Outbound from a concept
stays inside one theme.impact, not pack.## Excluded (available on request), so the model asks for a
named follow-up instead of guessing.x-impact: high types, then title.SECOND_BRAIN_WINDOW_TOKENS. An over-budget pack refuses to write rather than
truncating silently, and neighbor bodies are omitted unless the node is the root.| Optimization | What it buys |
|---|---|
| SQLite FTS5 index | Steady-state queries in single-digit milliseconds. One stdlib file, atomic transactions, concurrent readers, and no pip dependency. |
| Incremental refresh | Only changed files are re-parsed. Because every reader does the sweep itself, the index never goes stale behind your back. |
| ripgrep prefilter | An order of magnitude on large trees with no state on disk, so there is no cache-staleness class of bugs. |
| Outbound-only BFS | Hub catalogs stop flooding packs. This is the single largest read-path win. |
| Bodies off for neighbors | A 20-node pack costs roughly one body plus 19 cards instead of 20 bodies. |
| Fail-closed budget | You get an error you can act on instead of a silently truncated pack. |
| Narrow auto-context hook | pkc_auto_context.py injects a tiny 1-hop, 8-node pack only when a prompt
names a features/ path that exists or a ULID that resolves to a Feature.
Silence is the default, because an unwanted injection is worse than none. |
| Edge origin tracking | The index stores which file authored each edge, so incremental deletes do not leak orphan edges. |
| Claim identity hash | RKC computes claim_key = sha256(normalize(text)|claim_kind|subject_id), so
re-ingesting a source attaches evidence instead of duplicating claims. |
| Bulk ingest index | RKC looks up research/catalogs/ingest-index.json rather than scanning the
whole tree. |
Read main. Write brain/<actor>/<session-id>.
Close to a pull request.
read -> origin/main (shared truth) + optional session overlay
write -> brain/<actor>/<session-id> worktree only
close -> commit, push, open PR
merge -> a human, or green auto-merge on non-overlapping paths
Why not a lock on main. A file lock serializes writers on one machine. It fails across machines, across long thinking sessions, and for cloud bots. A worktree plus a pull request is the protocol that survives all three.
Three further rules keep concurrent writers apart:
Catalog and
ContextPack. An agent never writes a type it does not own and never invents a
rel.registry.json lists which catalogs each
plugin may rewrite. Foreign catalogs are read-only.Package,
Dashboard, DataLake, GlossaryTerm, and
RateLimit exist in more than one plugin and are not the same noun. SAC
Package is a build unit. PKC Package is what shipped.A conflict is information. OKF stores one concept per path, so two agents editing the same Feature file will conflict. That is correct. Prefer creating new nodes over editing shared ones, and let a human resolve the meaning.
Unknown types have a matching rule. An unknown type falls back to
BaseConcept so a reader can still parse the envelope, and
validate --strict rejects it. The fallback is a read affordance, never a write
authorization.
| Repository | Question it answers | Diagrams |
|---|---|---|
| okf-plugin | How do I read a slice of this graph, and what breaks if I change something? | engine · pack |
| project-knowledge-capture | Why did we do it this way? | components · typed edges |
| system-architecture-capture | What is actually running, and who owns it? | scanners · reverse engineering |
| data-engineering-knowledge-capture | Where does this number come from, and what does it mean? | medallion · judge loop |
| okf-agent-graph | How is this multi-agent loop configured and bounded? | four planes · loop |
| research-knowledge-capture | What do we claim, and what is the evidence? | ingest · spine pack |
| second-brain-marketplace | How does a host install all of this? | install topology |
Because the two obvious alternatives each fail at something the other does well, and Markdown in Git fails at neither.
| Alternative | Where it breaks |
|---|---|
| A vector store | It answers "what is similar to this?" It cannot answer "what breaks if I change this?" Blast radius needs typed, directed edges and transitive closure, not cosine similarity. |
| A graph database | It answers the traversal question well, and then you cannot review a change in a pull request, diff two versions, read a node without a client, or work offline. You have also added a service to operate. |
| A wiki product | Humans can read it and agents cannot bound it. There is no hop cap, no node cap, and no token budget, so an agent either reads one page or drowns. |
| Dumping the repo into context | It does not fit, it costs the same every turn, and it gives the model no signal about which nodes are trustworthy or dangerous. |
Markdown plus YAML in Git gives you review, history, diff, blame, branches, offline reading, and grep for free, because they are Git's features and not features you built. The graph engine adds exactly three things on top: conformance, blast radius, and a bounded read.
The wiki part matters as much as the graph part. A human writes the body prose and reviews the pull request. An agent writes the frontmatter through a script and reads the pack. Both work on the same file, so institutional memory does not fork into a human copy and a machine copy.
Portability is the last argument. The same tree loads in Claude Code, Grok Build, Codex, Cursor, OpenCode, Agent Plugins 1.0, Grok Bot, and LangChain Deep Agents. No host owns your memory, and no vendor can take it away.
Five interactive pages per plugin, generated from the real trees.
Every page reads one JSON fact file that gen/extract.py pulled from the
repositories: the concept types and their x-impact tiers, the catalogs the
plugin may rewrite, the relation directions its docs declare and the type-to-type edges its sample
bundle actually exercises, its scripts, skills, agents,
and hooks, and the full text of every SKILL.md and agent file. Regenerate them
after any change with two commands.
python3 gen/extract.py # repositories -> gen/data/*.json
python3 gen/render.py # gen/data/*.json -> playgrounds/*.html
Graph engine. Owns Catalog and ContextPack.
3 nouns · 0 declared directions · 5 observed edges · 14 sample concepts · 8 skill and agent files
Project memory. Why it was built this way.
16 nouns · 31 declared directions · 40 observed edges · 16 sample concepts · 24 skill and agent files
Runtime topology. What is actually running.
139 nouns · 0 declared directions · 90 observed edges · 82 sample concepts · 24 skill and agent files
Data plane. Lineage, layers, semantics.
29 nouns · 58 declared directions · 65 observed edges · 82 sample concepts · 32 skill and agent files
Multi-agent loop graphs as OKF.
51 nouns · 0 declared directions · 17 observed edges · 16 sample concepts · 10 skill and agent files
Research claims and their evidence.
8 nouns · 0 declared directions · 8 observed edges · 11 sample concepts · 6 skill and agent files