-
Notifications
You must be signed in to change notification settings - Fork 1
Feature: Multi Host
Thatch runs as both an opencode plugin and an MCP server for Claude Code and
Cursor. Three integration paths share a common core---the tool definitions in
src/tool-defs.ts---but differ in how they deliver system prompts, prefix tool
names, and handle session lifecycle events.
Thatch supports three host agents from a single codebase:
-
opencode plugin---in-process, direct event hooks, warm embedding model,
thatch_tool prefix -
Claude Code MCP---stdio MCP server, external CLI hooks,
mcp__thatch__tool prefix, system prompt in CLAUDE.md -
Cursor MCP---same stdio MCP server,
--jsonhook output format,mcp__thatch__tool prefix, system prompt in AGENTS.md
All three paths share the tool definitions from src/tool-defs.ts: the
host-agnostic tools plus the opencode-only tools, which the MCP server
filters out. The opencode-only set covers host-session capabilities MCP
hosts lack: get_session_info, session_search/session_get (no session
concept or session database), the watch_create/watch_branch_create/
watch_command_create/watch_list/watch_cancel watcher tools (no
poller or proactive-prompt
channel), and the chat_register/chat_list/chat_send/chat_read/
chat_unregister/chat_broadcast chat tools (no session identity or
wake-up channel). The
shared tools take args and a CoreContext
({ db, model, defaultStore }) and return a string. The host-specific
wrapping---prefixing, transport, session hooks---lives outside the core.
Runs inside opencode's Bun runtime as a loaded plugin. No setup command is
needed---opencode discovers the plugin from opencode.json and loads it at
startup.
System prompt: injected at runtime via the
experimental.chat.system.transform hook. The hook calls systemPrompt(repo)
and pushes the result into output.system every turn. No files are written.
The repo name is baked in at runtime, so the prompt always reflects the current
worktree. Identity detection reads the session's own directory (not just the
framework worktree) and recovers from the repo_paths cache when that
directory was deleted - see repo-identity.md.
Tools: registered through opencode's tool() wrapper in src/tools.ts,
which adds the thatch_ prefix. The agent sees thatch_memory_remember,
thatch_memory_recall, etc.
Skills: installed to $XDG_CONFIG_HOME/opencode/skills at plugin init.
Both the shared skill array and the opencode-only skill array are installed.
See ../skills.md for the skill system.
Capabilities unique to this path:
- Full access to plugin hooks: system prompt injection, session events, tool buffering, compaction context
- TUI toast notifications---best-effort, silently ignored in headless mode
- Direct extraction via child sessions (see session-lifecycle.md)
- Compaction recovery (see compaction-recovery.md)
- Background sub-agents (experimental)---the code-review coordinator dispatches specialist sub-agents through opencode's agent infrastructure
Runs as a stdio JSON-RPC 2.0 process spawned by Claude Code. The MCP server
exposes tools via tools/list and tools/call. It is long-lived for the
session duration, keeping the embedding model warm in memory.
System prompt: static text appended to CLAUDE.md by
thatch setup --claude. The text is written between marker constants
(THATCH_MARKER / THATCH_END_MARKER) using the appendBlock helper in
src/setup.ts. The block is idempotent---re-running setup replaces the content
between the markers rather than duplicating it. Claude Code loads CLAUDE.md
at session start.
Tools: the MCP server exposes bare names (memory_remember,
memory_recall). Claude Code's MCP client applies the mcp__thatch__ prefix,
so the agent sees mcp__thatch__memory_remember. Thatch itself does not apply
this prefix.
Skills: installed to the scope's skills dir (repo .claude/skills/ for
project-local setup, $CLAUDE_CONFIG_DIR/skills/ for --global)---shared
skills only. The code-review coordinator skill is opencode-only because it
requires sub-agent dispatch, which Claude Code does not support.
Session behavior: driven by external CLI hook processes (bin/thatch).
The hooks are registered in .claude/settings.json during setup. Each hook
spawns a short-lived thatch process that communicates with the long-lived MCP
server via the sideband socket (see sideband.md) for warm-model
access. This avoids loading the ~34 MB embedding model in every one-shot hook
process.
Setup: thatch setup --claude writes .mcp.json (server config),
CLAUDE.md (instructions block), .claude/settings.json (hooks), and
installs skills. See setup.md for the setup system.
The same stdio MCP server as Claude Code. The differences are in hook format, system prompt file, and tool batching granularity.
System prompt: static text appended to AGENTS.md by
thatch setup --cursor, using the same appendBlock helper and marker pair.
Cursor loads AGENTS.md at session start.
Tools: same bare names over MCP, same mcp__thatch__ prefix applied by
Cursor's MCP client.
Skills: installed to $CURSOR_CONFIG_DIR/skills/---shared skills only.
Session behavior: driven by Cursor hooks in flat hooks.json format
(.cursor/hooks.json). Hook output uses the --json flag, producing
{ additional_context: "..." } objects that Cursor injects into the agent's
context. The postToolUse hook fires per-tool---there is no batch equivalent
of Claude Code's PostToolBatch. Tool buffering uses thatch buffer-tool on
each individual tool call. Cursor uses conversation_id instead of
session_id for session tracking.
Setup: thatch setup --cursor writes .cursor/mcp.json, AGENTS.md,
.cursor/hooks.json, and installs skills.
Three mechanisms, one per host. The prompt functions all live in
src/prompts.ts.
-
opencode: the
experimental.chat.system.transformhook callssystemPrompt(repo)and pushes the result intooutput.systemat runtime. No files are written. The prompt is generated fresh every turn. -
Claude Code:
claudeInstructions()produces the text thatthatch setup --claudeappends toCLAUDE.mdbetweenTHATCH_MARKER/THATCH_END_MARKER. The file is loaded once at session start by Claude Code. -
Cursor:
cursorInstructions()produces the text thatthatch setup --cursorappends toAGENTS.mdbetween the same markers. Loaded once at session start by Cursor.
The three prompt functions are near-identical. They differ only in host name
string, config file reference (OPENCODE.md / CLAUDE.md / AGENTS.md), and
tool name prefix in the tool list line. Their shared prose sections---"When to
Write", "What NOT to Store", "Before Responding", "Stores", "Skills"---are
verbatim copies with these token substitutions.
There is no single-source-of-truth template that generates all three. Each
variant is an independent string constant in src/prompts.ts. Editing shared
prose in one variant requires mirroring the edit in the other two, or the
variants silently drift.
The tool list line in all three prompts must be kept in sync with
TOOL_DEFS in src/tool-defs.ts. The historical failure mode: a tool is added
to TOOL_DEFS but only two of the three prompt functions are updated, creating
an asymmetry a reviewer can catch by diffing the tool lines.
The tool definitions in src/tool-defs.ts use bare names:
memory_remember, memory_recall, memory_list, etc. Each host applies its
own prefix.
| Host | Prefix | Applied by | Example |
|---|---|---|---|
| opencode | thatch_ |
tool() wrapper in src/tools.ts
|
thatch_memory_remember |
| Claude Code | mcp__thatch__ |
Claude Code's MCP client | mcp__thatch__memory_remember |
| Cursor | mcp__thatch__ |
Cursor's MCP client | mcp__thatch__memory_remember |
The MCP server (src/mcp.ts) always exposes bare names. The
mcp__thatch__ prefix is a convention of the MCP client, not of thatch.
The opencode prefix is applied in-process by the tool() wrapper.
Not all features are available on all hosts. The opencode plugin has direct access to session events, child sessions, and compaction hooks. The MCP hosts rely on external hook processes and the sideband socket for equivalent behavior, with some features having no MCP counterpart.
| Feature | opencode | Claude Code | Cursor |
|---|---|---|---|
| Direct extraction (child sessions) | Yes | No | No |
| Compaction recovery | Yes | No | No |
| TUI toast notifications | Yes | No | No |
| Sideband socket | No (in-process) | Yes | Yes |
| code-review coordinator skill | Yes | No | No |
| Background sub-agents | Yes (experimental) | No | No |
| Tool batching | N/A (in-process) | PostToolBatch (batch) | postToolUse (per-tool) |
get_session_info (session identity) |
Yes | No | No |
session_search / session_get (conversation archaeology) |
Yes (tools) | CLI only (thatch session ...) |
CLI only (thatch session ...) |
watch_* (PR, branch, and command watchers) |
Yes (tools) | No | No |
chat_* (cross-session chat) |
Yes (wake on delivery) | Yes (mail at prompt time) | Yes (mail at prompt time) |
For the full parity matrix, see ../mcp-parity.md.
The shared tools are available on all hosts via the single source of truth
in src/tool-defs.ts; opencode-only tools (e.g. get_session_info) are
filtered out by the MCP server. Individual tool behavior is documented in
memory-store.md, extraction.md,
prediction-engine.md,
behavior-engine.md, and
deduplication.md.
The nudge pipeline (see nudge-pipeline.md) runs in-process for opencode. For MCP hosts, it runs via the sideband socket---hook processes query the long-lived MCP server for memory matches, predictions, and behavior nudges through a Unix domain socket. See sideband.md for the socket protocol.
The extraction pipeline (see extraction.md) uses an in-memory ring buffer for opencode. For MCP hosts, it uses a file-backed JSONL queue that hook processes append to and the MCP server drains.
The setup system (see setup.md) handles Claude Code and Cursor installation. opencode auto-installs skills and injects the system prompt at plugin init---no setup command is needed.
Skills (see ../skills.md) install both the shared and opencode-only arrays for opencode. MCP hosts receive shared skills only, since the opencode-only skills require sub-agent dispatch or in-process hooks.
| File | Role |
|---|---|
src/index.ts |
dual-shape plugin entry (merged default export loads on opencode v1 and v2) |
src/opencode/v1.ts + src/opencode/v2.ts
|
host adapters: hooks (v1) vs promise-context domains (v2) |
src/runtime.ts |
shared plugin runtime: nudges, system prompt injection, session events |
src/mcp.ts |
MCP server (shared by Claude Code and Cursor)---stdio JSON-RPC, tool dispatch |
src/setup.ts |
Setup installer for Claude Code and Cursor---markers, hooks, skills |
src/prompts.ts |
All three system prompt variants---systemPrompt(), claudeInstructions(), cursorInstructions()
|
src/tools.ts |
Thin opencode tool wrappers---imports tool-defs, adds thatch_ prefix via tool()
|
src/tool-defs.ts |
Single source of truth for all tool definitions---name, description, zod schema, execute, opencodeOnly flag |
bin/thatch |
CLI hook commands for MCP hosts---reminder, buffer-tool, flush-tools, setup
|
- All hosts share the tool definitions from
src/tool-defs.ts(shared tools plus opencode-only tools markedopencodeOnly: true, which the MCP server filters out). Adding a tool requires updatingTOOL_DEFSand all three prompt functions; opencode-only tools go in the opencode prompt only. - The MCP server always exposes bare names. The
mcp__thatch__prefix is applied by the MCP client, not thatch. - The three system prompt variants are independent string constants in
src/prompts.tswith no shared template. Editing shared prose in one requires mirroring in the other two, or they drift. - The tool list line in all three prompts must match
TOOL_DEFSinsrc/tool-defs.ts(opencode's list includes opencode-only tools; the MCP lists exclude them). The historical failure mode: a tool is added toTOOL_DEFSbut only two of three prompts are updated. - opencode-only features (direct extraction, compaction recovery, code-review coordinator, background sub-agents, TUI toasts,
get_session_info,session_search/session_get, all watchers (PR, branch, and command), cross-session chat wake-up) have no MCP counterpart. Thethatch sessionCLI subcommands work anywhere - they only need an opencode.db file to read.
User
- Guide: Behavior Engine
- Guide: Cli
- Guide: Code Review
- Guide: Commands
- Guide: Cross Session Chat
- Guide: Deduplication
- Guide: Default Behaviors
- Guide: Extraction
- Guide: Hygiene
- Guide: Memory
- Guide: Notifications
- Guide: Prediction Engine
- Guide: Overview
- Guide: Setup
- Guide: Skills
- Guide: Watchers
Developer
Dev Feature Guides
- Feature: Behavior Engine
- Feature: Cicd
- Feature: Cli
- Feature: Commands
- Feature: Compaction Recovery
- Feature: Cross Session Chat
- Feature: Database
- Feature: Deduplication
- Feature: Extraction
- Feature: Hygiene
- Feature: Memory Store
- Feature: Multi Host
- Feature: Notifications
- Feature: Nudge Pipeline
- Feature: Opencode Plugin
- Feature: Prediction Engine
- Feature: Qa System
- Feature: Overview
- Feature: Repo Identity
- Feature: Session Lifecycle
- Feature: Setup
- Feature: Sideband
- Feature: Watchers