# https://github.com/inkeep/open-knowledge Project Manual

Generated at: 2026-06-25 19:33:09 UTC

## Table of Contents

- [Overview & Monorepo Architecture](#page-overview)
- [Editor, Frontend Components & Integrated Terminal](#page-editor-frontend)
- [Server, Persistence, Shadow Repo & Sync](#page-server-sync)
- [CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)](#page-agent-handoff)

<a id='page-overview'></a>

## Overview & Monorepo Architecture

### Related Pages

Related topics: [Editor, Frontend Components & Integrated Terminal](#page-editor-frontend), [Server, Persistence, Shadow Repo & Sync](#page-server-sync), [CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)](#page-agent-handoff)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md)
- [package.json](https://github.com/inkeep/open-knowledge/blob/main/package.json)
- [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json)
- [packages/app/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/app/package.json)
- [packages/core/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/core/package.json)
- [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json)
- [packages/cli/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/cli/package.json)
- [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts)
- [biome-plugins/README.md](https://github.com/inkeep/open-knowledge/blob/main/biome-plugins/README.md)
</details>

# Overview & Monorepo Architecture

## Project Purpose & Scope

OpenKnowledge is a local-first markdown editor and LLM-powered wiki with first-class integrations for Claude Code, Codex, and Cursor. It provides a WYSIWYG editing experience that "feels like editing a Google Doc or Notion page," while keeping the underlying storage as plain markdown in a git repository so that team-based sharing and auto-sync are powered by git itself. Source: [README.md:3-9](README.md).

The editor is distributed as:

- A **macOS desktop app** packaged as a DMG, and
- A **local web app** for Linux and Intel Macs, served by a Node.js 24+ CLI named `ok`.

Source: [README.md:11-23](README.md).

The project emphasizes being **local-first**: edits round-trip through a Y.js document shared via Hocuspocus, with markdown round-tripped through the `core` package for serialization and parsing. Source: [packages/app/src/server/agent-flow.test.ts:7-37](packages/app/src/server/agent-flow.test.ts).

## Monorepo Layout

The repository is a Bun workspace monorepo. The root `package.json` declares two workspace globs and pins Bun 1.3.13 plus Node 24 as the package manager and engine, respectively. Source: [package.json:1-16](package.json).

| Path | Package name | Role | Key dependency / entry |
|---|---|---|---|
| `packages/core` | `@inkeep/open-knowledge-core` | Markdown ⇄ ProseMirror serialization, Y.js integration, shadow-repo layout, schema, helper bundle | Tiptap 3.22.3, unified/remark/rehype, yjs, Orama (search). Source: [packages/core/package.json:1-58](packages/core/package.json) |
| `packages/server` | `@inkeep/open-knowledge-server` | Hocuspocus collaboration server + MCP SDK for agents | `@hocuspocus/server` 4.0.0-rc.1, `@modelcontextprotocol/sdk`. Source: [packages/server/package.json:1-26](packages/server/package.json) |
| `packages/app` | `@inkeep/open-knowledge-app` | Electron + Vite frontend (Tiptap editor, presence, terminal) | Tiptap, Vite 8, Biome, Lingui. Source: [packages/app/package.json:1-50](packages/app/package.json) |
| `packages/cli` | `@inkeep/open-knowledge` | Published CLI `ok` / `open-knowledge` (init + start) | Bundles app + server + core; `engines.node: ">=24"`. Source: [packages/cli/package.json:1-42](packages/cli/package.json) |
| `docs` | (workspace) | Markdown/MDX documentation site | Declared as a workspace in root. Source: [package.json:8-10](package.json) |

`packages/core` exposes several entry points (`./`, `./shadow-repo-layout`, `./server`, `./keepalive`, `./helper-bundle`) so that the server, the CLI, and the Electron preload can each import only what they need, while sharing one TypeScript source tree. Source: [packages/core/package.json:9-32](packages/core/package.json).

## Build & Test Orchestration

Task orchestration is handled by **Turbo**. The `turbo.json` defines per-task inputs so that Turbo can cache results based on which source files changed. Examples:

- `test:integration` declares inputs across `src/`, `tests/`, `../server/src/**`, `../core/src/**`, the workspace `biome.jsonc`, and `../../biome-plugins/**` — meaning a change to any lint plugin invalidates every app integration test cache entry. Source: [turbo.json:1-60](turbo.json).
- `test:conversion` scopes to `src/editor/**`, conversion/integration tests, and the `core` + `server` packages.
- `test:dom`, `test:e2e`, `test:visual`, and `test:a11y` are deliberately `cache: false`, because their results depend on a real browser/Electron runtime.

The CLI ships as an aggregated artifact. `packages/cli` copies `packages/app/dist` into `dist/public` and bundles the server's skill assets so a single `npm install -g @inkeep/open-knowledge` delivers a runnable editor. Source: [packages/cli/package.json:33-42](packages/cli/package.json).

## Cross-Package Data Flow

At runtime, the data path for a single user keystroke is: **Editor (Tiptap/ProseMirror) → Y.Doc (Hocuspocus) → MarkdownManager (core) → files on disk**. Agents reverse the flow via MCP: they receive a Y.Doc view, mutate the `default` `XmlFragment` or the `source` `Y.Text`, and the changes propagate back through the editor. Source: [packages/app/src/server/agent-flow.test.ts:17-55](packages/app/src/server/agent-flow.test.ts).

```mermaid
flowchart LR
  UI[Tiptap Editor<br/>packages/app] -- "Y.js deltas" --> HOCUS[Hocuspocus<br/>packages/server]
  HOCUS -- "Y.Doc events" --> CORE[MarkdownManager<br/>packages/core]
  CORE -- "round-trip markdown" --> FS[(Project files on disk<br/>git-backed)]
  AGENT[Claude / Codex / Cursor<br/>via MCP] -- "Y.Doc writes" --> HOCUS
  CLI[ok CLI<br/>packages/cli] -- "serves app + server" --> UI
```

The integration test `packages/app/src/server/agent-flow.test.ts` codifies the contract: after an agent writes through a `Hocuspocus.openDirectConnection`, the resulting `XmlFragment` must contain the expected paragraphs **and** serialize through `MarkdownManager` to markdown that contains the agent's text. Source: [packages/app/src/server/agent-flow.test.ts:19-37](packages/app/src/server/agent-flow.test.ts). A second case verifies the markdown source-mode path: the agent appends raw markdown to a `Y.Text('source')` channel, and the editor preserves both the original paragraph and the injected content. Source: [packages/app/src/server/agent-flow.test.ts:39-75](packages/app/src/server/agent-flow.test.ts).

## Tooling & Conventions

The monorepo pins runtime versions (`.bun-version` and `.node-version`) and uses Biome for linting/formatting plus a set of **custom GritQL plugins** under `biome-plugins/`. These plugins encode project-specific conventions — for example `microcopy-ellipsis` reserves `…` for native macOS menus and truncation indicators, while `no-unportaled-editor-content` enforces that `<EditorContent />` is always rendered through a React portal. Source: [biome-plugins/README.md:30-80](biome-plugins/README.md). Tests for these plugins live in `packages/app/tests/integration/`, and the `test:integration` Turbo inputs explicitly include `../../biome-plugins/**` so plugin changes re-run the plugin tests. Source: [turbo.json:13-22](turbo.json).

The v0.18.1-beta.3 release notes (community context) describe a small UX change to the integrated terminal — its default height now computes as about one third of the window height on first use rather than a hard-coded 240 px. This sits squarely in the `packages/app` Electron shell and illustrates the kind of user-facing polish the monorepo enables: a single package change shipped through the same `ok` CLI distribution pipeline. Source: [package.json:18-30](package.json), [packages/cli/package.json:21-31](packages/cli/package.json).

## See Also

- [Editor & Yjs Collaboration](editor-and-collaboration.md)
- [Agent / MCP Integration](agent-mcp-integration.md)
- [CLI Distribution & Build Pipeline](cli-and-build.md)
- [Biome Plugins & Lint Conventions](biome-plugins.md)

---

<a id='page-editor-frontend'></a>

## Editor, Frontend Components & Integrated Terminal

### Related Pages

Related topics: [Overview & Monorepo Architecture](#page-overview), [Server, Persistence, Shadow Repo & Sync](#page-server-sync), [CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)](#page-agent-handoff)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md)
- [packages/app/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/app/package.json)
- [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts)
- [packages/app/src/server/agent-sim.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-sim.ts)
- [packages/core/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/core/package.json)
- [packages/cli/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/cli/package.json)
- [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json)
- [biome-plugins/README.md](https://github.com/inkeep/open-knowledge/blob/main/biome-plugins/README.md)
- [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json)
</details>

# Editor, Frontend Components & Integrated Terminal

OpenKnowledge is a local-first markdown editor and LLM wiki that pairs a WYSIWYG Tiptap-based editing surface with an integrated terminal for running project tooling alongside the document. This page covers the frontend component architecture, the editor's collaborative write model, and the integrated terminal's behavior and recent changes. Source: [README.md:1-3]()

## Project Layout and Package Roles

The repository is a Bun/Turborepo monorepo with four primary workspace packages that together compose the editor experience:

| Package | Role | Public Binaries |
| --- | --- | --- |
| `@inkeep/open-knowledge-app` | Vite-built frontend (Tiptap editor, UI components, terminal panel) | — |
| `@inkeep/open-knowledge-core` | Markdown ↔ ProseMirror serialization, Yjs binding, Orama search, schema definitions | — |
| `@inkeep/open-knowledge-server` | Hocuspocus collaboration server, MCP SDK, OpenTelemetry traces/metrics | — |
| `@inkeep/open-knowledge` (CLI) | `ok init` / `ok start --open` for Linux/Intel-Mac local-web workflow | `open-knowledge`, `ok` |

The CLI's `build:app` script copies `packages/app/dist` into `dist/public`, so the npm-published CLI ships the prebuilt editor assets inside the binary. Source: [packages/cli/package.json:32-42]()

## Tiptap Editor and the Yjs Collaborative Surface

The editor is built on Tiptap v3 (`@tiptap/core`, `@tiptap/pm`, `@tiptap/starter-kit`) and renders into a Yjs `XmlFragment` named `default`. The `MarkdownManager` from `@inkeep/open-knowledge-core` serializes the Yjs fragment to markdown and back, while `@tiptap/y-tiptap` (`yXmlFragmentToProseMirrorRootNode`) converts the fragment into a ProseMirror root node for rendering. Source: [packages/app/src/server/agent-flow.test.ts:7-19](), [packages/core/package.json:39-48]()

A second Yjs primitive — a `Y.Text` named `source` — holds the raw markdown projection. Agent writes can target either surface:

- **Rich write (default fragment):** the agent pushes a `Y.XmlElement('paragraph')` containing a `Y.XmlText` with the inserted delta; Tiptap re-renders and the markdown manager re-serializes the document.
- **Markdown write (source text):** the agent appends to `doc.getText('source')`, which the source-mode viewer reflects without re-parsing through ProseMirror.

The agent-sim harness exercises both paths against an `Hocuspocus.openDirectConnection` so the same code path used by remote agents is testable in-process. Source: [packages/app/src/server/agent-flow.test.ts:21-46](), [packages/app/src/server/agent-flow.test.ts:60-90]()

```mermaid
flowchart LR
  Agent[Agent / CLI] -->|Y.Doc transact| Fragment[XmlFragment 'default']
  Agent -.->|append markdown| Source[Y.Text 'source']
  Fragment --> Tiptap[Tiptap Editor UI]
  Source --> SourceView[Source-mode viewer]
  Fragment --> MM[MarkdownManager]
  Source --> MM
  MM --> Disk[(Project files via git sync)]
```

## Frontend Component Conventions

UI components live under `packages/app/src/components` and `packages/app/src/editor`. A few load-bearing conventions are enforced by custom Biome plugins so the lint budget is the source of truth:

- **No unportaled `EditorContent`.** `createPortal(<EditorContent …/>, portalTarget)` is the sanctioned shape, preventing H6 cross-doc DOM bleed. Source: [biome-plugins/README.md:no-unportaled-editor-content.grit section]()
- **Ellipsis discipline.** `…` is reserved for native macOS menu items (built via `Menu.buildFromTemplate`) and for literal truncation indicators (graph labels, breadcrumb collapse, search snippets). It is forbidden in JSX text children and in `placeholder|aria-label|title|description|tooltip` attributes. Source: [biome-plugins/README.md:microcopy-ellipsis.grit section]()
- **Playwright `toPass` budget.** `toPass({ timeout: N })` below `15_000` is flagged because macOS `open(1)` plus window/IPC startup empirically takes 2–8s on a healthy CI runner. Source: [biome-plugins/README.md:playwright-topass-budget.grit section]()

Components that need to silence these rules use the suppression form `// biome-ignore lint/plugin/<rule-name>: <reason>` — a per-rule suppression that survives grep and ratchets down with the backlog. Source: [biome-plugins/README.md:Suppression syntax]()

## Integrated Terminal

The integrated terminal lives alongside the editor and reuses the same project working directory, so commands like `git`, `bun`, and project CLIs run in the same shell context the user is editing. On Linux and Intel Macs, `ok start` boots the same editor as a local web app, and the terminal panel is mounted in the desktop shell. Source: [README.md:9-19]()

### Height policy change (v0.18.1-beta.3)

Prior to `v0.18.1-beta.3`, the terminal opened at a fixed 240px on first use, which was frequently too short to read a command's output before the user had to drag the splitter. The new behavior computes the default height as roughly one third of the window height on first open. The exact computation and the persisted-overrides flow live in the `TerminalPanel` / `TerminalDock` components, and the test tier (`test:integration`, `test:e2e`) gates regressions in the splitter contract. Source: [turbo.json:test:integration inputs](), [community release notes for v0.18.1-beta.3]()

### Terminal gating and CLI detection

`TerminalGate` decides whether the terminal mounts at all, and `TerminalCliMissingBanner` surfaces a recoverable error when the user's PATH is missing the shell or the `ok` binary the terminal expects to invoke. Both are tree-shakeable so a user who never opens the terminal does not pay the bundle cost. Source: [README.md:9-19](), [packages/app/package.json:30-80]()

### Common failure modes

| Symptom | Likely cause | Where to look |
| --- | --- | --- |
| Terminal mounts but commands are no-ops | `ok` binary not in `PATH` (CLI not installed globally) | `TerminalCliMissingBanner` |
| First-open height reverts to old value | Cached `prefersTerminalHeight` in local storage from a prior beta | Browser devtools → application storage |
| Agent markdown appends vanish in WYSIWYG | Write targeted `Y.Text 'source'` while editor was in source mode (expected) | `agent-flow.test.ts:source mode injection test` |
| Splitter drag is janky on HiDPI | Missing `devicePixelRatio` listener on the panel resize observer | `TerminalDock.tsx` resize effect |

## See Also

- [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md) — install, `ok init` / `ok start` workflow
- [packages/core/src/markdown](https://github.com/inkeep/open-knowledge/tree/main/packages/core/src/markdown) — `MarkdownManager` round-trip semantics
- [packages/server/src](https://github.com/inkeep/open-knowledge/tree/main/packages/server/src) — Hocuspocus + MCP wiring
- [biome-plugins/README.md](https://github.com/inkeep/open-knowledge/blob/main/biome-plugins/README.md) — GritQL plugin authoring guide
- [v0.18.1-beta.3 release notes](https://github.com/inkeep/open-knowledge/releases/tag/v0.18.1-beta.3) — terminal default-height change

---

<a id='page-server-sync'></a>

## Server, Persistence, Shadow Repo & Sync

### Related Pages

Related topics: [Overview & Monorepo Architecture](#page-overview), [Editor, Frontend Components & Integrated Terminal](#page-editor-frontend), [CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)](#page-agent-handoff)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [packages/server/src/server-factory.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/server-factory.ts)
- [packages/server/src/persistence.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/persistence.ts)
- [packages/server/src/shadow-repo.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/shadow-repo.ts)
- [packages/server/src/sync-engine.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/sync-engine.ts)
- [packages/server/src/conflict-storage.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/conflict-storage.ts)
- [packages/server/src/file-watcher.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/file-watcher.ts)
- [packages/server/src/index.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/server/src/index.ts)
- [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json)
- [packages/core/src/shadow-repo-layout.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/core/src/shadow-repo-layout.ts)
- [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts)
- [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md)
- [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json)
</details>

# Server, Persistence, Shadow Repo & Sync

The `open-knowledge` editor is a local-first, git-backed markdown workspace. To deliver real-time collaboration, agent integration, and durable on-disk storage without sacrificing the local-first feel, the project ships a dedicated server package (`@inkeep/open-knowledge-server`) that owns the realtime sync plane, the disk persistence plane, and the git/shadow-repo plane. This page documents how those planes fit together.

## 1. Role and Scope of the Server Package

The server package is the runtime that mediates between Yjs documents in the browser/Electron renderer, the local filesystem, and the user’s git repository. It is published as the workspace package `@inkeep/open-knowledge-server` and is consumed by the desktop app, the `ok` CLI web mode, and integration tests. Source: [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json).

Key responsibilities visible from the dependency and test surface:

| Concern | Implementation |
| --- | --- |
| Realtime collaboration | `@hocuspocus/server` 4.0.0-rc.1 (`Hocuspocus` class) — Source: [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts) |
| CRDT document model | `yjs`, `@tiptap/y-tiptap`, ProseMirror schema — Source: [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json) |
| Agent ↔ editor bridge | MCP SDK (`@modelcontextprotocol/sdk`) and direct Yjs transactions — Source: [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts) |
| Observability | OpenTelemetry trace + metric exporters (OTLP HTTP) — Source: [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json) |
| Persistence & sync | `server-factory`, `persistence`, `sync-engine`, `conflict-storage`, `file-watcher`, `shadow-repo` modules |

The README frames the product as “a beautiful, local-first markdown editor and LLM wiki … Sharing and auto-sync are available for team-based collaboration [and] are powered by git.” Source: [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md).

## 2. Document Model and Sync Engine

The editor stores two parallel representations of the same file inside a single Yjs document:

- An `XmlFragment('default')` that mirrors the ProseMirror / Tiptap rich-text tree. This is what the WYSIWYG surface binds to.
- A `Y.Text('source')` that holds the canonical markdown serialization. This is what the source-mode surface binds to and what the git layer diffs against.

Both shapes are written inside `doc.transact(...)` so origin tracking and undo stay consistent. The `agent-flow.test.ts` suite exercises three write paths: a direct Y.XmlElement push into the fragment, a markdown append into `Y.Text('source')`, and a source-mode “agent write updates serialized markdown” scenario that asserts the fragment re-serializes to the expected markdown. Source: [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts).

The `sync-engine` module owns the reconciliation rules between these two representations and feeds the resulting state to the persistence layer. Because the markdown in `Y.Text('source')` is what eventually lands on disk, the engine keeps the two sides consistent — e.g. when an agent writes markdown, the next observation round re-derives the fragment snapshot. The same module is what the desktop app and CLI rely on for opening documents in `Hocuspocus.openDirectConnection(...)` for headless writes.

## 3. Persistence Layer and Conflict Storage

`persistence.ts` is responsible for durable storage of Yjs updates between sessions, while `conflict-storage.ts` captures the cases where the on-disk markdown (e.g. a concurrent `git pull`, an external editor save) diverges from what the live document expects. When divergence is detected, the conflict-storage path keeps both the CRDT side and the disk side instead of silently overwriting — users can later resolve the conflict inside the editor.

The `file-watcher.ts` module bridges the filesystem and the sync engine: it observes the working tree and feeds external changes back into the sync engine so that, for example, switching branches or pulling in a teammate’s commit surfaces in the editor without losing local CRDT state.

Because the build pipeline caches by source inputs (`turbo.json` declares `inputs` per `test:integration` task that includes `../server/src/**/*.ts` and `../core/src/**/*.ts`), any change to these modules forces a full integration rebuild, signaling that the persistence ↔ sync boundary is treated as load-bearing. Source: [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json).

## 4. Shadow Repo and Git-Backed Sync

OpenKnowledge persists every change as git commits inside a hidden mirror of the user’s project — a “shadow repo.” The layout of that mirror is shared between the core package and the server so both agree on where each document lives on disk. Source: [packages/core/src/shadow-repo-layout.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/core/src/shadow-repo-layout.ts).

The `shadow-repo.ts` module is the server-side owner of this layout. It:

1. Creates and maintains the shadow repo on first launch (or detects an existing one).
2. Writes Yjs snapshots as ordinary markdown files at the layout paths.
3. Commits those files so that every edit produces a reviewable git history — the same history that powers team sharing, as described in the README. Source: [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md).
4. Coordinates with `conflict-storage` so that three-way merges (CRDT vs. shadow vs. upstream remote) can be surfaced rather than dropped.

```mermaid
flowchart LR
    Editor[Tiptap / Yjs in renderer] -- Yjs sync --> SyncEngine[sync-engine.ts]
    Agent[LLM agent via MCP] -- Yjs transactions --> SyncEngine
    SyncEngine -- XmlFragment + Y.Text --> Persistence[persistence.ts]
    Persistence -- markdown snapshots --> ShadowRepo[shadow-repo.ts]
    ShadowRepo -- git commits --> Git[(Local shadow git repo)]
    Git -- push / pull --> Remote[(Team remote)]
    FileWatcher[file-watcher.ts] -- external diffs --> SyncEngine
    ConflictStorage[conflict-storage.ts] -- unresolved diffs --> Editor
```

## 5. Operational Notes and Common Failure Modes

- **Dual-write consistency.** Both the rich-text fragment and the markdown `Y.Text` must be written in the same `doc.transact` call; otherwise the editor and the shadow repo can drift. The `agent-flow.test.ts` suite pins this contract.
- **First-use terminal sizing (community context).** v0.18.1-beta.3 changed the integrated terminal default to one third of window height — a UX-only patch, but it shows the project’s pattern of pairing editor-facing defaults with reactive sizing computed from runtime dimensions, similar in spirit to how the sync engine reacts to runtime Yjs events.
- **Build caching.** `turbo.json` declares `cache: true` for `test:integration` and `test:conversion`, with explicit `inputs` covering `packages/server/src/**/*.ts` and `packages/core/src/**/*.ts` — change any persistence or sync file and the gate re-runs. Source: [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json).
- **External edits.** The file-watcher is the only path that pulls filesystem changes back into the CRDT; disabling or misconfiguring it leaves the editor blind to `git pull`, IDE refactors, or CLI-driven rewrites.

## See Also

- Editor extensions and WYSIWYG surface — see the project’s editor package and `shared` extensions referenced by `agent-flow.test.ts`.
- CLI install and `ok init` flow — [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md).
- Core markdown ↔ ProseMirror serialization — `@inkeep/open-knowledge-core` (see [packages/core/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/core/package.json)).

---

<a id='page-agent-handoff'></a>

## CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)

### Related Pages

Related topics: [Overview & Monorepo Architecture](#page-overview), [Editor, Frontend Components & Integrated Terminal](#page-editor-frontend), [Server, Persistence, Shadow Repo & Sync](#page-server-sync)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/inkeep/open-knowledge/blob/main/README.md)
- [packages/cli/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/cli/package.json)
- [packages/app/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/app/package.json)
- [packages/core/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/core/package.json)
- [packages/server/package.json](https://github.com/inkeep/open-knowledge/blob/main/packages/server/package.json)
- [packages/app/src/server/agent-flow.test.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-flow.test.ts)
- [packages/app/src/server/agent-sim.ts](https://github.com/inkeep/open-knowledge/blob/main/packages/app/src/server/agent-sim.ts)
- [biome-plugins/README.md](https://github.com/inkeep/open-knowledge/blob/main/biome-plugins/README.md)
- [turbo.json](https://github.com/inkeep/open-knowledge/blob/main/turbo.json)
</details>

# CLI, Desktop Shell & Agent Handoff (Claude / Codex / Cursor)

OpenKnowledge ships in two delivery shapes that share one editor core: a macOS desktop bundle and a Node-based local web app driven by an `ok` CLI. Both shapes converge on a Hocuspocus-backed Y.Doc so that external agents (Claude Code, Codex, Cursor) can write markdown into a document while the editor reflects the change in real time. Source: [README.md](README.md).

## Distribution Shapes

### Desktop app (macOS)

The README describes a signed DMG that drops `Open Knowledge.app` into `/Applications`. Source: [README.md](README.md). The desktop bundle re-uses the same editor and server packages — `packages/app` and `packages/server` — so feature parity between the DMG and the CLI is intentional. The `@inkeep/open-knowledge-app` package is `private: true`, indicating it is built only inside this monorepo, while the CLI package (`@inkeep/open-knowledge`, version `0.18.0`) is published for general consumption. Source: [packages/app/package.json](packages/app/package.json), Source: [packages/cli/package.json](packages/cli/package.json).

### CLI / local web app

On Linux, Intel Macs, or any environment where the DMG is not viable, the editor runs as a browser-served web app. The CLI registers two bin entries — `open-knowledge` and `ok` — pointing at `dist/cli.mjs`. Source: [packages/cli/package.json](packages/cli/package.json). Bootstrapping requires Node.js 24+ ([`.node-version`](.node-version)) and Bun 1.3.13+ ([`.bun-version`](.bun-version)). Source: [README.md](README.md).

## CLI Surface

Two commands are documented in the README:

| Command | Purpose |
| --- | --- |
| `ok init` | Scaffold the current directory as an OpenKnowledge project and wire up Claude Code, Cursor, and Codex integrations. |
| `ok start --open` | Serve the editor locally and open it in the user's default browser. |

Source: [README.md](README.md).

The CLI package depends on `@inkeep/open-knowledge-app`, `@inkeep/open-knowledge-core`, and `@inkeep/open-knowledge-server` (all `workspace:*`), so the same editor bundle that ships in the DMG is statically embedded by the CLI build. The `build:app` script copies `packages/app/dist` into `dist/public`, and `build:skill-asset` bundles server-side skill assets into the CLI distribution. Source: [packages/cli/package.json](packages/cli/package.json). This means `ok start` serves the production editor bundle; it does not hot-reload `packages/app/src/**` unless invoked from the monorepo via `bun run dev`.

## Desktop Shell

The desktop shell wraps the same Vite-built editor and Hocuspocus server in an Electron-style host. The lint plugin rule `no-loosely-typed-webcontents-ipc` is suppressed in 12 sites of `packages/desktop/src/main/preload/index.ts`, 1 site of `packages/desktop/src/main/shared/ipc-send.ts`, and 2 e2e smoke sites — a strong signal that the desktop shell uses typed `contextBridge` channels to expose a narrow API surface to the renderer. Source: [biome-plugins/README.md](biome-plugins/README.md).

A notable UX change in the latest beta: the integrated terminal now opens at approximately one third of the window height on first use, rather than the prior fixed `240px` default. Source: v0.18.1-beta.3 release notes ([community context](#)). This matches a common complaint pattern in markdown editors where a fixed pixel default is too short for command output without manual dragging.

## Agent Handoff (Claude / Codex / Cursor)

### Wiring during `ok init`

`ok init` configures three agent surfaces side by side so that an LLM agent can read or write into the same Y.Doc the editor uses:

- **Claude Code** — wired as a project skill via `@modelcontextprotocol/sdk`.
- **Cursor** — wired through the editor's helper bundle.
- **Codex** — wired through the CLI's skill bundle (`build-skill-asset`).

Sources: [README.md](README.md), [packages/server/package.json](packages/server/package.json), [packages/cli/package.json](packages/cli/package.json).

### Write path

Agents write through a Hocuspocus `DirectConnection` against the same document name the editor has open. The test suite demonstrates the contract: a server-side `Hocuspocus` instance opens `openDirectConnection('test-agent-flow')`, mutates the `default` `Y.XmlFragment` inside a transaction, then re-serializes the fragment through `yXmlFragmentToProseMirrorRootNode` plus `MarkdownManager.serialize` to confirm the markdown string contains the agent's text. Source: [packages/app/src/server/agent-flow.test.ts](packages/app/src/server/agent-flow.test.ts).

A second variant, "source mode injection," proves that an agent can write by appending to a `Y.Text` named `source` while the user is in raw markdown view. The test seeds the fragment, hydrates `doc.getText('source')` with the serialized markdown, then inserts `${separator}${agentMarkdown}\n` at the end inside a transaction tagged `'agent-write'`. The serialized markdown after the operation must contain both the original and the agent text. Source: [packages/app/src/server/agent-flow.test.ts](packages/app/src/server/agent-flow.test.ts).

```mermaid
flowchart LR
    A[Claude / Codex / Cursor agent] -->|MCP skill or helper bundle| B[ok init config]
    B --> C[Hocuspocus server]
    C -->|DirectConnection.transact| D[Y.Doc default fragment + source text]
    D -->|yXmlFragmentToProseMirrorRootNode| E[TipTap ProseMirror schema]
    E -->|MarkdownManager.serialize| F[Markdown string]
    F -->|reflected to| G[Editor WYSIWYG / Source mode]
```

The same `MarkdownManager` and `sharedExtensions` from `@inkeep/open-knowledge-core` are used by both the editor (via `@tiptap/core`'s schema) and the agent write path, guaranteeing round-trip fidelity. Source: [packages/app/src/server/agent-flow.test.ts](packages/app/src/server/agent-flow.test.ts), Source: [packages/core/package.json](packages/core/package.json).

### Agent simulator

`packages/app/src/server/agent-sim.ts` is a developer-facing simulator that drives the same write paths against a running dev server. It exposes two modes — `agentWriteMarkdown` (raw Y.Text append) and `agentWriteRaw` (fragment mutation) — and a "patch mode" that walks a `PATCH_SEQUENCE` of find/replace pairs over a starter document, logging awareness transitions (`editing→idle`) and activity-map updates after each successful write. Source: [packages/app/src/server/agent-sim.ts](packages/app/src/server/agent-sim.ts). If a write fails the simulator prints `Is the dev server running? (bun run dev)` to remind the operator to start the editor first. Source: [packages/app/src/server/agent-sim.ts](packages/app/src/server/agent-sim.ts).

## Common Failure Modes

- **CLI invoked without `ok init`:** `ok start --open` will serve the editor, but no agent will be wired into the project. Re-run `ok init` from the project root.
- **Agent writes invisible in editor:** usually means the agent opened a `DirectConnection` against a different document name than the editor's active tab. Verify the doc identifier matches.
- **Source-mode divergence:** the agent wrote into the `Y.XmlFragment`, but the editor is in source mode and shows the `Y.Text('source')` projection. Both views must observe each other; the test in `agent-flow.test.ts` enforces that invariant.
- **Stale skill bundle:** after changing skill source, run `bun run build:skill-asset` in the CLI package so `dist/assets/skills/` is regenerated before publishing.
- **Terminal too short:** fixed-pixel terminal defaults are replaced by a proportional one-third-of-window default in v0.18.1-beta.3 — older betas need a manual drag if the divider feels cramped. Source: v0.18.1-beta.3 release notes ([community context](#)).

## See Also

- [README.md](README.md) — installation and quickstart
- [packages/cli/package.json](packages/cli/package.json) — CLI package manifest and build scripts
- [packages/app/src/server/agent-flow.test.ts](packages/app/src/server/agent-flow.test.ts) — canonical agent-write test contract
- [packages/app/src/server/agent-sim.ts](packages/app/src/server/agent-sim.ts) — developer agent simulator
- [biome-plugins/README.md](biome-plugins/README.md) — desktop IPC typing conventions

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: inkeep/open-knowledge

Summary: Found 7 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

## 1. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://news.ycombinator.com/item?id=48675435

## 2. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://news.ycombinator.com/item?id=48675435

## 3. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://news.ycombinator.com/item?id=48675435

## 4. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://news.ycombinator.com/item?id=48675435

## 5. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://news.ycombinator.com/item?id=48675435

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://news.ycombinator.com/item?id=48675435

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://news.ycombinator.com/item?id=48675435

<!-- canonical_name: inkeep/open-knowledge; human_manual_source: deepwiki_human_wiki -->
