CodeDocs Vault

Architecture

OpenKnowledge is a Bun + Turbo monorepo of six packages plus a docs site. The spine that ties them together is a single idea: one markdown document is, at the same time, a file on disk, a CRDT in memory, a git history, and an MCP resource. Every package is a different view onto that one object.


1. The one-object model

        ┌─────────────────────────────────────────────────────────┐
        │                  one knowledge document                  │
        ├───────────────┬───────────────┬──────────────┬──────────┤
        │  file on disk │  CRDT in RAM   │  git history │  MCP res. │
        │  notes/x.md   │  Y.Doc         │  refs/wip/…  │  exec/edit│
        └───────┬───────┴───────┬───────┴──────┬───────┴────┬─────┘
                │               │              │            │
         external-change   Hocuspocus     shadow-repo   server/mcp
         (disk watcher)    (y-websocket)  (simple-git)  (tool handlers)

The four representations are kept in sync by four subsystems, all living in packages/server:

Because the markdown source itself is a CRDT field, agents and humans editing the same file at the same time merge automatically — no lock, no "AI suggestion" side-channel. That seam is the subject of 06_collaboration_crdt.md.


2. The document schema is pinned

The editor's capabilities (which ProseMirror nodes/marks/attributes exist) are captured in a schema snapshot dumped by packages/core/scripts/dump-schema.ts:71-119 from @tiptap/core plus the active MDAST plugins. A CI check (scripts/check-schema-snapshot-clean.sh) fails the build if the schema drifts without an intentional update.

Why this matters: the markdown ↔ rich-text bridge is lossy if the two sides disagree about what a node is. Pinning the schema means a .md written by an old client and re-opened by a new one round-trips deterministically — a prerequisite for letting agents and humans on different app versions co-edit.


3. Process topology

OpenKnowledge runs as a small constellation of processes, not one server:

  ok start
    ├── collaboration server  (HTTP + Hocuspocus WS on :api-port)   packages/server
    │     ├── persistence extension      → git shadow repo
    │     ├── liveDerivedIndex extension → backlink / tag indexes
    │     ├── principalAuth extension    → token + branch validation
    │     ├── cc1Broadcaster extension   → push file/graph/tag changes
    │     └── serverObserver extension   → agent/human presence
    ├── ok ui  (static web editor on :39847, detached child)        packages/cli/commands/ui.ts
    └── ok mcp (stdio MCP server, one per connected agent)          packages/cli/mcp/server.ts

The Hocuspocus extension stack (server-factory.ts:545-699) is the clean part of the design: persistence, derived indexes, auth, broadcast, and presence are five orthogonal extensions over one document stream, not five tangled code paths.


4. Entry points

Entry File What it starts
ok CLI packages/cli/src/cli.ts (Commander, ~23 commands at :65-168) everything below
ok init packages/cli/src/commands/init.ts:587 (runInit) scaffold .ok/, wire harnesses, install skills
ok start packages/cli/src/commands/start.ts:560 collab server + UI
ok mcp packages/cli/src/commands/mcp.ts:14 stdio MCP server for an agent
Desktop app packages/desktop/src/main/index.ts (Electron main) windows, terminal, keyring, deep links
Web editor packages/app (React + TipTap) the WYSIWYG surface

5. Data-flow: an agent writes a doc

  1. Agent (in Claude Code) calls MCP tool write { path, content } on its stdio ok mcp process.
  2. The tool handler (packages/server/src/mcp/tools/) connects to the collab server and applies the change to the document's Y.Text('source') / Y.XmlFragment('default') via @tiptap/y-tiptap (persistence.ts:25).
  3. Hocuspocus broadcasts the Yjs update to every other client — the human's open editor renders the agent's edit live, with the agent's avatar in the presence bar.
  4. After a debounce of quiescence, persistence builds one git tree and writes one commit per active writer onto refs/wip/main/{writerId} in the shadow repo, footers carrying the agent's identity (persistence.ts:350-437, shadow-repo.ts:227-323).
  5. If GitHub sync is on, those commits are pushed to the remote; conflicts freeze the affected docs for humans and agents (docs/content/features/github-sync.mdx).

Every later doc expands one of these five steps.