@jeffober/thatch 0.1.21 → 0.1.24
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.
- package/README.md +5 -2
- package/artifacts/skills/common.md +6 -0
- package/artifacts/skills/thatch-code-review.md +20 -7
- package/artifacts/skills/thatch-fact-extractor.md +2 -1
- package/artifacts/skills/thatch-review-acceptance.md +17 -1
- package/artifacts/skills/thatch-review-context.md +2 -0
- package/artifacts/skills/thatch-review-highlights.md +111 -0
- package/artifacts/skills/thatch-review-synthesizer.md +29 -4
- package/artifacts/skills/ticket-description.md +42 -16
- package/docs/dev/README.md +43 -14
- package/docs/dev/gotchas.md +29 -7
- package/docs/dev/mcp-parity.md +29 -9
- package/docs/dev/setup-and-hooks.md +14 -3
- package/docs/dev/skills.md +8 -7
- package/docs/qa/use-cases/README.md +2 -2
- package/docs/qa/use-cases/UC-003-extraction-nudge.md +35 -13
- package/docs/qa/use-cases/UC-005-setup-install.md +2 -2
- package/docs/qa/use-cases/UC-014-skill-install-drift.md +3 -3
- package/docs/qa/use-cases/UC-020-extraction-escalation.md +23 -9
- package/docs/user/README.md +24 -16
- package/package.json +1 -1
- package/src/extraction.ts +41 -0
- package/src/index.ts +317 -29
- package/src/prompts.ts +28 -4
- package/src/skills.ts +1 -0
- package/src/tool-defs.ts +20 -14
package/docs/dev/README.md
CHANGED
|
@@ -54,7 +54,7 @@ bin/thatch → CLI: stores|list|show|forget|search|mcp|reminder|hygi
|
|
|
54
54
|
| `tool-defs.ts` | **Single source of truth** for all tools. Each tool has a name, description, zod schema (args), and execute function. Framework-agnostic — neither opencode nor MCP specific. |
|
|
55
55
|
| `tools.ts` | Thin opencode wrappers. Imports tool-defs, wraps each in opencode's `tool()` with a `thatch_` prefix. |
|
|
56
56
|
| `mcp.ts` | Stdio JSON-RPC 2.0 server. Compiles zod schemas to JSON Schema via `z.toJSONSchema()` for `tools/list`. Validates args via `z.object().parse()` in `tools/call`. All logging to stderr (stdout is the transport). |
|
|
57
|
-
| `index.ts` | OpenCode plugin entry. Wires DB, model, extraction; registers tools and hooks; installs skills. |
|
|
57
|
+
| `index.ts` | OpenCode plugin entry. Wires DB, model, extraction; registers tools and hooks; installs skills. Internal state beyond the extraction pipeline: `extracting` set (parent IDs with an active direct-extraction child), `childMetrics` map (new/updated/deleted counts per child session), and `triggerExtraction(parentID)` (creates a child session via the SDK client and prompts it with the extraction payload). |
|
|
58
58
|
| `setup.ts` | `thatch setup --claude` installer. Writes .mcp.json, appends to CLAUDE.md (idempotent), installs hooks in settings.json, installs skills. |
|
|
59
59
|
| `hygiene.ts` | Hygiene report: pending dedup pairs, stale count, orphaned branch memories. Shared by the plugin's session-start hook and the CLI's `thatch reminder` command. |
|
|
60
60
|
| `git.ts` | Parse `owner/repo` from git remote. Worktree-safe fallback chain. |
|
|
@@ -64,7 +64,7 @@ bin/thatch → CLI: stores|list|show|forget|search|mcp|reminder|hygi
|
|
|
64
64
|
| `extract-queue.ts` | File-backed per-session JSONL queue (caps 20, oldest dropped). Shared by the Claude Code and Cursor hook paths, which fire one-shot per event with no cross-call state. This is the MCP-side equivalent of `extraction.ts`. |
|
|
65
65
|
| `sideband.ts` | Unix domain socket server + client. The MCP server (long-lived, warm model) runs `SidebandServer` so one-shot hook processes can ask it to embed a prompt and search for matches without loading the model themselves. Handles two methods: `match` (recall nudge) and `predictions` (prediction auto-fire). Socket path is a hash of the DB path — both processes compute it independently. |
|
|
66
66
|
| `prompts.ts` | Text constants: opencode system prompt, compaction context, session-start reminder, prompt-aware recall nudge (`recallNudge` / `claudeRecallNudge`), Claude Code CLAUDE.md instructions, Cursor AGENTS.md instructions, Claude Code hook text. |
|
|
67
|
-
| `skills.ts` | `SKILL.md` content for all thatch skills, plus the installer. Skills are split into `SHARED_SKILLS` (
|
|
67
|
+
| `skills.ts` | `SKILL.md` content for all thatch skills, plus the installer. Skills are split into `SHARED_SKILLS` (19 skills: fact-extractor, dedup-classifier, project-primer, 7 review specialists, review synthesizer, review context, workflow research, change walkthrough, code walkthrough, session reflection, pr-description, ticket-description, split-overlarge-pr — work on both opencode and Claude Code) and `OPENCODE_ONLY_SKILLS` (1 skill: code-review coordinator — requires sub-agent support, not installed for Claude Code). `installSkills(dir, skills)` defaults to `SHARED_SKILLS`; the opencode plugin passes `[...SHARED_SKILLS, ...OPENCODE_ONLY_SKILLS]`. |
|
|
68
68
|
|
|
69
69
|
## Plugin hooks
|
|
70
70
|
|
|
@@ -75,9 +75,9 @@ bin/thatch → CLI: stores|list|show|forget|search|mcp|reminder|hygi
|
|
|
75
75
|
| `experimental.chat.system.transform` | Appends the thatch system prompt (store names, usage rules). |
|
|
76
76
|
| `experimental.session.compacting` | Marks the session as compacting and appends re-familiarization context so a compacted session still knows thatch exists. |
|
|
77
77
|
| `experimental.compaction.autocontinue` | Clears the compacting flag so `chat.message` nudges resume. Without this, nudges that instruct tool calls would fire during summary generation where tools are blocked. The `chat.message` hook also clears the flag if it fires for a session still in the compacting set but the incoming message has no compaction-type part — this handles compaction failure, where the session would otherwise be stuck with nudges off forever. |
|
|
78
|
-
| `tool.execute.after` | Buffers every non-`thatch_*`, non-`skill`, non-`task` tool call into the session's extraction buffer. (Skill/task are excluded — buffering them creates a feedback loop where the nudge triggers a skill load, which gets buffered, which triggers another nudge.) Memory writes (`thatch_memory_remember`) and `thatch_extraction_done` drain the buffer and reset the missed-nudge counter. This is a plugin hook, NOT a bus event — do not move it into the `event` handler; the event bus has no such event and it will silently never fire. |
|
|
79
|
-
| `chat.message` | Two priority tiers: (a) if extraction buffer has interactions, **peeks** the buffer (does NOT drain it) and injects a synthetic text part carrying the extraction nudge + JSON payload — the buffer persists until the agent writes a memory or calls `thatch_extraction_done`, so ignored nudges repeat and escalate (polite → insistent → ALL-CAPS) via the `missedNudges` counter; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). The same embedding also feeds the prediction auto-fire: `db.scorePredictionNudge` scores the prompt against prediction matchers and injects a separate `[thatch] User decision model` nudge if any matchers clear the 0.45 threshold. Recall and prediction nudges fire independently (separate try/catch blocks, separate synthetic parts). Skipped entirely while the session is compacting (tool calls are blocked during summary generation). |
|
|
80
|
-
| `event`
|
|
78
|
+
| `tool.execute.after` | Buffers every non-`thatch_*`, non-`skill`, non-`task` tool call into the session's extraction buffer. (Skill/task are excluded — buffering them creates a feedback loop where the nudge triggers a skill load, which gets buffered, which triggers another nudge.) Memory writes (`thatch_memory_remember`) and `thatch_extraction_done` drain the buffer and reset the missed-nudge counter. For child sessions (`childToParent.has(sessionID)`), also tracks metrics: `remember` with `overwrite:false` → new++, `overwrite:true` → updated++, `forget` → deleted++. This is a plugin hook, NOT a bus event — do not move it into the `event` handler; the event bus has no such event and it will silently never fire. |
|
|
79
|
+
| `chat.message` | Two priority tiers: (a) if extraction buffer has interactions and the session is NOT in the `extracting` set (direct extraction in progress), **peeks** the buffer (does NOT drain it) and injects a synthetic text part carrying the extraction nudge + JSON payload — the buffer persists until the agent writes a memory or calls `thatch_extraction_done`, so ignored nudges repeat and escalate (polite → insistent → ALL-CAPS) via the `missedNudges` counter; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). The same embedding also feeds the prediction auto-fire: `db.scorePredictionNudge` scores the prompt against prediction matchers and injects a separate `[thatch] User decision model` nudge if any matchers clear the 0.45 threshold. Recall and prediction nudges fire independently (separate try/catch blocks, separate synthetic parts). Skipped entirely while the session is compacting (tool calls are blocked during summary generation). |
|
|
80
|
+
| `event` | Subscribes to all session bus events. `session.created`: records `childToParent` + `parentSnapshots` (shallow copy of the parent's buffer for snapshot-aware drain), then sends the session-start reminder via `client.session.prompt` carrying the hygiene heartbeat (pending dedup pairs, stale count, orphaned branch memories) when any signal is non-zero. `session.status` (idle): if the session is a child, drains its snapshot, fires a toast with `childMetrics`, and deletes the child session; if the session is a parent with pending tool interactions and not already extracting, calls `triggerExtraction` to create a direct-extraction child. `session.error`: requeues the parent's buffer (child died without draining). `session.deleted`: cleans up `childToParent`, `parentSnapshots`, `childMetrics`, and `extracting`. `session.compacted`: clears the compacting flag so `chat.message` nudges resume. |
|
|
81
81
|
| `dispose` | Closes the DB. |
|
|
82
82
|
|
|
83
83
|
Hook failures are logged with a `[thatch]` prefix — never swallowed silently.
|
|
@@ -168,16 +168,45 @@ dedup cycle (agent-driven)
|
|
|
168
168
|
→ thatch_dedup_mark_checked records verdicts for surviving pairs
|
|
169
169
|
(overwriting or forgetting an entry clears its verdicts → can re-flag)
|
|
170
170
|
|
|
171
|
-
extraction cycle
|
|
171
|
+
extraction cycle
|
|
172
172
|
→ tool.execute.after buffers non-thatch, non-skill, non-task tool calls
|
|
173
|
-
per session (max 20)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
per session (max 20); for child sessions, also tracks new/updated/deleted
|
|
174
|
+
metrics
|
|
175
|
+
→ direct extraction (primary path, opencode-only):
|
|
176
|
+
parent goes idle (session.status idle) with pending tool interactions
|
|
177
|
+
→ triggerExtraction adds parentID to the `extracting` set (suppresses
|
|
178
|
+
nudge in chat.message), creates a child session via
|
|
179
|
+
client.session.create, and prompts it with the extraction payload
|
|
180
|
+
→ child runs the fact-extractor skill, writes memories via
|
|
181
|
+
thatch_memory_remember → consumeSnapshot drains the parent's buffer
|
|
182
|
+
(snapshot-aware: removes only entries captured at dispatch time by
|
|
183
|
+
reference identity, preserving interleaved-turn entries)
|
|
184
|
+
→ child goes idle → event handler drains remaining snapshot entries,
|
|
185
|
+
fires a toast with childMetrics, deletes the child session
|
|
186
|
+
→ nudge path (fallback): if triggerExtraction throws (create or prompt
|
|
187
|
+
fails), the `extracting` set clears and the next chat.message sees
|
|
188
|
+
pending entries with no extracting flag → peeks the buffer and injects
|
|
189
|
+
a nudge part with JSON payload; missed nudges escalate (polite →
|
|
190
|
+
insistent → ALL-CAPS) via the missedNudges counter
|
|
191
|
+
→ drain: thatch_memory_remember (or thatch_extraction_done) clears the
|
|
192
|
+
buffer and resets the missed-nudge counter
|
|
193
|
+
→ agent loads thatch-fact-extractor skill, saves facts via
|
|
194
|
+
thatch_memory_remember
|
|
195
|
+
→ MCP path (Claude Code/Cursor): unchanged — no SDK client, no child
|
|
196
|
+
sessions; extract-queue.ts + flush-tools drives the nudge via hooks
|
|
197
|
+
|
|
198
|
+
toast notifications (opencode-only, TUI-rendered)
|
|
199
|
+
→ client.tui.showToast — best-effort, silently ignored if TUI not
|
|
200
|
+
connected (headless mode); model-invisible (goes to the user only,
|
|
201
|
+
not the conversation history — the inverse of synthetic nudge parts,
|
|
202
|
+
which are model-visible but TUI-hidden)
|
|
203
|
+
→ extraction metrics: `[thatch] new: N, updated: M, deleted: K` (success
|
|
204
|
+
variant, 4s) — fires when an extraction child goes idle; no-save runs
|
|
205
|
+
show `[thatch] extraction complete — nothing to save` (info variant)
|
|
206
|
+
→ recall matches: `[thatch] recalled N memories` (info variant, 3s) —
|
|
207
|
+
fires when chat.message matches stored memories
|
|
208
|
+
→ prediction matches: `[thatch] N predictions surfaced` (info variant,
|
|
209
|
+
3s) — fires when chat.message matches decision-model patterns
|
|
181
210
|
|
|
182
211
|
prompt-aware recall nudge (both paths)
|
|
183
212
|
→ opencode: chat.message hook embeds prompt text with warm in-process model,
|
package/docs/dev/gotchas.md
CHANGED
|
@@ -65,15 +65,37 @@ here first. These are the things that have already cost time.
|
|
|
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
|
|
68
|
-
buffer drains.
|
|
68
|
+
buffer drains. The primary opencode path doesn't use the nudge at all:
|
|
69
|
+
`triggerExtraction` creates a child session directly, and the `extracting`
|
|
70
|
+
set suppresses the nudge in `chat.message` while a direct-extraction child
|
|
71
|
+
is active. The peek-not-drain semantics still hold for the fallback nudge
|
|
72
|
+
path (MCP hosts and any `triggerExtraction` failure).
|
|
69
73
|
- **A child sub-agent's `thatch_memory_remember` drains the parent's buffer**
|
|
70
74
|
via the `childToParent` Map (`index.ts:65` declaration, `index.ts:131`
|
|
71
|
-
lookup).
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
lookup). Two paths reach this machinery: (a) the **plugin-initiated child
|
|
76
|
+
session** — `triggerExtraction` calls `client.session.create` with a
|
|
77
|
+
`parentID`, the primary opencode path; (b) the **agent-initiated background
|
|
78
|
+
task** — the model dispatches the fact-extractor via the `task` tool after
|
|
79
|
+
receiving the nudge, the fallback path still used by MCP hosts. Both use
|
|
80
|
+
the same `childToParent`/`parentSnapshots`/`consumeSnapshot` plumbing.
|
|
81
|
+
Without this, either path would write memories in the child but never
|
|
82
|
+
clear the parent's queue — the nudge would replay every turn.
|
|
83
|
+
`thatch_extraction_done` is the belt-and-suspenders explicit
|
|
84
|
+
acknowledgment: it drains the buffer without requiring a memory write
|
|
85
|
+
(covers cases where the sub-agent errors out or the host doesn't expose
|
|
86
|
+
parent-child session relationships).
|
|
87
|
+
- **The no-save drain runs in the child-idle handler regardless of writes.**
|
|
88
|
+
When the extraction child goes idle after a no-save run (nothing worth
|
|
89
|
+
extracting), the parent's snapshot entries must still be drained from the
|
|
90
|
+
buffer. Without this, entries linger in pending and the nudge fires as a
|
|
91
|
+
synthetic (TUI-hidden) part on the next `chat.message`. The child-idle
|
|
92
|
+
handler drains the snapshot only if it still exists (the child wrote no
|
|
93
|
+
memories). If the child did write memories, `tool.execute.after` already
|
|
94
|
+
consumed the snapshot — the idle handler skips the drain so interleaved-turn
|
|
95
|
+
entries survive.
|
|
96
|
+
- **`client.tui.showToast` is best-effort.** The toast call is wrapped in a
|
|
97
|
+
catch-and-ignore — if the TUI is not connected (headless mode), it silently
|
|
98
|
+
does nothing. The toast is TUI-rendered (in-app), not an OS notification.
|
|
77
99
|
|
|
78
100
|
## Hooks (Claude Code / Cursor)
|
|
79
101
|
|
package/docs/dev/mcp-parity.md
CHANGED
|
@@ -22,7 +22,8 @@ This document maps the feature parity and documents the remaining gaps.
|
|
|
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 |
|
|
25
|
-
| **Extraction
|
|
25
|
+
| **Extraction** (buffer tool calls, extract durable facts) | `tool.execute.after` buffers non-thatch, non-skill, non-task tool calls in-process; **direct extraction** is the primary path — when the parent session goes idle with pending buffer entries, the plugin creates a child session via the SDK (`client.session.create` with `parentID`) and prompts it with the extraction payload (nudge suppressed via the `extracting` set); the `chat.message` nudge path is a **fallback** used when direct extraction throws | `PostToolBatch` → `thatch buffer-batch` (file-backed JSONL queue); `UserPromptSubmit` → `thatch flush-tools` peeks the queue and prints the nudge (does not drain — the queue persists until a memory write or `extraction_done`) | `postToolUse` → `thatch buffer-tool` (single-tool, file-backed queue); `beforeSubmitPrompt` → `thatch flush-tools --json` | **Partial** — opencode uses direct extraction (parent idle → child session) as the primary path, with the nudge as fallback; MCP hosts are nudge-only. Both paths produce the same JSON shape via `buildExtractionPayload()`. Nudge timing differs: the nudge arrives at the **start** of the next turn in Claude Code/Cursor; opencode's direct extraction fires at **end of turn** (session idle), and the nudge fallback fires at the start of the next turn like MCP |
|
|
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 |
|
|
26
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 |
|
|
27
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 |
|
|
28
29
|
| **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) |
|
|
@@ -61,18 +62,37 @@ through compaction, so the agent retains the usage instructions. The
|
|
|
61
62
|
compaction in Claude Code, so the recall reminder runs again. There is no
|
|
62
63
|
explicit "re-familiarization" nudge for hosts without a compaction hook.
|
|
63
64
|
|
|
64
|
-
### Extraction
|
|
65
|
+
### Extraction timing
|
|
65
66
|
|
|
66
|
-
OpenCode's extraction pipeline
|
|
67
|
+
OpenCode's extraction pipeline has two paths — direct extraction (primary)
|
|
68
|
+
and the nudge (fallback):
|
|
69
|
+
|
|
70
|
+
**Direct extraction (primary path):**
|
|
67
71
|
|
|
68
72
|
1. `tool.execute.after` buffers every non-thatch, non-skill, non-task tool
|
|
69
73
|
call into a per-session in-memory array (max 20 interactions).
|
|
70
|
-
2.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`
|
|
74
|
-
|
|
75
|
-
3. The
|
|
74
|
+
2. When the parent session goes idle (`session.status` idle event) with pending
|
|
75
|
+
buffer entries, the plugin calls `triggerExtraction`: creates a child session
|
|
76
|
+
via `client.session.create` (with `parentID`), then prompts it via
|
|
77
|
+
`client.session.promptAsync` (or `prompt`) with the extraction payload. The
|
|
78
|
+
`extracting` set suppresses the nudge in `chat.message` while the child runs.
|
|
79
|
+
3. The child session runs the `thatch-fact-extractor` skill, writes memories via
|
|
80
|
+
`thatch_memory_remember`. A memory write in the child drains the parent's
|
|
81
|
+
buffer snapshot (via the `childToParent` Map and `consumeSnapshot`) and
|
|
82
|
+
resets the missed-nudge counter.
|
|
83
|
+
4. When the child goes idle, the handler drains any remaining snapshot entries
|
|
84
|
+
(covers no-save runs), deletes the child session, and fires a toast via
|
|
85
|
+
`client.tui.showToast`.
|
|
86
|
+
|
|
87
|
+
**Nudge (fallback path):**
|
|
88
|
+
|
|
89
|
+
1. If `triggerExtraction` throws (session creation or prompt fails), the catch
|
|
90
|
+
block clears the `extracting` flag. On the next `chat.message`, the buffer is
|
|
91
|
+
**peeked** (not drained) and a synthetic text part carrying the JSON payload
|
|
92
|
+
is injected into the conversation. The buffer persists until the agent writes
|
|
93
|
+
a memory or calls `thatch_extraction_done`, so ignored nudges repeat and
|
|
94
|
+
escalate (polite → insistent → ALL-CAPS) via the `missedNudges` counter.
|
|
95
|
+
2. The agent sees the nudge, loads the `thatch-fact-extractor` skill, and saves
|
|
76
96
|
durable facts via `thatch_memory_remember`. A memory write in the session
|
|
77
97
|
(or a child sub-agent via the `childToParent` Map) or `thatch_extraction_done`
|
|
78
98
|
drains the buffer and resets the missed-nudge counter.
|
|
@@ -19,14 +19,25 @@ The plugin entry (`src/index.ts`) registers these hooks in code:
|
|
|
19
19
|
| `experimental.chat.system.transform` | `{}` | `{ system: string[] }` | Pushes the system prompt (store names, usage rules). |
|
|
20
20
|
| `experimental.session.compacting` | `{ sessionID }` | `{ context: string[] }` | Marks the session as compacting, pushes re-familiarization context. |
|
|
21
21
|
| `experimental.compaction.autocontinue` | `{ sessionID }` | `{ enabled: boolean }` | Clears the compacting flag so `chat.message` nudges resume post-compaction. |
|
|
22
|
-
| `tool.execute.after` | `{ tool, sessionID, callID, args }` | `{ title, output, metadata }` | Buffers non-`thatch_`, non-`skill`, non-`task` tool calls into the in-memory extraction ring buffer (max 20). |
|
|
23
|
-
| `chat.message` | `{ sessionID, messageID }` | `{ message, parts }` | Two tiers: extraction nudge if pending, else prompt-aware recall nudge.
|
|
24
|
-
| `event`
|
|
22
|
+
| `tool.execute.after` | `{ tool, sessionID, callID, args }` | `{ title, output, metadata }` | Buffers non-`thatch_`, non-`skill`, non-`task` tool calls into the in-memory extraction ring buffer (max 20). In child sessions, also tracks new/updated/deleted counts via `childMetrics` for the extraction toast. |
|
|
23
|
+
| `chat.message` | `{ sessionID, messageID }` | `{ message, parts }` | Two tiers: extraction nudge if pending and not already extracting (fallback — direct extraction via the `event` hook is the primary path), else prompt-aware recall nudge. Suppressed while compacting or while `extracting` is set. |
|
|
24
|
+
| `event` | `{ event: { type, properties } }` | — | Dispatches on `event.type`: `session.created` (top-level) → `client.session.prompt` with reminder + hygiene heartbeat; `session.created` (child with `parentID`) → records `childToParent` + snapshots parent's pending buffer. `session.status` idle (parent, pending interactions) → `triggerExtraction` (direct child-session extraction); idle (child) → complete/drain, `showToast` with metrics, delete child. `session.error` (child) → requeue parent's accepted entries. `session.deleted` → requeue if child, drop accepted if parent, clean maps. `session.compacted` → clear compacting flag. |
|
|
25
25
|
| `dispose` | — | — | Closes the DB. |
|
|
26
26
|
|
|
27
27
|
Skills install to `$XDG_CONFIG_HOME/opencode/skills` at plugin init — shared
|
|
28
28
|
**and** opencode-only (the coordinator needs sub-agents).
|
|
29
29
|
|
|
30
|
+
Direct extraction is the primary path for opencode: when a parent session goes
|
|
31
|
+
idle with pending tool interactions, the `event` hook creates a child session
|
|
32
|
+
and prompts it directly via `triggerExtraction`. The `chat.message` extraction
|
|
33
|
+
nudge is a fallback — it fires only if direct extraction was never triggered or
|
|
34
|
+
threw an error (the `extracting` set is cleared on failure).
|
|
35
|
+
|
|
36
|
+
`client.tui.showToast` is called from the `event` hook (on child idle, with
|
|
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).
|
|
40
|
+
|
|
30
41
|
## Claude Code (MCP server + hooks)
|
|
31
42
|
|
|
32
43
|
`thatch setup --claude` (project-local) or `thatch setup --claude --global`.
|
package/docs/dev/skills.md
CHANGED
|
@@ -21,9 +21,9 @@ description: Extract durable project facts ... Use when ...
|
|
|
21
21
|
- `description` drives when the agent loads the skill (both opencode and
|
|
22
22
|
Cursor auto-discover skills and use the description for relevance).
|
|
23
23
|
|
|
24
|
-
## The
|
|
24
|
+
## The 20 skills
|
|
25
25
|
|
|
26
|
-
**Shared (
|
|
26
|
+
**Shared (19)** — installed everywhere; no sub-agents required:
|
|
27
27
|
|
|
28
28
|
| Skill | Role |
|
|
29
29
|
|-------|------|
|
|
@@ -36,6 +36,7 @@ description: Extract durable project facts ... Use when ...
|
|
|
36
36
|
| `thatch-review-no-slop` | AI writing anti-patterns: change narration, fourth-wall breaks, em dashes, filler. |
|
|
37
37
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of behavior? |
|
|
38
38
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
39
|
+
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
39
40
|
| `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Starts the final report with a workflow-change preface, then cross-references findings against prior review comments when a follow-up round register is provided. |
|
|
40
41
|
| `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
|
|
41
42
|
| `thatch-workflow-research` | Research code workflows/features affected by a change or planned change. Reads code flows, comments, git history, memories, docs. Produces a guide to the code for reviewers or planners. |
|
|
@@ -50,11 +51,11 @@ description: Extract durable project facts ... Use when ...
|
|
|
50
51
|
|
|
51
52
|
| Skill | Role |
|
|
52
53
|
|-------|------|
|
|
53
|
-
| `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
|
|
54
|
+
| `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. |
|
|
54
55
|
|
|
55
56
|
## REVIEW_COMMON
|
|
56
57
|
|
|
57
|
-
The six review specialists share a framework interpolated via `${REVIEW_COMMON}
|
|
58
|
+
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):
|
|
58
59
|
|
|
59
60
|
- **Static analysis only** — no running tests/linters/compilers.
|
|
60
61
|
- **Scope gathering** — resolve the git range, `git diff --stat`, read changed
|
|
@@ -84,7 +85,7 @@ The synthesizer reuses the same verification rigor but has its own structure
|
|
|
84
85
|
## The two arrays
|
|
85
86
|
|
|
86
87
|
```ts
|
|
87
|
-
const SHARED_SKILLS: SkillDef[] = [ /*
|
|
88
|
+
const SHARED_SKILLS: SkillDef[] = [ /* 19 skills above */ ];
|
|
88
89
|
const OPENCODE_ONLY_SKILLS: SkillDef[] = [ /* code-review coordinator */ ];
|
|
89
90
|
```
|
|
90
91
|
|
|
@@ -107,7 +108,7 @@ and `--cursor` pass only the shared set.
|
|
|
107
108
|
|
|
108
109
|
## Adding a skill
|
|
109
110
|
|
|
110
|
-
1. Write `artifacts/skills/thatch-<name>.md` with YAML frontmatter. If it's a review specialist, include `${REVIEW_COMMON}` (interpolated from `artifacts/skills/common.md`).
|
|
111
|
+
1. Write `artifacts/skills/thatch-<name>.md` with YAML frontmatter. If it's a problem-finding review specialist, include `${REVIEW_COMMON}` (interpolated from `artifacts/skills/common.md`). The highlights specialist does not use REVIEW_COMMON — it finds positive things, not problems, so the problem-finding framework does not apply.
|
|
111
112
|
2. Add the skill name to the `names` array in `loadSharedSkills()` (or `loadOpencodeOnlySkills()` if sub-agents are needed). The loader in `src/skills.ts` reads `.md` files at init.
|
|
112
113
|
3. If the skill name appears in a tool's workflow (e.g. `thatch-fact-extractor`), update `src/prompts.ts`.
|
|
113
114
|
4. Run `mise run check` — tests verify counts; `installSkills` picks up new files on next init.
|
|
@@ -115,7 +116,7 @@ and `--cursor` pass only the shared set.
|
|
|
115
116
|
## Memory review skills in practice
|
|
116
117
|
|
|
117
118
|
- **Quick single lens**: load any specialist directly and point it at a branch.
|
|
118
|
-
- **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all
|
|
119
|
+
- **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.
|
|
119
120
|
- **Full review on Claude Code/Cursor**: run each specialist in sequence, then
|
|
120
121
|
run `thatch-review-synthesizer` to verify and aggregate.
|
|
121
122
|
|
|
@@ -22,13 +22,13 @@ file/IPC/CLI contracts ready to graduate into `bun:test` integration tests.
|
|
|
22
22
|
| [UC-011](UC-011-write-time-similarity-warning.md) | Write-time warning never blocks; merge or mark-distinct reconciliation |
|
|
23
23
|
| [UC-012](UC-012-model-migration.md) | `THATCH_MODEL` change: old memories skipped (not corrupted) until re-saved |
|
|
24
24
|
| [UC-013](UC-013-compaction-context.md) | Compaction context re-familiarization (opencode-only) |
|
|
25
|
-
| [UC-014](UC-014-skill-install-drift.md) | Skill install:
|
|
25
|
+
| [UC-014](UC-014-skill-install-drift.md) | Skill install: 19 shared vs 20 opencode; drift overwritten on re-setup |
|
|
26
26
|
| [UC-015](UC-015-env-override-matrix.md) | `THATCH_DB_PATH`, `XDG_CONFIG_HOME`, `CLAUDE_CONFIG_DIR`, `THATCH_QUEUE_DIR`, `THATCH_RECALL_THRESHOLD`, `THATCH_MODEL` |
|
|
27
27
|
| [UC-016](UC-016-concurrent-session-isolation.md) | Per-session extraction isolation (in-memory + file queue); shared stateless sideband |
|
|
28
28
|
| [UC-017](UC-017-buffer-tool-vs-buffer-batch.md) | `buffer-batch` (Claude, `tool_calls[]`+`session_id`) vs `buffer-tool` (Cursor, single+`conversation_id`) |
|
|
29
29
|
| [UC-018](UC-018-mcp-startup-setup-detection.md) | MCP startup detects missing/broken setup instructions and warns the agent |
|
|
30
30
|
| [UC-019](UC-019-archived-memory-lifecycle.md) | Archive, search exclusion, update guard, unarchive |
|
|
31
|
-
| [UC-020](UC-020-extraction-escalation.md) | Nudge escalation (polite → insistent → ALL-CAPS), buffer persistence, `extraction_done`
|
|
31
|
+
| [UC-020](UC-020-extraction-escalation.md) | Nudge escalation (polite → insistent → ALL-CAPS), buffer persistence, `extraction_done` accept/complete |
|
|
32
32
|
| [UC-021](UC-021-prediction-autofire.md) | Prediction auto-fire: matcher scores prompt, prediction nudge injected alongside recall |
|
|
33
33
|
| [UC-022](UC-022-prediction-dedup.md) | Prediction create-on-existing: dedup finds match, links edge without disconfirming |
|
|
34
34
|
| [UC-023](UC-023-prediction-confidence-model.md) | Bayesian confidence math: create, confirm, soft (weak disconfirm), disconfirm signals |
|
|
@@ -9,24 +9,46 @@ client and a synthetic tool call sequence._
|
|
|
9
9
|
**Steps**
|
|
10
10
|
1. Do some real work: have the agent read files, run commands, edit code —
|
|
11
11
|
any non-`thatch_*`, non-`skill`, non-`task` tool activity.
|
|
12
|
-
2.
|
|
12
|
+
2. The agent's turn ends and the session goes idle.
|
|
13
13
|
|
|
14
|
-
**Expected**
|
|
15
|
-
- The
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
**Expected (opencode — direct extraction, primary path)**
|
|
15
|
+
- The plugin's `event` hook catches `session.status` idle with pending tool
|
|
16
|
+
interactions and calls `triggerExtraction`: creates a child session via
|
|
17
|
+
`client.session.create({ parentID })` and prompts it via
|
|
18
|
+
`client.session.promptAsync` (or `client.session.prompt` fire-and-forget
|
|
19
|
+
if the env var is unset).
|
|
20
|
+
- The `extracting` set suppresses the nudge in `chat.message` while the
|
|
21
|
+
child runs — no nudge text appears in the user's conversation.
|
|
22
|
+
- The child loads `thatch-fact-extractor` and saves durable facts via
|
|
19
23
|
`thatch_memory_remember` — or saves nothing if the activity was routine.
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
- A `thatch_memory_remember` call in the child drains the parent's snapshot
|
|
25
|
+
entries from the buffer (via `consumeSnapshot` with `parentSnapshots`).
|
|
26
|
+
- When the child goes idle, the parent's snapshot entries are drained
|
|
27
|
+
(covering no-save runs where no memory was written), the child session is
|
|
28
|
+
deleted, and a toast notification fires with the extraction metrics
|
|
29
|
+
(`[thatch] new: N, updated: M, deleted: K`, or
|
|
30
|
+
`[thatch] extraction complete — nothing to save`).
|
|
31
|
+
- If `triggerExtraction` throws, the `extracting` set is cleared and the
|
|
32
|
+
nudge fires as a fallback on the next `chat.message` (see below).
|
|
33
|
+
|
|
34
|
+
**Expected (fallback nudge path — opencode when direct extraction fails,
|
|
35
|
+
and all MCP hosts)**
|
|
36
|
+
- The agent's context for the next message includes a `[thatch]` nudge
|
|
37
|
+
carrying a JSON payload summarizing the buffered tool interactions (tool
|
|
38
|
+
name, title, truncated args/output).
|
|
39
|
+
- The buffer is **not** drained on nudge delivery — it persists until the
|
|
40
|
+
agent writes a memory or accepts it by calling `thatch_extraction_done`.
|
|
41
|
+
Accepting quiets the nudge while holding the entries until the extractor
|
|
42
|
+
completes; a child extractor that errors or is deleted requeues them. If
|
|
43
|
+
the nudge is ignored, the next message carries a repeat nudge, escalating
|
|
44
|
+
in urgency:
|
|
23
45
|
- 1st-2nd miss: polite tone
|
|
24
46
|
- 3rd consecutive miss (missedCount=2): insistent (directive) tone
|
|
25
47
|
- 4th+ consecutive miss (missedCount>=3): ALL-CAPS tone
|
|
26
|
-
The counter resets when the buffer drains (memory write or
|
|
27
|
-
`thatch_extraction_done`).
|
|
28
|
-
- A `thatch_memory_remember` call in a child sub-agent session also drains
|
|
29
|
-
parent's buffer (via the `childToParent` Map), so dispatching the
|
|
48
|
+
The counter resets when the buffer drains (memory write) or is accepted
|
|
49
|
+
(`thatch_extraction_done`).
|
|
50
|
+
- A `thatch_memory_remember` call in a child sub-agent session also drains
|
|
51
|
+
the parent's buffer (via the `childToParent` Map), so dispatching the
|
|
30
52
|
fact-extractor as a background task clears the parent's queue.
|
|
31
53
|
- Two concurrent sessions never see each other's interactions in a nudge.
|
|
32
54
|
- The agent's own `thatch_*` tool calls never appear in a payload (no
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
appends a thatch block to `CLAUDE.md` bracketed by start/end markers (replaced, not
|
|
18
18
|
duplicated, on re-run), writes `.claude/settings.json` hooks (`SessionStart` -> `thatch reminder`,
|
|
19
19
|
`PostToolBatch` -> `thatch buffer-batch`, `UserPromptSubmit` -> `thatch flush-tools`), and installs
|
|
20
|
-
**
|
|
20
|
+
**19 shared skills** (no code-review coordinator) to `$CLAUDE_CONFIG_DIR/skills/` — user-scoped
|
|
21
21
|
even in project-local mode.
|
|
22
22
|
- `--cursor` project-local writes `.cursor/mcp.json`, appends to `AGENTS.md`, writes
|
|
23
23
|
`.cursor/hooks.json` in the **flat format** (`{version:1, hooks:{...}}`): `sessionStart` ->
|
|
24
24
|
`thatch reminder --json`, `postToolUse` -> `thatch buffer-tool`, `beforeSubmitPrompt` ->
|
|
25
|
-
`thatch flush-tools --json`; and installs
|
|
25
|
+
`thatch flush-tools --json`; and installs 19 shared skills to `~/.cursor/skills/`.
|
|
26
26
|
- Re-run is idempotent: instructions are not duplicated, thatch hooks are replaced (not appended),
|
|
27
27
|
and non-thatch hooks are preserved. A legacy `thatch echo` hook is replaced with `flush-tools`.
|
|
28
28
|
- `--global` (Claude) writes `~/.claude/CLAUDE.md` + `~/.claude/settings.json` but **no project
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
5. Check whether the `thatch-code-review` coordinator skill is present.
|
|
14
14
|
|
|
15
15
|
**Expected**
|
|
16
|
-
- Claude Code and Cursor install exactly **
|
|
16
|
+
- Claude Code and Cursor install exactly **19 shared skills** to the skills
|
|
17
17
|
dir — the coordinator (`thatch-code-review`) is **absent** (it needs
|
|
18
18
|
sub-agents, which those hosts lack).
|
|
19
|
-
- opencode installs **
|
|
19
|
+
- opencode installs **20** — the 19 shared plus the coordinator.
|
|
20
20
|
- The locally edited `SKILL.md` is **overwritten** with the canonical content
|
|
21
21
|
on the next `setup`/init (drift detection: a file is only rewritten when its
|
|
22
22
|
content differs from the definition). Unrelated skill files are untouched.
|
|
23
23
|
- Skills never land in the worktree — always under the user-scoped config dir
|
|
24
24
|
(`~/.claude/skills`, `~/.cursor/skills`, `$XDG_CONFIG_HOME/opencode/skills`).
|
|
25
25
|
|
|
26
|
-
_Automatable: yes — file presence, count (
|
|
26
|
+
_Automatable: yes — file presence, count (19 vs 20), content-diff-overwrite, and
|
|
27
27
|
coordinator host-gating are all file assertions (`setup.test.ts` already covers
|
|
28
28
|
the unit contract)._
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UC-020: Extraction nudge escalation and acknowledgment
|
|
2
2
|
|
|
3
|
-
_Automatable: missedNudges counter + escalation tiers + extraction_done
|
|
3
|
+
_Automatable: missedNudges counter + escalation tiers + extraction_done accept
|
|
4
4
|
are testable with the mock client and a synthetic tool call sequence._
|
|
5
5
|
|
|
6
6
|
**Preconditions**
|
|
@@ -27,12 +27,26 @@ are testable with the mock client and a synthetic tool call sequence._
|
|
|
27
27
|
persists until a memory is written or `extraction_done` is called. The nudge
|
|
28
28
|
repeats each turn with escalated tone (and the payload grows if new tool
|
|
29
29
|
activity adds entries between nudges).
|
|
30
|
-
- Step 6: `thatch_extraction_done`
|
|
31
|
-
`missedNudges` counter. The tool returns
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
- Step 6: `thatch_extraction_done` in the parent accepts the buffer (moves it
|
|
31
|
+
to a holding area) and resets the `missedNudges` counter. The tool returns
|
|
32
|
+
`"[acknowledged]"`. Held entries drop when the extractor completes (child
|
|
33
|
+
memory write, child `extraction_done`, or child idle); if the child errors
|
|
34
|
+
or is deleted first, the entries requeue and the nudge replays.
|
|
35
|
+
- Step 7: no extraction nudge appears (buffer is accepted). If the user prompt
|
|
34
36
|
semantically matches existing memories, a recall nudge may appear instead.
|
|
35
|
-
- Alternative drain path
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
- Alternative drain path (opencode direct extraction): when the parent session
|
|
38
|
+
goes idle with pending tool interactions, the plugin calls
|
|
39
|
+
`triggerExtraction` — creates a child session via the SDK client and prompts
|
|
40
|
+
it directly. The `extracting` set suppresses the nudge in `chat.message`
|
|
41
|
+
while the child runs. The child writes memories via
|
|
42
|
+
`thatch_memory_remember`, which drains the parent's snapshot entries via
|
|
43
|
+
`consumeSnapshot`. When the child goes idle, the snapshot is drained
|
|
44
|
+
(covering no-save runs), the child session is deleted, and a toast fires
|
|
45
|
+
with the metrics. This path bypasses the nudge-and-acknowledge cycle
|
|
46
|
+
entirely — no `missedNudges` counter, no escalation. The nudge path is
|
|
47
|
+
fallback only (when `triggerExtraction` throws).
|
|
48
|
+
- Alternative drain path (agent-initiated): if a child sub-agent (dispatched
|
|
49
|
+
via the `task` tool in the fallback nudge path) writes a memory via
|
|
50
|
+
`thatch_memory_remember`, the parent's buffer is also drained via the
|
|
51
|
+
`childToParent` Map — the `missedNudges` counter resets for the parent
|
|
52
|
+
session.
|
package/docs/user/README.md
CHANGED
|
@@ -20,16 +20,15 @@ Publish to npm and add thatch to your opencode config:
|
|
|
20
20
|
|
|
21
21
|
OpenCode installs the plugin and its dependencies automatically on next start.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
fact-extractor as a **background** sub-agent instead of blocking your turn:
|
|
23
|
+
For async extraction (child sessions run in the background):
|
|
25
24
|
|
|
26
25
|
```bash
|
|
27
26
|
export OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true
|
|
28
27
|
```
|
|
29
28
|
|
|
30
|
-
Without
|
|
31
|
-
|
|
32
|
-
`[env]`, or `.envrc`.
|
|
29
|
+
Without this env var, extraction still works — the child session runs
|
|
30
|
+
fire-and-forget instead of asynchronously. Put it in your shell rc,
|
|
31
|
+
`mise.toml` `[env]`, or `.envrc`.
|
|
33
32
|
|
|
34
33
|
For local development before publishing, use a file path:
|
|
35
34
|
|
|
@@ -106,7 +105,7 @@ Stores are created automatically — no setup required.
|
|
|
106
105
|
|
|
107
106
|
| Tool | What it does |
|
|
108
107
|
|------|-------------|
|
|
109
|
-
| `thatch_extraction_done` | Acknowledge
|
|
108
|
+
| `thatch_extraction_done` | Acknowledge extraction buffer work. In the nudge fallback path, quiets the nudge while holding entries until the extractor completes. In a child extractor session, marks entries complete. Called by the model after dispatching the fact-extractor skill. |
|
|
110
109
|
|
|
111
110
|
### Prediction tools
|
|
112
111
|
|
|
@@ -133,13 +132,21 @@ Beyond the tools, thatch hooks into opencode itself:
|
|
|
133
132
|
- **Write-time similarity warning.** Saving a memory that closely resembles an
|
|
134
133
|
existing one succeeds, but the response warns the agent and lists the
|
|
135
134
|
similar entries so it can merge them or record that they're distinct.
|
|
136
|
-
- **Fact
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
- **Fact extraction.** Thatch buffers the session's recent tool calls (up
|
|
136
|
+
to 20, per session). When the session goes idle, the plugin creates a
|
|
137
|
+
child session and prompts it to run the fact-extractor skill directly —
|
|
138
|
+
no nudge text in your conversation. The child writes memories via
|
|
139
|
+
`thatch_memory_remember` and is cleaned up when it finishes. A toast
|
|
140
|
+
notification shows the results (`[thatch] new: 2, updated: 1`). If the
|
|
141
|
+
direct path fails, a nudge is injected into the next message as a
|
|
142
|
+
fallback. On Claude Code and Cursor, the nudge-and-acknowledge path is
|
|
143
|
+
the only mechanism (no SDK client to create child sessions). The agent
|
|
144
|
+
does the writing — thatch never saves memories on its own.
|
|
145
|
+
- **Recall and prediction toasts.** When your prompt matches stored
|
|
146
|
+
memories or learned decision patterns, thatch injects a synthetic nudge
|
|
147
|
+
(invisible to you, visible to the agent) and fires a toast notification
|
|
148
|
+
(`[thatch] recalled 3 memories` or `[thatch] 2 predictions surfaced`).
|
|
149
|
+
The toast is ephemeral — it fades after a few seconds.
|
|
143
150
|
- **Compaction context.** When opencode compacts a long session, thatch injects
|
|
144
151
|
a reminder so the summarized session still knows memory tools exist.
|
|
145
152
|
- **Prediction auto-fire.** When a prompt matches learned contexts, thatch
|
|
@@ -179,7 +186,7 @@ With `thatch setup --claude`, skills install to `~/.claude/skills/` (or
|
|
|
179
186
|
|
|
180
187
|
### Code review skills
|
|
181
188
|
|
|
182
|
-
|
|
189
|
+
Seven specialist review lenses, each a self-contained static-analysis pass:
|
|
183
190
|
|
|
184
191
|
| Skill | Focus |
|
|
185
192
|
|-------|-------|
|
|
@@ -189,7 +196,8 @@ Six specialist review lenses, each a self-contained static-analysis pass:
|
|
|
189
196
|
| `thatch-review-no-slop` | AI writing anti-patterns: change narration, fourth wall breaks, em dashes, hedging, filler. |
|
|
190
197
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
|
|
191
198
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
192
|
-
| `thatch-review-
|
|
199
|
+
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
200
|
+
| `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a report that starts with workflow changes, then highlights, then deduplicated severity-grouped findings. |
|
|
193
201
|
| `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, memory) before a review. Prevents false positives about intentionally deferred work. |
|
|
194
202
|
| `thatch-workflow-research` | Researches code workflows and features affected by a change or planned change. Reads code flows, comments, git history, and produces a guide for reviewers or planners. |
|
|
195
203
|
| `thatch-change-walkthrough` | Explains a change to the user as a teaching walkthrough: researches each affected workflow at the merge-base, teaches current behavior, then overlays the modifications with file:line citations. |
|
|
@@ -214,7 +222,7 @@ Six specialist review lenses, each a self-contained static-analysis pass:
|
|
|
214
222
|
| Skill | opencode | Claude Code | Cursor |
|
|
215
223
|
|-------|----------|-------------|--------|
|
|
216
224
|
| Memory skills (4) | Yes | Yes | Yes |
|
|
217
|
-
| Review specialists (
|
|
225
|
+
| Review specialists (7) | Yes | Yes | Yes |
|
|
218
226
|
| Review synthesizer | Yes | Yes | Yes |
|
|
219
227
|
| Review context + workflow research | Yes | Yes | Yes |
|
|
220
228
|
| Walkthrough skills (2) | Yes | Yes | Yes |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffober/thatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "Persistent memory for AI coding agents — local embeddings, SQLite stores, zero config. Works with OpenCode (as a plugin), Claude Code (as an MCP server), and Cursor (as an MCP server).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|