@jeffober/thatch 0.1.28 → 0.1.29

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 (60) hide show
  1. package/README.md +24 -10
  2. package/artifacts/skills/thatch-code-review.md +9 -7
  3. package/artifacts/skills/thatch-review-economy.md +97 -0
  4. package/artifacts/skills/thatch-review-followup.md +1 -1
  5. package/artifacts/skills/thatch-review-synthesizer.md +15 -5
  6. package/bin/qa-run +38 -0
  7. package/bin/thatch +10 -5
  8. package/docs/dev/README.md +71 -18
  9. package/docs/dev/features/README.md +33 -0
  10. package/docs/dev/features/behavior-engine.md +271 -0
  11. package/docs/dev/features/cicd.md +89 -0
  12. package/docs/dev/features/cli.md +81 -0
  13. package/docs/dev/features/compaction-recovery.md +48 -0
  14. package/docs/dev/features/database.md +244 -0
  15. package/docs/dev/features/deduplication.md +102 -0
  16. package/docs/dev/features/extraction.md +253 -0
  17. package/docs/dev/features/hygiene.md +81 -0
  18. package/docs/dev/features/memory-store.md +154 -0
  19. package/docs/dev/features/multi-host.md +228 -0
  20. package/docs/dev/features/nudge-pipeline.md +282 -0
  21. package/docs/dev/features/prediction-engine.md +253 -0
  22. package/docs/dev/features/qa-system.md +205 -0
  23. package/docs/dev/features/session-lifecycle.md +110 -0
  24. package/docs/dev/features/setup.md +199 -0
  25. package/docs/dev/features/sideband.md +104 -0
  26. package/docs/dev/gotchas.md +3 -3
  27. package/docs/dev/mcp-parity.md +6 -4
  28. package/docs/dev/setup-and-hooks.md +4 -4
  29. package/docs/dev/skills.md +10 -8
  30. package/docs/plans/README.md +2 -2
  31. package/docs/user/README.md +58 -20
  32. package/docs/user/behavior-engine.md +85 -0
  33. package/docs/user/cli.md +98 -0
  34. package/docs/user/code-review.md +73 -0
  35. package/docs/user/deduplication.md +70 -0
  36. package/docs/user/default-behaviors.md +75 -0
  37. package/docs/user/extraction.md +74 -0
  38. package/docs/user/hygiene.md +76 -0
  39. package/docs/user/memory.md +81 -0
  40. package/docs/user/prediction-engine.md +87 -0
  41. package/docs/user/setup.md +110 -0
  42. package/docs/user/skills.md +97 -0
  43. package/package.json +2 -2
  44. package/src/behavior.ts +120 -0
  45. package/src/db.ts +160 -417
  46. package/src/embeddings.ts +0 -41
  47. package/src/extraction.ts +2 -2
  48. package/src/git.ts +3 -1
  49. package/src/index.ts +55 -9
  50. package/src/mcp.ts +30 -1
  51. package/src/prediction.ts +127 -0
  52. package/src/prompts.ts +135 -188
  53. package/src/scoring-engine.ts +374 -0
  54. package/src/seed-behaviors.ts +339 -0
  55. package/src/setup.ts +2 -6
  56. package/src/sideband.ts +36 -8
  57. package/src/skills.ts +1 -0
  58. package/src/tool-defs.ts +172 -25
  59. package/src/vector-math.ts +30 -0
  60. package/docs/qa/README.md +0 -175
@@ -0,0 +1,199 @@
1
+ # Setup System
2
+
3
+ Installs thatch into Claude Code and Cursor. opencode does not need setup --- it
4
+ auto-installs skills and injects the system prompt at plugin init. All setup
5
+ operations are idempotent: re-running updates drifted content without clobbering
6
+ unrelated config.
7
+
8
+ For the concrete artifact paths and hook event tables each host writes, see
9
+ [../setup-and-hooks.md](../setup-and-hooks.md). This doc covers the architecture:
10
+ how setup commands, the marker system, detection, auto-refresh, and binary
11
+ resolution fit together.
12
+
13
+ ## What it does
14
+
15
+ - `thatch setup --claude` --- installs MCP config, CLAUDE.md instructions,
16
+ hooks, and skills for Claude Code
17
+ - `thatch setup --cursor` --- installs MCP config, AGENTS.md instructions,
18
+ hooks, and skills for Cursor
19
+ - `--global` flag --- installs to user-scoped config dirs instead of
20
+ project-local
21
+ - **Marker system** --- idempotent replacement of the thatch instruction block
22
+ in `CLAUDE.md` or `AGENTS.md` via start/end markers
23
+ - **`checkSetup`** --- detects installed, not-installed, or markers-broken at
24
+ MCP server startup
25
+ - **Auto-refresh** --- MCP server re-runs setup on startup if installed,
26
+ updating drifted content
27
+ - **Setup warning surfacing** --- first `tools/call` response prepends a
28
+ warning if setup was not run
29
+ - **Binary resolution** --- uses bare `thatch` if on PATH (survives updates),
30
+ else the absolute path to the running script
31
+
32
+ ## How it works
33
+
34
+ ### Setup commands
35
+
36
+ At least one of `--claude` or `--cursor` is required. Both can be passed
37
+ together. `--global` applies to whichever host or hosts are selected.
38
+
39
+ ### Claude Code setup (`setupClaudeCode` in `src/setup.ts`)
40
+
41
+ Four artifacts, all idempotent:
42
+
43
+ 1. **MCP config** --- project-local writes `.mcp.json` with a stdio thatch
44
+ MCP server entry. Global prints a `claude mcp add --scope user thatch --
45
+ <bin> mcp` command for the user to run (does not write a file, because
46
+ `~/.claude.json` is too complex to write directly).
47
+ 2. **Instructions** --- appends `claudeInstructions()` to `CLAUDE.md` between
48
+ start and end markers (`THATCH_MARKER` / `THATCH_END_MARKER`). Project-local:
49
+ `<projectDir>/CLAUDE.md`. Global: `$CLAUDE_CONFIG_DIR/CLAUDE.md`.
50
+ 3. **Hooks** --- writes to `.claude/settings.json` (project) or
51
+ `$CLAUDE_CONFIG_DIR/settings.json` (global). Three hooks: `SessionStart`
52
+ → `thatch reminder`, `PostToolBatch` → `thatch buffer-batch`,
53
+ `UserPromptSubmit` → `thatch flush-tools`. Nested format:
54
+ `{hooks:{Event:{hooks:[{type,command}]}}}`.
55
+ 4. **Skills** --- installs to `$CLAUDE_CONFIG_DIR/skills/` (always
56
+ user-scoped, even for project-local setup). `SHARED_SKILLS` only --- the
57
+ code-review coordinator requires sub-agent dispatch, which Claude Code
58
+ does not support.
59
+
60
+ ### Cursor setup (`setupCursor` in `src/setup.ts`)
61
+
62
+ Four artifacts, same idempotent pattern:
63
+
64
+ 1. **MCP config** --- writes `.cursor/mcp.json` (project) or
65
+ `$CURSOR_CONFIG_DIR/mcp.json` (global). Same JSON shape as Claude Code.
66
+ No `claude mcp add` equivalent needed --- Cursor reads the config file
67
+ directly.
68
+ 2. **Instructions** --- appends `cursorInstructions()` to `AGENTS.md` between
69
+ markers (`CURSOR_MARKER` / `CURSOR_END_MARKER`). Project-local:
70
+ `<projectDir>/AGENTS.md`. Global: `$CURSOR_CONFIG_DIR/AGENTS.md`.
71
+ 3. **Hooks** --- writes to `.cursor/hooks.json` (project) or
72
+ `$CURSOR_CONFIG_DIR/hooks.json` (global). Flat format:
73
+ `{version:1, hooks:{event:[{command}]}}`. Three hooks: `sessionStart`
74
+ → `thatch reminder --json`, `postToolUse` → `thatch buffer-tool`,
75
+ `beforeSubmitPrompt` → `thatch flush-tools --json`.
76
+ 4. **Skills** --- installs to `$CURSOR_CONFIG_DIR/skills/` (shared only).
77
+
78
+ ### Marker system (`appendBlock`)
79
+
80
+ `appendBlock(path, instructions, startMarker, endMarker)` handles three cases:
81
+
82
+ 1. **Both markers found** --- replace content between them. Preserve text
83
+ before the start marker and after the end marker. This is the normal
84
+ update path: re-running setup replaces the thatch block without touching
85
+ user-written content elsewhere in the file.
86
+ 2. **Start marker found but end missing** --- leave the file alone. This is a
87
+ corrupted state --- someone edited the file and accidentally removed the
88
+ end marker. Writing would risk clobbering content that follows the start
89
+ marker. `checkSetup` reports this as `markers-broken`.
90
+ 3. **No markers** --- append instructions to the end of the file (with a
91
+ separator). Create the file if it does not exist.
92
+
93
+ Start markers differ by host (the text says "Claude Code" or "Cursor"). The end
94
+ marker is shared.
95
+
96
+ ### `checkSetup` (`src/setup.ts`)
97
+
98
+ Detects the host from environment variables set by the host process:
99
+
100
+ - `CURSOR_PROJECT_DIR` set → Cursor
101
+ - `CLAUDE_PROJECT_DIR` set (and Cursor not) → Claude Code
102
+ - Neither set → returns `null` (manual `thatch mcp` invocation, no check)
103
+
104
+ Cursor takes priority because Cursor also sets `CLAUDE_PROJECT_DIR` as an
105
+ alias. Without the priority check, Cursor sessions would be misidentified as
106
+ Claude Code.
107
+
108
+ `checkSetup` looks for start and end markers in the host's instructions file
109
+ --- `CLAUDE.md` for Claude Code, `AGENTS.md` for Cursor. It checks local first,
110
+ then global. Local takes priority.
111
+
112
+ | Outcome | Condition | Action |
113
+ |---------|-----------|--------|
114
+ | **installed** | Both markers found (local or global) | No warning |
115
+ | **not-installed** | No instructions file with markers | Warning surfaced on first `tools/call` |
116
+ | **markers-broken** | Start marker found, end marker missing | Warning with file path and fix instructions |
117
+
118
+ ### Auto-refresh at MCP startup
119
+
120
+ If `checkSetup` returns `installed`, the MCP server re-runs `setupClaudeCode`
121
+ or `setupCursor` with the same scope. This updates skills, instructions, and
122
+ hooks that drifted since the last `thatch setup`. All operations are
123
+ idempotent --- they only write when content differs. Failure is best-effort
124
+ and logged to stderr.
125
+
126
+ This is how installations stay current without the user manually re-running
127
+ setup after upgrading thatch. The next MCP session picks up new skill content,
128
+ updated instructions, and any hook changes automatically.
129
+
130
+ ### Setup warning surfacing
131
+
132
+ On the first `tools/call` response, if a setup warning exists, the server
133
+ prepends `[thatch] {warning}` to the tool's text output. The agent sees it
134
+ and can tell the user to run `thatch setup`. The warning is cleared after one
135
+ surfacing so it does not repeat on every tool call.
136
+
137
+ ### Binary resolution
138
+
139
+ Setup resolves the thatch binary via `Bun.which("thatch")`. If `thatch` is on
140
+ `PATH` (npm global install, opencode plugin install), it uses the bare name.
141
+ This survives updates --- the resolved path points to whatever `thatch` is
142
+ current at hook execution time, not a stale absolute path.
143
+
144
+ If `thatch` is not on `PATH`, setup falls back to the absolute path of the
145
+ running script. This handles one-off invocations (e.g., `bun run bin/thatch
146
+ setup --claude`).
147
+
148
+ The resolved binary is baked into every installed hook command. Hooks are
149
+ short-lived processes spawned by the host after the setup session ends, so
150
+ they cannot rely on the original process's environment. The baked-in path
151
+ ensures hooks keep working across sessions.
152
+
153
+ ### Hook replacement
154
+
155
+ `replaceThatchHooks` / `replaceCursorThatchHooks` filter out any existing hook
156
+ group whose `command` contains the string `thatch`, then add the current
157
+ ones. Non-thatch hooks are preserved. This handles legacy hooks --- for
158
+ example, an older `thatch echo` hook is replaced with the current
159
+ `flush-tools` hook without touching hooks from other tools.
160
+
161
+ ## Interactions with other features
162
+
163
+ - [Multi-host](multi-host.md) --- setup is the installation mechanism for
164
+ Claude Code and Cursor. opencode auto-installs at plugin init.
165
+ - [Skills](../skills.md) --- setup installs skills as part of the install.
166
+ Skill content is plugin-owned and overwritten on drift.
167
+ - [Nudge pipeline](nudge-pipeline.md) --- setup installs the hooks that drive
168
+ the nudge pipeline for MCP hosts.
169
+ - [Extraction](extraction.md) --- setup installs the `buffer-batch` /
170
+ `buffer-tool` hooks that feed the file-backed extraction queue.
171
+ - [Sideband](sideband.md) --- setup installs `flush-tools`, which connects to
172
+ the sideband socket for warm-model access during nudge evaluation.
173
+
174
+ ## Source files
175
+
176
+ | File | Role |
177
+ |------|------|
178
+ | `src/setup.ts` | `setupClaudeCode`, `setupCursor`, `checkSetup`, `appendBlock`, marker definitions, hook replacement |
179
+ | `bin/thatch` | `setup` subcommand --- parses flags, dispatches to `setupClaudeCode` / `setupCursor` |
180
+ | `src/prompts.ts` | `claudeInstructions`, `cursorInstructions` --- the instruction text appended to `CLAUDE.md` / `AGENTS.md` |
181
+
182
+ ## Key invariants
183
+
184
+ 1. **All operations are idempotent.** Re-running setup updates drifted content
185
+ without clobbering. Instructions use markers, hooks filter by `thatch`
186
+ string, MCP config preserves existing servers, skills diff before writing.
187
+ 2. **Skills are always user-scoped**, even in project-local setup. Claude Code
188
+ and Cursor load skills from the user config dir, not the project.
189
+ 3. **`appendBlock` leaves content alone if markers do not parse.** A start
190
+ marker without an end marker means the file was edited externally. Writing
191
+ would risk clobbering content after the start marker.
192
+ 4. **Binary path is baked into hook commands.** Hooks are short-lived
193
+ processes that outlive the setup session. The resolved path ensures they
194
+ keep working.
195
+ 5. **Non-thatch hooks are preserved during hook replacement.** Only hooks
196
+ whose `command` contains `thatch` are filtered out.
197
+ 6. **Auto-refresh keeps installations current.** The MCP server re-runs
198
+ setup on startup if markers are present, picking up new skills and
199
+ updated instructions without manual intervention.
@@ -0,0 +1,104 @@
1
+ # Sideband IPC (MCP Hosts)
2
+
3
+ A Unix domain socket server that lets one-shot hook processes borrow the MCP server's warm embedding model. Without this, each hook invocation would load the ~34 MB model from scratch, adding 300-700 ms to every prompt.
4
+
5
+ ## What it does
6
+
7
+ - Unix domain socket at a deterministic path derived from the DB path
8
+ - Three request methods: match (recall), predictions, behaviors
9
+ - One embedding round-trip per request (all three methods share the model)
10
+ - 2-second timeout, null on failure (callers skip the nudge gracefully)
11
+ - Stale socket cleanup on connection error
12
+
13
+ ## How it works
14
+
15
+ ### The problem it solves
16
+
17
+ Claude Code and Cursor spawn a fresh process for each hook invocation (`thatch flush-tools`, `thatch reminder`). These processes need the embedding model to embed the user's prompt for the recall/prediction/behavior nudges. Loading the ~34 MB model on every prompt would add unacceptable latency.
18
+
19
+ The MCP server is long-lived (kept alive by the host's stdio connection) and has the model warm in memory. The sideband socket lets hook processes ask the warm server to do the embedding work.
20
+
21
+ ### Socket path
22
+
23
+ The path is derived from a SHA-256 hash of the DB path (first 16 hex chars), under os.tmpdir():
24
+
25
+ ```text
26
+ $TMPDIR/thatch-<sha256(dbPath)[0:16]>.sock
27
+ ```
28
+
29
+ Both the MCP server and hook processes compute the same path independently (from `THATCH_DB_PATH` or the default under `XDG_CONFIG_HOME`). No out-of-band coordination needed.
30
+
31
+ Changing `THATCH_DB_PATH` moves the socket. A stale socket from a crash is cleaned up on ECONNREFUSED/ENOENT.
32
+
33
+ ### Protocol
34
+
35
+ Newline-delimited JSON. One request per connection, one response.
36
+
37
+ Request:
38
+
39
+ ```json
40
+ {"method":"match|predictions|behaviors","text":"...","stores":[...],"threshold":N,"limit":N}
41
+ ```
42
+
43
+ Response (success):
44
+
45
+ ```json
46
+ {"ok":true,"matches":[...]}
47
+ ```
48
+
49
+ ```json
50
+ {"ok":true,"predictions":[...]}
51
+ ```
52
+
53
+ ```json
54
+ {"ok":true,"behaviors":[...]}
55
+ ```
56
+
57
+ Response (failure):
58
+
59
+ ```json
60
+ {"ok":false,"error":"..."}
61
+ ```
62
+
63
+ ### Three methods
64
+
65
+ 1. **match** -- embeds text, runs `db.search` across stores, returns matches with score >= threshold as `{label, score, store}`
66
+ 2. **predictions** -- embeds text, calls `db.scorePredictionNudge`, returns scored prediction nudge items
67
+ 3. **behaviors** -- embeds text, calls `db.scoreBehaviorNudge`, returns scored behavior nudge items
68
+
69
+ ### Client helpers
70
+
71
+ - `sidebandMatch(text, stores, threshold, limit)` -- returns matches or null on failure
72
+ - `sidebandPredictions(text, stores, threshold, limit)` -- returns predictions or null
73
+ - `sidebandBehaviors(text, stores, threshold, limit)` -- returns behaviors or null
74
+
75
+ All three return null on any failure (server not running, stale socket, timeout, parse error). Callers must treat null as "skip the nudge, fall back gracefully."
76
+
77
+ ### Graceful degradation
78
+
79
+ If the socket isn't available (MCP server not running, old version, stale socket, >2s timeout), `sidebandMatch` returns null and `flush-tools` falls back to the static write nudge. The recall/prediction/behavior nudge is best-effort -- its absence never blocks the agent's workflow.
80
+
81
+ ### Server lifecycle
82
+
83
+ - Opened at MCP server startup (`src/mcp.ts`). Failure is non-fatal (only the prompt-aware recall/prediction/behavior nudge degrades).
84
+ - Closed + socket file removed on shutdown (stdin close).
85
+
86
+ ## Interactions with other features
87
+
88
+ - Nudge pipeline ([nudge-pipeline.md](nudge-pipeline.md)): MCP hosts use the sideband socket for all three nudge tiers (recall, prediction, behavior)
89
+ - Multi-host ([multi-host.md](multi-host.md)): only MCP hosts (Claude Code, Cursor) use the sideband; opencode has the model in-process
90
+ - Prediction engine ([prediction-engine.md](prediction-engine.md)): predictions method
91
+ - Behavior engine ([behavior-engine.md](behavior-engine.md)): behaviors method
92
+ - Memory store ([memory-store.md](memory-store.md)): match method uses `db.search`
93
+
94
+ ## Source files
95
+
96
+ - `src/sideband.ts` -- SidebandServer (server side) + sidebandMatch/sidebandPredictions/sidebandBehaviors (client helpers)
97
+
98
+ ## Key invariants
99
+
100
+ - Socket path = SHA-256 of DB path. Both sides compute it independently.
101
+ - Sideband failure never blocks. All client helpers return null on failure.
102
+ - One embedding per request (all three methods share the model).
103
+ - 2-second timeout default.
104
+ - Stale socket cleanup on ECONNREFUSED/ENOENT.
@@ -41,7 +41,7 @@ here first. These are the things that have already cost time.
41
41
  a memory, write it with `archived: true`; to unarchive, `archived: false`.
42
42
  - **Updating an archived memory requires explicit `archived` param.** If the
43
43
  entry is already archived and a `remember` call omits the `archived` param,
44
- the tool returns an error (`db.ts:211`). Pass `archived: true` to keep it
44
+ the tool returns an error (`db.ts:395`). Pass `archived: true` to keep it
45
45
  archived or `archived: false` to unarchive. This guard prevents accidental
46
46
  unarchival via an unrelated content update.
47
47
 
@@ -61,7 +61,7 @@ here first. These are the things that have already cost time.
61
61
  - **`chat.message` has two priority tiers**: extraction nudge first (returns
62
62
  early), then the prompt-aware recall nudge. Don't run both in one turn.
63
63
  - **The extraction nudge peeks, never flushes.** The buffer is NOT drained
64
- on nudge delivery (`index.ts:169` — `peek()` call). It persists until the
64
+ on nudge delivery (`index.ts:366` — `peek()` call). It persists until the
65
65
  agent writes a memory or calls `thatch_extraction_done`. Ignored nudges
66
66
  accumulate; the `missedNudges` counter escalates the tone (polite at 0-1
67
67
  misses, insistent at 2, ALL-CAPS at 3+). The counter resets when the
@@ -71,7 +71,7 @@ here first. These are the things that have already cost time.
71
71
  is active. The peek-not-drain semantics still hold for the fallback nudge
72
72
  path (MCP hosts and any `triggerExtraction` failure).
73
73
  - **A child sub-agent's `thatch_memory_remember` drains the parent's buffer**
74
- via the `childToParent` Map (`index.ts:65` declaration, `index.ts:131`
74
+ via the `childToParent` Map (`index.ts:79` declaration, `index.ts:272`
75
75
  lookup). Two paths reach this machinery: (a) the **plugin-initiated child
76
76
  session** — `triggerExtraction` calls `client.session.create` with a
77
77
  `parentID`, the primary opencode path; (b) the **agent-initiated background
@@ -18,7 +18,7 @@ This document maps the feature parity and documents the remaining gaps.
18
18
 
19
19
  | Feature | OpenCode plugin | Claude Code MCP + hooks | Cursor MCP + hooks | Parity |
20
20
  |---------|----------------|------------------------|---------------------|--------|
21
- | **Tools** (13, single source of truth) | Plugin tool registration, `thatch_` prefix | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix | **Full** |
21
+ | **Tools** (18, single source of truth) | Plugin tool registration, `thatch_` prefix | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix | **Full** |
22
22
  | **System prompt** (store names, usage rules) | `experimental.chat.system.transform` — dynamic, repo baked in at runtime | CLAUDE.md static text appended by `thatch setup`; repo auto-detected by the MCP server at startup | AGENTS.md static text appended by `thatch setup`; repo auto-detected at startup | **Approximate** — static text persists through compaction, so the agent retains the usage instructions, but the dynamic per-turn refresh is lost |
23
23
  | **Session-start reminder** (recall nudge + hygiene heartbeat) | `session.created` event → `client.session.prompt` injects a synthetic message | `SessionStart` hook → `thatch reminder`; stdout becomes context | `sessionStart` hook → `thatch reminder --json`; output is `additional_context` JSON | **Full** |
24
24
  | **Compaction context** (re-familiarize after compaction) | `experimental.session.compacting` hook appends context to the compaction output | `PostCompact` hook — side-effects only, **cannot inject context** | No equivalent hook | **Gapped** — see below |
@@ -26,6 +26,7 @@ This document maps the feature parity and documents the remaining gaps.
26
26
  | **Extraction feedback** (toast notifications) | `client.tui.showToast` fires when the extraction child goes idle — shows `[thatch] new: N, updated: M, deleted: K` (success) or `extraction complete — nothing to save` (info); best-effort, silently ignored in headless mode | No TUI connection — MCP hosts have no equivalent | No TUI connection | **Gapped** — MCP hosts cannot show toast notifications |
27
27
  | **Prompt-aware recall nudge** | `chat.message` hook embeds the prompt with the in-process warm model, searches `db.search()`, pushes a nudge part if matches ≥ threshold | `UserPromptSubmit` hook → `thatch flush-tools` connects to the MCP server's sideband socket; the warm server embeds + searches; hook prints the nudge or falls back to the write nudge | `beforeSubmitPrompt` hook → `thatch flush-tools --json` (same sideband path) | **Full** — sideband socket gives cold hook processes access to the warm MCP server's model |
28
28
  | **Prediction auto-fire** (user decision model) | `chat.message` hook scores the prompt embedding against prediction matchers; injects a `[thatch] User decision model` nudge alongside the recall nudge (separate synthetic part, same embedding call) | `UserPromptSubmit` hook → `thatch flush-tools` fires prediction query via the sideband socket's `predictions` method in parallel with the recall nudge | `beforeSubmitPrompt` hook → `thatch flush-tools --json` (same sideband path) | **Full** — same `scorePredictionNudge` entry point in both paths |
29
+ | **Behavior auto-fire** (self-discipline rules) | `chat.message` hook scores the prompt embedding against behavior matchers; injects a `[thatch] Situational behaviors` nudge (separate synthetic part, same embedding call) | `UserPromptSubmit` hook → `thatch flush-tools` fires behavior query via the sideband socket's `behaviors` method in parallel with recall and predictions | `beforeSubmitPrompt` hook → `thatch flush-tools --json` (same sideband path) | **Full** — same `scoreBehaviorNudge` entry point in both paths |
29
30
  | **Skills** | Installed to `$XDG_CONFIG_HOME/opencode/skills` at plugin init (shared **+** opencode-only) | Installed to `$CLAUDE_CONFIG_DIR/skills/` by `thatch setup` (shared only) | Installed to `~/.cursor/skills/` by `thatch setup` (shared only) | **Full** — same SKILL.md format; the code-review coordinator is opencode-only (needs sub-agents) |
30
31
  | **Store detection** (repo identity from git remote) | `worktree` parameter from the opencode plugin | `CLAUDE_PROJECT_DIR` env (set by Claude Code for stdio MCP servers) | `CURSOR_PROJECT_DIR` then `CLAUDE_PROJECT_DIR` then cwd | **Full** |
31
32
  | **Setup detection at startup** | n/a — plugin auto-installs at init | `checkSetup` in MCP server: detects missing or broken instructions in CLAUDE.md | Same as Claude Code (checks AGENTS.md) | **Full** — warns the agent to tell the user to run `thatch setup` |
@@ -151,9 +152,10 @@ same socket path without out-of-band coordination. The path lives under
151
152
  `os.tmpdir()`.
152
153
 
153
154
  The protocol is newline-delimited JSON: one request per connection, one
154
- response. Requests are `{"method":"match","text":"...","stores":[...],
155
- "threshold":N,"limit":N}`. Responses are `{"ok":true,"matches":[...]}` or
156
- `{"ok":false,"error":"..."}`.
155
+ response. Requests are `{"method":"match|predictions|behaviors",
156
+ "text":"...","stores":[...],"threshold":N,"limit":N}`. Responses are
157
+ `{"ok":true,"matches":[...]}` / `{"ok":true,"predictions":[...]}` /
158
+ `{"ok":true,"behaviors":[...]}` or `{"ok":false,"error":"..."}`.
157
159
 
158
160
  Graceful degradation: if the socket isn't available (MCP server not running,
159
161
  old version, stale socket from a crash, or a >2 s timeout), `sidebandMatch`
@@ -35,8 +35,8 @@ threw an error (the `extracting` set is cleared on failure).
35
35
 
36
36
  `client.tui.showToast` is called from the `event` hook (on child idle, with
37
37
  extraction metrics: new/updated/deleted counts) and from `chat.message` (on
38
- recall and prediction matches). Best-effort — silently ignored if the TUI is
39
- not connected (headless mode).
38
+ recall, prediction, and behavior matches). Best-effort — silently ignored if
39
+ the TUI is not connected (headless mode).
40
40
 
41
41
  ## Claude Code (MCP server + hooks)
42
42
 
@@ -71,7 +71,7 @@ in the repo; only skills are user-scoped.
71
71
  |-------|---------|--------|------|
72
72
  | `SessionStart` | `thatch reminder` | plain text to stdout (becomes context) | Recall instructions + hygiene heartbeat |
73
73
  | `PostToolBatch` | `thatch buffer-batch` | **silent** (no stdout) | Appends a batch of tool calls to the file-backed JSONL queue |
74
- | `UserPromptSubmit` | `thatch flush-tools` | nudge text to stdout | Peeks queue (extraction nudge), else recall nudge via sideband, else write nudge |
74
+ | `UserPromptSubmit` | `thatch flush-tools` | nudge text to stdout | Peeks queue (extraction nudge), else fires recall, prediction, and behavior nudges via sideband in parallel, else write nudge |
75
75
 
76
76
  `PostToolBatch` is silent so the agent loop is not delayed; the buffered
77
77
  content is invisible until `UserPromptSubmit` peeks it.
@@ -111,7 +111,7 @@ is honored for symmetry and forward-compatibility. Cursor has no equivalent of
111
111
  |-------|---------|--------|------|
112
112
  | `sessionStart` | `thatch reminder --json` | `{ additional_context: "..." }` | Recall + heartbeat, JSON-wrapped for Cursor |
113
113
  | `postToolUse` | `thatch buffer-tool` | **silent** | Appends a **single** tool call to the file-backed queue |
114
- | `beforeSubmitPrompt` | `thatch flush-tools --json` | JSON `additional_context` | Peeks queue, else recall via sideband, else write nudge |
114
+ | `beforeSubmitPrompt` | `thatch flush-tools --json` | JSON `additional_context` | Peeks queue, else recall, prediction, and behavior via sideband, else write nudge |
115
115
 
116
116
  Differences from Claude Code:
117
117
 
@@ -25,12 +25,13 @@ description: Extract durable project facts ... Use when ...
25
25
  ```
26
26
 
27
27
  - `name` must match the directory name (`<skillsDir>/<name>/SKILL.md`).
28
- - `description` drives when the agent loads the skill (both opencode and
29
- Cursor auto-discover skills and use the description for relevance).
28
+ - `description` drives when the agent loads the skill (opencode, Claude
29
+ Code, and Cursor all auto-discover skills and use the description for
30
+ relevance).
30
31
 
31
- ## The 23 skills
32
+ ## The 24 skills
32
33
 
33
- **Shared (22)** — installed everywhere; no sub-agents required:
34
+ **Shared (23)** — installed everywhere; no sub-agents required:
34
35
 
35
36
  | Skill | Role |
36
37
  |-------|------|
@@ -40,6 +41,7 @@ description: Extract durable project facts ... Use when ...
40
41
  | `thatch-review-pedantic` | Mechanical correctness: spelling, naming, doc accuracy, specs, stale artifacts. |
41
42
  | `thatch-review-acceptance` | Behavioral/product review: UX, behavioral delta, integration effects. |
42
43
  | `thatch-review-state-flow` | Data flow and contracts: module boundaries, implicit FSMs, error propagation. |
44
+ | `thatch-review-economy` | Design simplicity and maintainability: is the complexity earned? Evaluates both the overall change design (forest) and individual touch points (trees) for unnecessary complexity, redundancy, and simpler available alternatives. |
43
45
  | `thatch-review-no-slop` | AI writing anti-patterns: change narration, fourth-wall breaks, em dashes, filler. |
44
46
  | `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of behavior? |
45
47
  | `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
@@ -61,11 +63,11 @@ description: Extract durable project facts ... Use when ...
61
63
 
62
64
  | Skill | Role |
63
65
  |-------|------|
64
- | `thatch-code-review` | Resolve review target (incl. VCS detection and connected PR/MR lookup for follow-up round detection), gather project context, research affected workflows, estimate complexity, partition, dispatch the 7 specialists in parallel, synthesize with a workflow-change preface and prior-comment cross-reference. |
66
+ | `thatch-code-review` | Resolve review target (incl. VCS detection and connected PR/MR lookup for follow-up round detection), gather project context, research affected workflows, estimate complexity, partition, dispatch the 8 specialists in parallel, synthesize with a workflow-change preface and prior-comment cross-reference. |
65
67
 
66
68
  ## REVIEW_COMMON
67
69
 
68
- The six problem-finding review specialists share a framework interpolated via `${REVIEW_COMMON}` (the seventh specialist, highlights, finds positive things and uses its own structure):
70
+ The seven problem-finding review specialists share a framework interpolated via `${REVIEW_COMMON}` (the eighth specialist, highlights, finds positive things and uses its own structure):
69
71
 
70
72
  - **Static analysis only** — no running tests/linters/compilers.
71
73
  - **Scope gathering** — resolve the git range, `git diff --stat`, read changed
@@ -95,7 +97,7 @@ The synthesizer reuses the same verification rigor but has its own structure
95
97
  ## The two arrays
96
98
 
97
99
  ```ts
98
- const SHARED_SKILLS: SkillDef[] = [ /* 21 skills above */ ];
100
+ const SHARED_SKILLS: SkillDef[] = [ /* 23 skills above */ ];
99
101
  const OPENCODE_ONLY_SKILLS: SkillDef[] = [ /* code-review coordinator */ ];
100
102
  ```
101
103
 
@@ -132,7 +134,7 @@ and `--cursor` pass only the shared set.
132
134
  ## Memory review skills in practice
133
135
 
134
136
  - **Quick single lens**: load any specialist directly and point it at a branch.
135
- - **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all 7 specialists in parallel (with both the context brief and workflow guide injected into each briefing), then synthesizes a report that starts with the workflow changes before findings.
137
+ - **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all 8 specialists in parallel (with both the context brief and workflow guide injected into each briefing), then synthesizes a report that starts with the workflow changes before findings.
136
138
  - **Full review on Claude Code/Cursor**: run each specialist in sequence, then
137
139
  run `thatch-review-synthesizer` to verify and aggregate.
138
140
  - **Follow-up round (re-review)**: load `thatch-review-followup` when the author
@@ -1,6 +1,6 @@
1
1
  # Plans
2
2
 
3
- Numbered plan documents capture design decisions that span multiple sessions.
3
+ Plan documents capture design decisions that span multiple sessions.
4
4
  Each plan is a snapshot of the reasoning at the time — subsequent plans may
5
5
  supersede earlier ones as the project evolves.
6
6
 
@@ -9,7 +9,7 @@ Plans are temporary. When a plan is fully implemented, it **graduates**:
9
9
  1. The plan file is removed from this folder.
10
10
  2. The final architecture is documented in `docs/dev/` — either updated into
11
11
  existing dev docs or captured in a new one.
12
- 3. End-to-end use-case scenarios are added to `docs/qa/use-cases/`.
12
+ 3. End-to-end use-case scenarios are added to `tests/qa/`.
13
13
 
14
14
  Once graduated, the dev docs and use-case docs are the permanent record. The
15
15
  plan file is no longer needed — git history preserves it if someone needs the