@animalabs/connectome-host 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/.env.example +20 -0
  2. package/.github/workflows/publish.yml +65 -0
  3. package/ARCHITECTURE.md +355 -0
  4. package/CHANGELOG.md +30 -0
  5. package/HEADLESS-FLEET-PLAN.md +330 -0
  6. package/README.md +189 -0
  7. package/UNIFIED-TREE-PLAN.md +242 -0
  8. package/bun.lock +288 -0
  9. package/docs/AGENT-MEMORY-GUIDE.md +214 -0
  10. package/docs/AGENT-ONBOARDING.md +541 -0
  11. package/docs/ATTENTION-AND-GATING.md +120 -0
  12. package/docs/DEPLOYMENTS.md +130 -0
  13. package/docs/DEV-ENVIRONMENT.md +215 -0
  14. package/docs/LIBRARY-PIPELINE.md +286 -0
  15. package/docs/LOCUS-ROUTING-DESIGN.md +115 -0
  16. package/docs/claudeai-evacuation.md +228 -0
  17. package/docs/debug-context-api.md +208 -0
  18. package/docs/webui-deployment.md +219 -0
  19. package/package.json +33 -0
  20. package/recipes/SETUP.md +308 -0
  21. package/recipes/TRIUMVIRATE-SETUP.md +467 -0
  22. package/recipes/claude-export-revive.json +19 -0
  23. package/recipes/clerk.json +157 -0
  24. package/recipes/knowledge-miner.json +174 -0
  25. package/recipes/knowledge-reviewer.json +76 -0
  26. package/recipes/mcpl-editor-test.json +38 -0
  27. package/recipes/prompts/transplant-addendum.md +17 -0
  28. package/recipes/triumvirate.json +63 -0
  29. package/recipes/webui-fleet-test.json +27 -0
  30. package/recipes/webui-test.json +16 -0
  31. package/recipes/zulip-miner.json +87 -0
  32. package/scripts/connectome-doctor +373 -0
  33. package/scripts/evacuator.ts +956 -0
  34. package/scripts/import-claudeai-export.ts +747 -0
  35. package/scripts/lib/line-reader.ts +53 -0
  36. package/scripts/test-historical-thinking.ts +148 -0
  37. package/scripts/warmup-session.ts +336 -0
  38. package/src/agent-name.ts +58 -0
  39. package/src/commands.ts +1074 -0
  40. package/src/headless.ts +528 -0
  41. package/src/index.ts +867 -0
  42. package/src/logging-adapter.ts +208 -0
  43. package/src/mcpl-config.ts +199 -0
  44. package/src/modules/activity-module.ts +270 -0
  45. package/src/modules/channel-mode-module.ts +260 -0
  46. package/src/modules/fleet-module.ts +1705 -0
  47. package/src/modules/fleet-types.ts +225 -0
  48. package/src/modules/lessons-module.ts +465 -0
  49. package/src/modules/mcpl-admin-module.ts +345 -0
  50. package/src/modules/retrieval-module.ts +327 -0
  51. package/src/modules/settings-module.ts +143 -0
  52. package/src/modules/subagent-module.ts +2074 -0
  53. package/src/modules/subscription-gc-module.ts +322 -0
  54. package/src/modules/time-module.ts +85 -0
  55. package/src/modules/tui-module.ts +76 -0
  56. package/src/modules/web-ui-curve-page.ts +249 -0
  57. package/src/modules/web-ui-module.ts +2595 -0
  58. package/src/recipe.ts +1003 -0
  59. package/src/session-manager.ts +278 -0
  60. package/src/state/agent-tree-reducer.ts +431 -0
  61. package/src/state/fleet-tree-aggregator.ts +195 -0
  62. package/src/strategies/frontdesk-strategy.ts +364 -0
  63. package/src/synesthete.ts +68 -0
  64. package/src/tui.ts +2200 -0
  65. package/src/types/bun-ffi.d.ts +6 -0
  66. package/src/web/protocol.ts +648 -0
  67. package/test/agent-name.test.ts +62 -0
  68. package/test/agent-tree-fleet-launch.test.ts +64 -0
  69. package/test/agent-tree-reducer-parity.test.ts +194 -0
  70. package/test/agent-tree-reducer.test.ts +443 -0
  71. package/test/agent-tree-rollup.test.ts +109 -0
  72. package/test/autobio-progress-snapshot.test.ts +40 -0
  73. package/test/claudeai-export-importer.test.ts +386 -0
  74. package/test/evacuator.test.ts +332 -0
  75. package/test/fleet-commands.test.ts +244 -0
  76. package/test/fleet-no-subfleets.test.ts +147 -0
  77. package/test/fleet-orchestration.test.ts +353 -0
  78. package/test/fleet-recipe.test.ts +124 -0
  79. package/test/fleet-route.test.ts +44 -0
  80. package/test/fleet-smoke.test.ts +479 -0
  81. package/test/fleet-subscribe-union-e2e.test.ts +123 -0
  82. package/test/fleet-subscribe-union.test.ts +85 -0
  83. package/test/fleet-tree-aggregator-e2e.test.ts +110 -0
  84. package/test/fleet-tree-aggregator.test.ts +215 -0
  85. package/test/frontdesk-strategy.test.ts +326 -0
  86. package/test/headless-describe.test.ts +182 -0
  87. package/test/headless-smoke.test.ts +190 -0
  88. package/test/logging-adapter.test.ts +87 -0
  89. package/test/mcpl-admin-module.test.ts +213 -0
  90. package/test/mcpl-agent-overlay.test.ts +126 -0
  91. package/test/mock-headless-child.ts +133 -0
  92. package/test/recipe-cache-ttl.test.ts +37 -0
  93. package/test/recipe-env.test.ts +157 -0
  94. package/test/recipe-path-resolution.test.ts +170 -0
  95. package/test/subagent-async-timeout.test.ts +381 -0
  96. package/test/subagent-fork-materialise.test.ts +241 -0
  97. package/test/subagent-peek-scoping.test.ts +180 -0
  98. package/test/subagent-peek-zombie.test.ts +148 -0
  99. package/test/subagent-reaper-in-flight.test.ts +229 -0
  100. package/test/subscription-gc-module.test.ts +136 -0
  101. package/test/warmup-handoff.test.ts +150 -0
  102. package/test/web-ui-bind.test.ts +51 -0
  103. package/test/web-ui-module.test.ts +246 -0
  104. package/test/web-ui-protocol.test.ts +0 -0
  105. package/tsconfig.json +14 -0
  106. package/web/bun.lock +357 -0
  107. package/web/index.html +12 -0
  108. package/web/package.json +24 -0
  109. package/web/src/App.tsx +1931 -0
  110. package/web/src/Context.tsx +158 -0
  111. package/web/src/ContextDocument.tsx +150 -0
  112. package/web/src/Files.tsx +271 -0
  113. package/web/src/Lessons.tsx +164 -0
  114. package/web/src/Mcpl.tsx +310 -0
  115. package/web/src/Stream.tsx +119 -0
  116. package/web/src/TreeSidebar.tsx +283 -0
  117. package/web/src/Usage.tsx +182 -0
  118. package/web/src/main.tsx +7 -0
  119. package/web/src/styles.css +26 -0
  120. package/web/src/tree.ts +268 -0
  121. package/web/src/wire.ts +120 -0
  122. package/web/tsconfig.json +21 -0
  123. package/web/vite.config.ts +32 -0
package/.env.example ADDED
@@ -0,0 +1,20 @@
1
+ ANTHROPIC_API_KEY=sk-ant-...
2
+ # MODEL=claude-opus-4-6
3
+
4
+ # --- Recipe ${VAR} substitutions ---------------------------------------
5
+ # Recipes in recipes/ reference these via ${VAR}. Unset = that branch of
6
+ # the recipe fails to load; remove the referencing mcpServers block from
7
+ # the recipe if you don't use the source.
8
+
9
+ # GitLab (knowledge-miner.json: gitlab)
10
+ # GITLAB_TOKEN=glpat-...
11
+ # GITLAB_API_URL=https://gitlab.example.com/api/v4
12
+
13
+ # Notion (knowledge-miner.json: syncntn)
14
+ # NOTION_STORAGE_URL=http://localhost:8000
15
+ # NOTION_WORKSPACE_ID=...
16
+
17
+ # Scribe — audio/video transcription (knowledge-miner.json: scribe)
18
+ # GEMINI_API_KEY=... # REQUIRED if you keep the scribe server (recipe uses bare ${GEMINI_API_KEY}); powers transcription
19
+ # NOTION_API_KEY=... # optional (recipe uses ${NOTION_API_KEY:-}); only scribe--scribe_notion_page needs it
20
+ # SCRIBE_GLOSSARY_URL=... # optional (recipe uses ${SCRIBE_GLOSSARY_URL:-}); unset = transcribe without a glossary
@@ -0,0 +1,65 @@
1
+ name: Build & Publish
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ tags:
7
+ - 'v*'
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build-and-test:
14
+ name: Build & Test
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Setup Node.js
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version: 24
24
+
25
+ - name: Install dependencies
26
+ run: npm install
27
+
28
+ - name: Build web assets
29
+ run: npm run build:web
30
+
31
+ - name: Test
32
+ run: npm test
33
+
34
+ publish:
35
+ name: Publish to npm
36
+ runs-on: ubuntu-latest
37
+ needs: build-and-test
38
+ if: startsWith(github.ref, 'refs/tags/v')
39
+
40
+ # OIDC trusted publishing: GitHub mints a short-lived id-token, npm CLI
41
+ # exchanges it for a publish credential. No long-lived NPM_TOKEN secret.
42
+ # npm-side config: npmjs.com -> package -> Settings -> Trusted Publishers
43
+ # -> GitHub Actions, matching the repo + this workflow path.
44
+ permissions:
45
+ contents: read
46
+ id-token: write
47
+
48
+ steps:
49
+ - uses: actions/checkout@v4
50
+
51
+ - name: Setup Node.js
52
+ uses: actions/setup-node@v4
53
+ with:
54
+ # node 24 ships npm >= 11.5.1, required for OIDC publishing.
55
+ node-version: 24
56
+ registry-url: https://registry.npmjs.org
57
+
58
+ - name: Install dependencies
59
+ run: npm install
60
+
61
+ - name: Build web assets
62
+ run: npm run build:web
63
+
64
+ - name: Publish
65
+ run: npm publish --access public --provenance
@@ -0,0 +1,355 @@
1
+ # connectome-host
2
+
3
+ A general-purpose agent TUI host with recipe-based configuration. Point it at any use case by loading a recipe — a JSON file that defines the system prompt, MCP servers, modules, and agent settings. Built on the Connectome stack (Agent Framework + Context Manager + Membrane + Chronicle).
4
+
5
+ ## Goals
6
+
7
+ 1. **Recipe-driven configuration** — a single JSON file defines the entire agent personality: system prompt, model, MCP servers, module toggles, context strategy, session naming hints
8
+ 2. **Parallel exploration** — spawn and fork subagents to work on multiple tasks concurrently, with fleet tree view and live peeking
9
+ 3. **Semantic memory** — persistent lesson store with confidence scoring, plus LLM-as-retriever pipeline for automatic context injection
10
+ 4. **Reversibility** — Chronicle-backed undo/redo, named checkpoints, branch exploration via slash commands
11
+ 5. **Session management** — isolated Chronicle stores per session, auto-naming via Haiku
12
+ 6. **Dogfood the AF** — stress-test the agent framework's module system, MCPL integration, context strategies, and multi-agent capabilities
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ ┌──────────────┐
18
+ │ OpenTUI │ ScrollBox, TextRenderable,
19
+ │ (tui.ts) │ InputRenderable, status bar
20
+ └──────┬───────┘
21
+ │ pushEvent('external-message')
22
+ ┌──────┴───────┐
23
+ │ TuiModule │ event bridge: TUI → context messages
24
+ └──────┬───────┘
25
+
26
+ ┌───────────┴───────────┐
27
+ │ Agent Framework │
28
+ │ ┌─────────────────┐ │
29
+ │ │ recipe agent │ │ name, model, prompt from recipe
30
+ │ │ (event loop) │ │
31
+ │ └────────┬────────┘ │
32
+ │ │ │
33
+ │ ┌────────┴────────┐ │
34
+ │ │ Modules │ │ (recipe-toggleable)
35
+ │ │ - subagent │──┼── spawn/fork ephemeral agents
36
+ │ │ - lessons │──┼── CRUD knowledge store (Chronicle)
37
+ │ │ - retrieval │──┼── LLM-as-retriever (Haiku)
38
+ │ │ - workspace │──┼── mount-based filesystem (Chronicle-backed)
39
+ │ │ - tui │ │ (always-on)
40
+ │ └────────┬────────┘ │
41
+ │ │ │
42
+ │ ┌────────┴────────┐ │
43
+ │ │ MCPL Servers │ │ from recipe + mcpl-servers.json
44
+ │ │ (stdio or ws) │──┼── any MCP/MCPL server
45
+ │ └─────────────────┘ │
46
+ └───────────────────────┘
47
+ ```
48
+
49
+ ### Core data flow
50
+
51
+ 1. User types a message in the TUI
52
+ 2. `TuiModule` converts it to a context message + triggers inference
53
+ 3. The agent reads the conversation, calls tools (MCPL servers, subagent, lessons, etc.)
54
+ 4. Before each inference, `RetrievalModule` and `LessonsModule` inject relevant knowledge via `gatherContext()`
55
+ 5. Trace events (`inference:tokens`, `tool:started`, etc.) drive the TUI's streaming display
56
+
57
+ ## Project Structure
58
+
59
+ ```
60
+ connectome-host/
61
+ src/
62
+ index.ts Entry point, recipe resolution, framework factory
63
+ tui.ts OpenTUI-based terminal interface (@opentui/core)
64
+ commands.ts Slash command handler (Chronicle reversibility, /mcp, /session, etc.)
65
+ recipe.ts Recipe loading, validation, persistence, CLI parsing
66
+ mcpl-config.ts File-driven MCPL server config (mcpl-servers.json)
67
+ session-manager.ts Session index, isolation, migration
68
+ synesthete.ts Auto-naming sessions via Haiku
69
+ modules/
70
+ tui-module.ts Event bridge: external-message → context + inference
71
+ subagent-module.ts Spawn, fork, peek, hud, concurrency, return
72
+ lessons-module.ts Knowledge CRUD + gatherContext injection
73
+ retrieval-module.ts 3-step LLM-as-retriever pipeline
74
+ time-module.ts Session-start timestamp + time:now tool
75
+ strategies/ (reserved for future domain-specific strategies)
76
+ types/
77
+ bun-ffi.d.ts Bun FFI type declarations
78
+ recipes/
79
+ zulip-miner.json Knowledge extraction from Zulip workspaces
80
+ knowledge-miner.json General-purpose knowledge extraction
81
+ mcpl-editor-test.json Collaborative markdown editor testing via WebSocket MCPL
82
+ ```
83
+
84
+ ## Components
85
+
86
+ ### Recipe System (`recipe.ts`)
87
+
88
+ Recipes are JSON files that configure everything domain-specific. See [README.md](README.md) for the full recipe schema.
89
+
90
+ **Loading precedence**:
91
+ 1. CLI argument (`bun src/index.ts recipes/foo.json` or `bun src/index.ts https://...`)
92
+ 2. Saved recipe from last run (`data/.recipe.json`)
93
+ 3. Built-in default (generic assistant with all modules enabled)
94
+
95
+ **System prompt from URL**: If `agent.systemPrompt` is an HTTP(S) URL (no spaces/newlines), the text is fetched at load time.
96
+
97
+ **MCP server merging**: Recipe servers merge with `mcpl-servers.json`. The file wins on conflict, so `/mcp add` can override recipe defaults.
98
+
99
+ **Transport support**: Recipe MCP servers support both stdio (`command` + `args`) and WebSocket (`url` + `transport: 'websocket'` + optional `token`).
100
+
101
+ ### TUI (`tui.ts`)
102
+
103
+ Built on [OpenTUI](https://github.com/anomalyco/opentui) (`@opentui/core`) — the same terminal UI library that powers OpenCode. Requires the Bun runtime.
104
+
105
+ **Layout**:
106
+ ```
107
+ ┌─────────────────────────────────────────────────────┐
108
+ │ ScrollBoxRenderable (flexGrow, stickyScroll) │
109
+ │ └─ TextRenderable per message/stream chunk │
110
+ ├──────────────────────────────────────┬──────────────┤
111
+ │ [✓ idle | tool | N sub] │ 1.2kin 0.5kout│
112
+ ├──────────────────────────────────────┴──────────────┤
113
+ │ InputRenderable │
114
+ └─────────────────────────────────────────────────────┘
115
+ ```
116
+
117
+ - **Conversation area**: `ScrollBoxRenderable` with `stickyScroll: true` — auto-scrolls as content is added. Each message or tool notification is a `TextRenderable` child node.
118
+ - **Status bar**: Two `TextRenderable` nodes in a `BoxRenderable` with `justifyContent: 'space-between'`. Left side shows agent state, current tool, and subagent count. Right side shows cumulative token usage across the session (all agents).
119
+ - **Input**: `InputRenderable` with `ENTER` event for submitting messages and commands.
120
+ - **Keyboard**: Tab toggles fleet view (subagent tree). Esc interrupts the agent. Ctrl+V toggles verbose mode. Ctrl+B detaches a sync subagent to background. Ctrl+C exits.
121
+
122
+ **Streaming**: Tokens arrive via `inference:tokens` trace events. A plain string buffer tracks accumulated text and assigns the full string to `TextRenderable.content` each time (the `.content` property is a `StyledText` object, not a string — `+=` would break).
123
+
124
+ **Token tracking**: `usage:updated` trace events (from all agents) feed a session-wide counter tracking input tokens, output tokens, cache reads, and cache writes. Displayed compactly: `1.2kin 0.5kout 3.4kcache`.
125
+
126
+ **Dual mode**: If stdout is not a TTY (piped/CI), falls back to a plain readline loop with `waitForInference` promise gating. No OpenTUI dependency on this path.
127
+
128
+ ### Subagent Module (`subagent-module.ts`)
129
+
130
+ Enables the agent to delegate work to parallel ephemeral agents.
131
+
132
+ **Tools**:
133
+ | Tool | Behavior |
134
+ |------|----------|
135
+ | `subagent--spawn` | Fresh agent with system prompt + task. Async by default (returns immediately). |
136
+ | `subagent--fork` | Agent inheriting parent's compiled context. Async by default. |
137
+ | `subagent--hud` | Toggle fleet status HUD overlay (injected before each inference). |
138
+ | `subagent--concurrency` | View/adjust concurrency ceiling (auto-adapts to rate limits). |
139
+ | `subagent--peek` | Live state of a running subagent (status, messages, streaming output). |
140
+ | `subagent--return` | Subagent calls this to deliver results back to parent and exit. |
141
+
142
+ **Async by default**: Spawn and fork return immediately; results arrive as messages + inference-request events. Pass `sync: true` to block until completion. Sync tasks are detachable (Ctrl+B or `timeoutMs` auto-detach).
143
+
144
+ **Interaction model** (parallel-async-await): When the LLM emits multiple spawn/fork calls in a single turn, the AF dispatches them concurrently. The parent blocks on `waiting_for_tools` until all results arrive together — natural fan-out without explicit orchestration.
145
+
146
+ **Isolation**: Each ephemeral agent gets its own temporary Chronicle store (temp directory, cleaned up on completion). This prevents message leakage between parent and children.
147
+
148
+ **Depth limiting**: Constructor takes `maxDepth` (default 3). At the depth limit, subagent tools are stripped from the child's tool set.
149
+
150
+ **Concurrency**: Adaptive concurrency control — halves on HTTP 429, recovers after consecutive successes.
151
+
152
+ **Terminology**: "Fork" and "branch" are distinct concepts:
153
+ - **Fork** = spawning a subagent that inherits the parent's compiled messages (agent-level, message copy)
154
+ - **Branch** = Chronicle state branch for undo/redo/checkpointing (storage-level, user-facing)
155
+
156
+ ### EventGate
157
+
158
+ MCPL event gating is a core Agent Framework feature. Configuration is file-based (`{storePath}/config/gate.json`) and controlled via `GateOptions` in `FrameworkConfig`. The recipe's `modules.wake` key controls whether gating is enabled and can provide initial policy config.
159
+
160
+ ### Workspace Module (from AF)
161
+
162
+ Mount-based filesystem access backed by Chronicle, imported from `@connectome/agent-framework`. Replaces the former `FilesModule` + `LocalFilesModule`.
163
+
164
+ **Default mounts** (when recipe doesn't specify):
165
+ - `input` — read-only, `./input`
166
+ - `products` — read-write, `./output`
167
+
168
+ **Recipe-configurable**: `modules.workspace.mounts` overrides the default mounts. `modules.workspace.configMount: true` adds a special `_config` mount that version-controls gate config via Chronicle.
169
+
170
+ Disabled entirely with `modules.workspace: false` (no filesystem access at all).
171
+
172
+ ### Lessons Module (`lessons-module.ts`)
173
+
174
+ Persistent knowledge store backed by Chronicle state snapshots.
175
+
176
+ **Data model**:
177
+ ```typescript
178
+ interface Lesson {
179
+ id: string; // Short UUID
180
+ content: string; // The knowledge itself
181
+ confidence: number; // 0.0–1.0
182
+ tags: string[]; // people, process, decision, technical, ...
183
+ evidence: string[]; // Source references (stream:topic:messageId)
184
+ created: number;
185
+ updated: number;
186
+ deprecated: boolean;
187
+ deprecationReason?: string;
188
+ }
189
+ ```
190
+
191
+ **Tools**: `create`, `update`, `deprecate`, `query` (text + tags + confidence filter), `list`, `boost`, `demote`.
192
+
193
+ **Confidence dynamics**: `boost` applies diminishing-returns growth (`+0.1 * (1 - c)`); `demote` applies diminishing-returns decay (`-0.1 * c`). Lessons below 0.3 confidence are excluded from context injection.
194
+
195
+ **Context injection**: `gatherContext()` injects the top 10 active lessons (by confidence) as a `## Knowledge Library` block in the system position.
196
+
197
+ ### Retrieval Module (`retrieval-module.ts`)
198
+
199
+ Semantic memory lookup using a three-step LLM-as-retriever pipeline. Runs in `gatherContext()` before each main-agent inference.
200
+
201
+ ```
202
+ Step 1: Flag concepts Step 2: Keyword query Step 3: Validate
203
+ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
204
+ │ Recent messages │──Haiku──│ Concept keywords │──DB──│ Candidate lessons │──Haiku──│ Relevant only │
205
+ │ → "What concepts │ │ ["RFC", "auth"] │ │ (top 20 by conf.) │ │ (filtered IDs)│
206
+ │ need background │ └──────────────────┘ └──────────────────┘ └───────────────┘
207
+ │ knowledge?" │
208
+ └──────────────────┘
209
+ ```
210
+
211
+ - Steps 1 and 3 use Haiku (~$0.001 each)
212
+ - Step 2 is mechanical keyword matching (no LLM call)
213
+ - Results cached by context hash — skips entirely if conversation hasn't changed
214
+ - Fails open: on error, returns empty (never blocks inference)
215
+ - Short-circuits: if only 3 or fewer candidates, skips validation step
216
+
217
+ ### Session Manager (`session-manager.ts`)
218
+
219
+ Each session is an isolated Chronicle store under `{dataDir}/sessions/{id}/`. A JSON index (`sessions.json`) tracks metadata.
220
+
221
+ **Features**: create, delete, rename, switch, find (by name or ID prefix), legacy store migration.
222
+
223
+ ### Synesthete (`synesthete.ts`)
224
+
225
+ Auto-generates session names via a Haiku call after the 3rd user message. Produces 2–4 word names. Recipe can provide naming examples to steer the style.
226
+
227
+ ### Slash Commands (`commands.ts`)
228
+
229
+ | Command | Effect |
230
+ |---------|--------|
231
+ | `/help` | List all commands |
232
+ | `/quit`, `/q` | Exit |
233
+ | `/status` | Agent state, branch, queue depth |
234
+ | `/clear` | Clear conversation display |
235
+ | `/lessons` | Show lesson library sorted by confidence |
236
+ | `/undo` | Branch at the message before the last agent turn, switch to it |
237
+ | `/redo` | Pop from redo stack, switch back |
238
+ | `/checkpoint <name>` | Save `(branchId, branchName)` as named point |
239
+ | `/restore <name>` | Switch to checkpoint's branch |
240
+ | `/branches` | List all Chronicle branches with head positions |
241
+ | `/checkout <name>` | Switch to named branch |
242
+ | `/history` | Show last 20 messages in summary form |
243
+ | `/mcp list` | List MCPL servers from `mcpl-servers.json` |
244
+ | `/mcp add <id> <cmd> [args...]` | Add or overwrite a server |
245
+ | `/mcp remove <id>` | Remove a server |
246
+ | `/mcp env <id> KEY=VALUE [...]` | Set env vars on a server |
247
+ | `/budget [tokens]` | Show/set stream token budget (e.g. `/budget 150k`, `/budget 1m`) |
248
+ | `/session` | Show current session |
249
+ | `/session list` | List all sessions |
250
+ | `/session new [name]` | Create and switch to new session |
251
+ | `/session switch <name>` | Switch to session (by name or ID) |
252
+ | `/session rename <name>` | Rename current session |
253
+ | `/session delete <name>` | Delete a session |
254
+ | `/recipe` | Show current recipe info |
255
+ | `/newtopic [context]` | Reset head window (auto-summarize or with user context) |
256
+ | `/usage` | Show session token usage and cost breakdown |
257
+
258
+ ## Framework Integration
259
+
260
+ The app runs on the `mcpl-first-class` branch of the Agent Framework, which embeds MCPL server management directly in the framework core.
261
+
262
+ **Key AF extensions used**:
263
+ - `createEphemeralAgent()` — creates an agent + context manager with an isolated temp Chronicle store; returns a cleanup function
264
+ - `runEphemeralToCompletion()` — temporarily registers an ephemeral agent in the framework's agent map, triggers inference through the normal event loop (full trace events, logging, tool dispatch), resolves when the agent returns to idle
265
+ - `executeToolCall()` — routes tool calls to module registry or MCPL servers (used by subagents to access tools)
266
+ - `KnowledgeStrategy` — context strategy used for subagent fork/spawn context (from `@connectome/agent-framework`)
267
+
268
+ **Configuration** is recipe-driven — see `createFramework()` in `index.ts`. The framework factory:
269
+ 1. Builds the module list based on recipe toggles (subagent, lessons, retrieval, workspace)
270
+ 2. Merges recipe MCP servers with `mcpl-servers.json` (file wins)
271
+ 3. Configures EventGate via `GateOptions` (file-based, per-session)
272
+ 4. Selects context strategy from recipe (`autobiographical` or `passthrough`, defaults to autobiographical)
273
+
274
+ ## Environment
275
+
276
+ ```
277
+ ANTHROPIC_API_KEY Required. API key for Membrane.
278
+ MODEL Override model for the main agent. Default: from recipe or claude-opus-4-6
279
+ DATA_DIR Data directory for sessions and recipes. Default: ./data
280
+ ```
281
+
282
+ ## Runtime
283
+
284
+ **Bun** (not Node.js). OpenTUI's native Zig core requires Bun. Chronicle's N-API bindings are validated under Bun (56 tests in `bun-compat/`).
285
+
286
+ ## Running
287
+
288
+ ```bash
289
+ # Interactive TUI (requires TTY)
290
+ bun src/index.ts
291
+
292
+ # Load a recipe
293
+ bun src/index.ts recipes/zulip-miner.json
294
+
295
+ # Piped mode (CI / testing)
296
+ echo -e "/help\n/status\n/quit" | bun src/index.ts
297
+
298
+ # Dev mode with watch
299
+ bun --watch src/index.ts
300
+ ```
301
+
302
+ ## Dependencies
303
+
304
+ | Package | Source |
305
+ |---------|--------|
306
+ | `@connectome/agent-framework` | `../agent-framework` (local) |
307
+ | `@connectome/context-manager` | `../context-manager` (local) |
308
+ | `chronicle` | `../chronicle` (Rust + N-API bindings, local) |
309
+ | `membrane` | `../membrane` (local) |
310
+ | `@opentui/core` | npm (native Zig terminal UI, powers OpenCode) |
311
+
312
+ ## Roadmap
313
+
314
+ ### 1. TUI rework for branch operations
315
+ The TUI is imperative (OpenTUI) and builds display state incrementally from trace events. After a Chronicle branch switch (undo/redo/checkpoint restore), the display stays stale — it doesn't re-query the store. Needs:
316
+ - A `refreshFromStore()` path that clears the conversation view and reloads from `queryMessages()` without tearing down the framework
317
+ - Called after any branch operation (`/undo`, `/redo`, `/restore`, `/branch switch`)
318
+ - Preserve branch-independent state (view mode, expanded nodes, layout) while rebuilding message display
319
+
320
+ ### 2. Hierarchical compression in AutobiographicalStrategy
321
+ The context-manager's `AutobiographicalStrategy` currently does single-level compression (raw → diary). Upgrade to moltbot-style 3-level pyramid:
322
+ - **Merge logic in `tick()`**: when N unmerged summaries accumulate at level K, merge into one at level K+1
323
+ - **Anti-redundancy in `select()`**: exclude a summary if all its children are expanded at the level below
324
+ - **Budget carryover**: unused token budget at higher levels flows down (L3 → L2 → L1)
325
+ - **Self-voice framing**: summaries injected as assistant messages (the model's own recollections), not Q&A pairs
326
+ - **Source range tracking**: each compressed chunk records which message sequences it covers (Chronicle is lossless, but we need the mapping)
327
+
328
+ ### 3. Domain-specific context strategies
329
+ Recipe-aware compression strategies that understand domain semantics. For example, a knowledge extraction strategy that prioritizes lesson-relevant messages, research leads, and synthesis differently from generic conversation. Builds on top of the hierarchical compression work.
330
+
331
+ ### 4. Undo/redo at the framework level
332
+ Currently each app builds its own undo/redo on top of Chronicle branching. Should be a first-class framework feature:
333
+ - Auto-record the Chronicle sequence number before each inference turn
334
+ - Expose `undoLastTurn(agentName)` / `redo()` on `AgentFramework`
335
+ - Branch at the recorded sequence, switch to the new branch
336
+ - Emit trace events so TUI/UI layers know to refresh
337
+
338
+ ### 5. MCPL integration depth
339
+ connectome-host has config-level MCPL support and wake subscriptions, but deeper integration is needed:
340
+ - Visibility into MCPL server status and activity in the TUI
341
+ - MCPL-triggered inference distinguished from user-triggered in the conversation view
342
+ - Interaction model for how MCPL-pushed content appears and is handled
343
+
344
+ ## TUI Evolution
345
+
346
+ 1. **Ink/React** — first attempt, clunky rendering, interleaved output
347
+ 2. **Custom ANSI** — raw escape sequences, cursor tracking; fixed interleave but letters disappeared during typing
348
+ 3. **OpenTUI** — production-quality terminal rendering (Zig core), handles cursor/input/scroll natively
349
+
350
+ ## Gotchas
351
+
352
+ - **`TextRenderable.content` is a `StyledText` object**, not a string. Using `+=` silently breaks (stringifies as `[object Object]`). Always track text in a plain string buffer and assign the full string via `=`.
353
+ - **Bun auto-loads `.env`** — no `dotenv` package needed.
354
+ - **`child_process.spawn`** works in Bun (needed for MCPL server connections).
355
+ - **Tool name separator**: module tools use `--` separator (e.g. `subagent--fork`, `wake--subscribe`), not `:`.
package/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Breaking (recipe authors only)
6
+
7
+ - `modules.fleet.children[].recipe` paths now resolve at recipe-load time
8
+ against the **directory of the parent recipe file** (or URL base) rather
9
+ than `process.cwd()`. Absolute paths and `http(s)://` URLs pass through
10
+ unchanged. This makes recipe bundles portable: a parent file and its
11
+ sibling children can live anywhere on disk and be launched from any CWD.
12
+
13
+ **Who needs to act**: anyone maintaining a forked or custom
14
+ triumvirate-style recipe that hard-codes child paths with a `recipes/`
15
+ prefix (or any prefix anchored at `connectome-host/`'s CWD). After
16
+ upgrade, `"recipes/knowledge-miner.json"` inside
17
+ `<somewhere>/my-recipe.json` resolves to
18
+ `<somewhere>/recipes/knowledge-miner.json`, which is almost certainly
19
+ not what's intended.
20
+
21
+ **Migration**: drop the `recipes/` prefix so the child is referenced as a
22
+ sibling of the parent file (e.g. `"knowledge-miner.json"` or
23
+ `"./knowledge-miner.json"`). No files need to move on disk. The
24
+ in-tree `recipes/triumvirate.json` has already been updated.
25
+
26
+ **Unchanged**: `dataDir`, workspace mount paths, and child process CWD
27
+ stay CWD-relative (these are runtime paths, not authoring references).
28
+ `fleet--launch` invocations from the conductor are still matched
29
+ CWD-relative at dispatch time, so existing system prompts that document
30
+ CWD-relative paths continue to work.