@jeffober/thatch 0.1.38 → 0.1.40
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 +8 -2
- package/artifacts/skills/common.md +4 -0
- package/artifacts/skills/thatch-code-review.md +10 -4
- package/artifacts/skills/thatch-review-mentorship.md +174 -0
- package/artifacts/skills/thatch-review-synthesizer.md +57 -6
- package/docs/dev/README.md +3 -1
- package/docs/dev/features/README.md +3 -2
- package/docs/dev/features/behavior-engine.md +5 -3
- package/docs/dev/features/database.md +2 -2
- package/docs/dev/features/memory-store.md +13 -0
- package/docs/dev/features/multi-host.md +2 -2
- package/docs/dev/features/notifications.md +106 -0
- package/docs/dev/features/prediction-engine.md +6 -3
- package/docs/dev/features/qa-system.md +18 -17
- package/docs/dev/gotchas.md +18 -0
- package/docs/dev/mcp-parity.md +1 -1
- package/docs/dev/skills.md +9 -6
- package/docs/user/README.md +37 -13
- package/docs/user/code-review.md +4 -3
- package/docs/user/memory.md +3 -0
- package/docs/user/notifications.md +84 -0
- package/docs/user/setup.md +4 -2
- package/docs/user/skills.md +2 -1
- package/package.json +2 -1
- package/src/behavior.ts +1 -1
- package/src/config.ts +103 -0
- package/src/db.ts +2 -2
- package/src/embeddings.ts +183 -8
- package/src/index.ts +4 -0
- package/src/notify.ts +123 -0
- package/src/prediction.ts +1 -1
- package/src/prompts.ts +27 -3
- package/src/scoring-engine.ts +25 -4
- package/src/skills.ts +1 -0
- package/src/tool-defs.ts +249 -40
|
@@ -85,9 +85,12 @@ Runs in a single DB transaction:
|
|
|
85
85
|
|
|
86
86
|
1. **Matcher dedup** — finds an existing matcher above cosine 0.85, else
|
|
87
87
|
creates one.
|
|
88
|
-
2. **Prediction dedup** — store
|
|
89
|
-
(cosine >= 0.85). If found, links this matcher to
|
|
90
|
-
creating a duplicate row.
|
|
88
|
+
2. **Prediction dedup** — search across the target store AND global for a
|
|
89
|
+
near-identical prediction (cosine >= 0.85). If found, links this matcher to
|
|
90
|
+
it via an edge rather than creating a duplicate row. The auto-fire nudge
|
|
91
|
+
scans both stores, so a prediction saved to both would otherwise surface
|
|
92
|
+
twice every turn; the write reinforces the existing row in its home store
|
|
93
|
+
and the result echoes where it landed.
|
|
91
94
|
3. **New prediction with a non-create signal** — applies the signal
|
|
92
95
|
immediately so the first confirm/disconfirm is not lost.
|
|
93
96
|
4. **`create` on an existing prediction** — links the edge and records
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# QA System
|
|
2
2
|
|
|
3
|
-
Thatch ships
|
|
4
|
-
a `bun:test` file that runs in an isolated environment — a
|
|
5
|
-
of the repo, not the working tree itself. Use cases are
|
|
6
|
-
**automatable** (no LLM, fast) and **live** (spawns opencode, costs
|
|
7
|
-
tokens).
|
|
3
|
+
Thatch ships a suite of QA use cases that verify end-to-end behavior. Each use
|
|
4
|
+
case is a `bun:test` file that runs in an isolated environment — a
|
|
5
|
+
temp-directory copy of the repo, not the working tree itself. Use cases are
|
|
6
|
+
split into **automatable** (no LLM, fast) and **live** (spawns opencode, costs
|
|
7
|
+
model tokens).
|
|
8
8
|
|
|
9
9
|
## What it does
|
|
10
10
|
|
|
11
|
-
- 95 use cases: 75 automatable + 20 live
|
|
12
11
|
- Automatable use cases run without an LLM — they test CLI behavior, hooks, DB
|
|
13
12
|
operations, and tool execution directly via bun assertions
|
|
14
13
|
- Live use cases spawn real opencode sessions — they test the full
|
|
@@ -39,7 +38,7 @@ registers all use cases in one suite, enabling `--concurrent
|
|
|
39
38
|
--max-concurrency 5` to run 5 use cases at once (33s vs 88s sequential for the
|
|
40
39
|
auto suite).
|
|
41
40
|
|
|
42
|
-
### Automatable use cases
|
|
41
|
+
### Automatable use cases
|
|
43
42
|
|
|
44
43
|
Run without an LLM. Test CLI behavior, hooks, DB operations, and tool
|
|
45
44
|
execution directly via bun assertions. These are fast and run in parallel.
|
|
@@ -66,14 +65,15 @@ execution directly via bun assertions. These are fast and run in parallel.
|
|
|
66
65
|
| UC-027 | behavior-confidence-model | ham/spam adjusts Bayesian confidence |
|
|
67
66
|
| UC-028 | behavior-delete | semantic-match deletion with cascade |
|
|
68
67
|
|
|
69
|
-
### Live use cases
|
|
68
|
+
### Live use cases
|
|
70
69
|
|
|
71
70
|
Spawn real opencode sessions. Test the full pipeline with a real model. These
|
|
72
|
-
cost model tokens and have a 20-minute per-use-case timeout.
|
|
73
|
-
|
|
74
|
-
(UC-006, UC-010, UC-013) are
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
cost model tokens and have a 20-minute per-use-case timeout. Live use cases
|
|
72
|
+
check for `opencode` on PATH at runtime: if it is present they run; if not,
|
|
73
|
+
they skip with `[MANUAL]`. Three (UC-006, UC-010, UC-013) are
|
|
74
|
+
`manualOnly: true` for infrastructure reasons (Cursor hook lifecycle, nested
|
|
75
|
+
opencode session timeout, compaction trigger). Run them locally with
|
|
76
|
+
`mise run qa-live`.
|
|
77
77
|
|
|
78
78
|
| UC | Name | What it tests |
|
|
79
79
|
|----|------|---------------|
|
|
@@ -182,8 +182,8 @@ includes all of `tests/`), just not executed during `check`. See
|
|
|
182
182
|
| `tests/qa/runner.ts` | `registerUseCase`, `UseCase` type, `ensureMaster`, `createFixture`, `runViaOpencode`, execution logic |
|
|
183
183
|
| `tests/qa/auto/index.test.ts` | Automatable use case barrel — imports all auto use case modules |
|
|
184
184
|
| `tests/qa/live/index.test.ts` | Live use case barrel — imports all live use case modules |
|
|
185
|
-
| `tests/qa/auto/uc-NNN-*.ts` |
|
|
186
|
-
| `tests/qa/live/uc-NNN-*.ts` |
|
|
185
|
+
| `tests/qa/auto/uc-NNN-*.ts` | Automatable use case files, one per use case |
|
|
186
|
+
| `tests/qa/live/uc-NNN-*.ts` | Live use case files, one per use case |
|
|
187
187
|
|
|
188
188
|
No separate QA docs directory exists. QA use cases live in `tests/qa/` as executable tests, not docs.
|
|
189
189
|
|
|
@@ -191,8 +191,9 @@ No separate QA docs directory exists. QA use cases live in `tests/qa/` as execut
|
|
|
191
191
|
|
|
192
192
|
1. **Automatable use cases never spawn an LLM.** They test CLI, hooks, DB, and
|
|
193
193
|
tool execution directly.
|
|
194
|
-
2. **Live use cases spawn real opencode sessions and cost model tokens.**
|
|
195
|
-
|
|
194
|
+
2. **Live use cases spawn real opencode sessions and cost model tokens.** They
|
|
195
|
+
skip with `[MANUAL]` when `opencode` is not on PATH; three are
|
|
196
|
+
`manualOnly: true` for infrastructure reasons.
|
|
196
197
|
3. **`QA_DRY_RUN=1` lists use cases without executing.** Use this for CI and
|
|
197
198
|
coverage review.
|
|
198
199
|
4. **Each use case follows the structured format**: preconditions, steps,
|
package/docs/dev/gotchas.md
CHANGED
|
@@ -146,3 +146,21 @@ here first. These are the things that have already cost time.
|
|
|
146
146
|
- **`bun test` does not typecheck**, and `tsconfig.json` excludes `tests`. Test
|
|
147
147
|
type errors are editor-only noise unless you run `tsc` on the test files
|
|
148
148
|
directly. Keep test files type-clean anyway so the editor stays quiet.
|
|
149
|
+
|
|
150
|
+
## Config and notifications
|
|
151
|
+
|
|
152
|
+
- **Tests touching the config must set `THATCH_DB_PATH`.** The config tools
|
|
153
|
+
derive the config file path from the environment (`THATCH_DB_PATH`, then the
|
|
154
|
+
XDG default), not from the test's tempdir `ThatchDB`. A config test that
|
|
155
|
+
skips this reads and writes the developer's real
|
|
156
|
+
`~/.config/thatch/config.json`. See `tests/notify.test.ts` for the
|
|
157
|
+
save-and-restore pattern.
|
|
158
|
+
- **osascript exits 0 even when macOS drops the banner.** Focus/Do Not Disturb
|
|
159
|
+
or missing notification permission silently swallow it. `notify_user` result
|
|
160
|
+
text therefore reports command success only; never interpret exit 0 as
|
|
161
|
+
delivery.
|
|
162
|
+
- **New QA use cases must be imported into the directory's barrel file**
|
|
163
|
+
(`tests/qa/auto/index.test.ts` or the live one). The `.ts` files are not
|
|
164
|
+
discovered by bun on their own. UC-095 sat out of the suite for a release
|
|
165
|
+
cycle and rotted (asserted 3 watch tools when 4 existed) because nobody
|
|
166
|
+
noticed it never ran.
|
package/docs/dev/mcp-parity.md
CHANGED
|
@@ -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** (
|
|
21
|
+
| **Tools** (single source of truth) | Plugin tool registration, `thatch_` prefix | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix (opencode-only tools filtered out) | MCP `tools/list` + `tools/call`, `mcp__thatch__` prefix (opencode-only tools filtered out) | **Full** for the shared tools; `get_session_info` (session identity) and `session_search`/`session_get` (conversation archaeology) are opencode-only — MCP hosts have no session concept. The `thatch session` CLI subcommands cover the same archaeology on any host with an opencode.db file. The `watch_*` tools (PR and branch watchers) are opencode-only — MCP hosts have no poller or proactive-prompt channel |
|
|
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 |
|
package/docs/dev/skills.md
CHANGED
|
@@ -29,9 +29,9 @@ description: Extract durable project facts ... Use when ...
|
|
|
29
29
|
Code, and Cursor all auto-discover skills and use the description for
|
|
30
30
|
relevance).
|
|
31
31
|
|
|
32
|
-
## The
|
|
32
|
+
## The skills
|
|
33
33
|
|
|
34
|
-
**Shared
|
|
34
|
+
**Shared** — installed everywhere; no sub-agents required:
|
|
35
35
|
|
|
36
36
|
| Skill | Role |
|
|
37
37
|
|-------|------|
|
|
@@ -46,6 +46,7 @@ description: Extract durable project facts ... Use when ...
|
|
|
46
46
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of behavior? |
|
|
47
47
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
48
48
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
49
|
+
| `thatch-review-mentorship` | Peer-mentorship lens: teaching-grade notes on unseen helpers/internal packages, companion techniques, house patterns, test-craft, API-shape principles, next-reader discoverability. Informational only, verified citations, never blocking. |
|
|
49
50
|
| `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. |
|
|
50
51
|
| `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, linked docs/tickets followed from the change, memory) before fan-out. Prevents false positives about intentionally deferred work, and checks whether main moved past the merge-base touching the same paths (staleness signal for the synthesizer). 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. |
|
|
51
52
|
| `thatch-code-archaeology` | Investigate an existing feature, debug an unfamiliar area, or begin a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. The research skill; pair with `thatch-coding-workflow`. |
|
|
@@ -61,11 +62,11 @@ description: Extract durable project facts ... Use when ...
|
|
|
61
62
|
| `thatch-memory-verify` | Fact-check a single memory against the current codebase and correct stale claims. Uses git archaeology to preserve historical context when changes were intentional. |
|
|
62
63
|
| `thatch-knowledge-export` | Compile everything thatch knows about a topic into a curated markdown file for knowledge transfer. Searches across stores, curates out personal noise, fact-checks code-related memories via `thatch-memory-verify`. |
|
|
63
64
|
|
|
64
|
-
**opencode-only
|
|
65
|
+
**opencode-only** — the coordinator needs sub-agent support:
|
|
65
66
|
|
|
66
67
|
| Skill | Role |
|
|
67
68
|
|-------|------|
|
|
68
|
-
| `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
|
|
69
|
+
| `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 review specialists in parallel, synthesize with a workflow-change preface and prior-comment cross-reference. |
|
|
69
70
|
|
|
70
71
|
## REVIEW_COMMON
|
|
71
72
|
|
|
@@ -92,6 +93,8 @@ The seven problem-finding review specialists share a framework interpolated via
|
|
|
92
93
|
ticket is closed or merged.
|
|
93
94
|
- **Output format** — `[SEVERITY] [CATEGORY] file:line` with finding, evidence
|
|
94
95
|
(quoted), trigger, reachability, source of truth, producer chain, provenance.
|
|
96
|
+
- **Wording** — findings are prose for humans, not shorthand: one idea per
|
|
97
|
+
sentence, no method names as verbs, one sentence per hop for producer chains.
|
|
95
98
|
|
|
96
99
|
The synthesizer reuses the same verification rigor but has its own structure
|
|
97
100
|
(it does not interpolate `REVIEW_COMMON`).
|
|
@@ -99,7 +102,7 @@ The synthesizer reuses the same verification rigor but has its own structure
|
|
|
99
102
|
## The two arrays
|
|
100
103
|
|
|
101
104
|
```ts
|
|
102
|
-
const SHARED_SKILLS: SkillDef[] = [ /*
|
|
105
|
+
const SHARED_SKILLS: SkillDef[] = [ /* all shared skills above */ ];
|
|
103
106
|
const OPENCODE_ONLY_SKILLS: SkillDef[] = [ /* code-review coordinator */ ];
|
|
104
107
|
```
|
|
105
108
|
|
|
@@ -138,7 +141,7 @@ and `--cursor` pass only the shared set.
|
|
|
138
141
|
## Memory review skills in practice
|
|
139
142
|
|
|
140
143
|
- **Quick single lens**: load any specialist directly and point it at a branch.
|
|
141
|
-
- **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all
|
|
144
|
+
- **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all review 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.
|
|
142
145
|
- **Full review on Claude Code/Cursor**: run each specialist in sequence, then
|
|
143
146
|
run `thatch-review-synthesizer` to verify and aggregate.
|
|
144
147
|
- **Follow-up round (re-review)**: load `thatch-review-followup` when the author
|
package/docs/user/README.md
CHANGED
|
@@ -12,6 +12,7 @@ This README is the overview. Each feature has its own guide:
|
|
|
12
12
|
- [memory.md](memory.md): persistent memory store
|
|
13
13
|
- [extraction.md](extraction.md): automatic fact extraction from tool calls
|
|
14
14
|
- [watchers.md](watchers.md): event-driven notifications (PR and branch watching)
|
|
15
|
+
- [notifications.md](notifications.md): banner and voice notifications, user config
|
|
15
16
|
- [prediction-engine.md](prediction-engine.md): user decision model
|
|
16
17
|
- [behavior-engine.md](behavior-engine.md): agent self-discipline rules
|
|
17
18
|
- [default-behaviors.md](default-behaviors.md): what ships automatically
|
|
@@ -143,6 +144,22 @@ Stores are created automatically. No setup required.
|
|
|
143
144
|
| `thatch_behavior_list` | List all codified behaviors with matchers, confidence, and provenance. |
|
|
144
145
|
| `thatch_behavior_delete` | Delete a behavior by semantic match. Edges and provenance are cascade-deleted. |
|
|
145
146
|
|
|
147
|
+
### Config tools
|
|
148
|
+
|
|
149
|
+
| Tool | What it does |
|
|
150
|
+
|------|-------------|
|
|
151
|
+
| `thatch_config_get` | Read the user config (`~/.config/thatch/config.json`), with defaults annotated. The agent manages config through these tools; you can also edit the file by hand. |
|
|
152
|
+
| `thatch_config_set` | Update config fields. Field-level merge: only fields you pass change. Returns the resulting section so the agent can verify. |
|
|
153
|
+
|
|
154
|
+
### Notification tools
|
|
155
|
+
|
|
156
|
+
| Tool | What it does |
|
|
157
|
+
|------|-------------|
|
|
158
|
+
| `thatch_notify_user` | Notify the user out-of-band: desktop banner and/or spoken voice. Use for long-running outcomes worth interrupting for (CI results, deploys, watcher events). macOS and Linux. |
|
|
159
|
+
|
|
160
|
+
See [notifications.md](notifications.md) for the full behavior and
|
|
161
|
+
configuration.
|
|
162
|
+
|
|
146
163
|
### Session tools (opencode only)
|
|
147
164
|
|
|
148
165
|
| Tool | What it does |
|
|
@@ -159,7 +176,8 @@ search` - JSONL output designed for piping to `jq` or `grep`.
|
|
|
159
176
|
|
|
160
177
|
| Tool | What it does |
|
|
161
178
|
|------|-------------|
|
|
162
|
-
| `thatch_watch_create` | Watch a GitHub PR for events (comments, review comments and replies, commits, status changes, description edits, CI completions). The plugin polls in the background and prompts the session when a watched event happens. |
|
|
179
|
+
| `thatch_watch_create` | Watch a GitHub PR for events (comments, review comments and replies, thread resolutions, commits, status changes, description edits, CI completions). The plugin polls in the background and prompts the session when a watched event happens. |
|
|
180
|
+
| `thatch_watch_branch_create` | Watch a GitHub branch (typically main) for commit landings, CI check-run completions, and workflow runs, with an optional workflow-name filter. |
|
|
163
181
|
| `thatch_watch_list` | List this session's active watchers. |
|
|
164
182
|
| `thatch_watch_cancel` | Cancel one of this session's watchers by id. |
|
|
165
183
|
|
|
@@ -260,6 +278,7 @@ response, walkthrough, and workflow skills that support the review pipeline:
|
|
|
260
278
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
|
|
261
279
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
262
280
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
281
|
+
| `thatch-review-mentorship` | Peer-mentorship lens: teaching-grade notes on unseen helpers/internal packages, companion techniques, house patterns, test-craft, API-shape principles, next-reader discoverability. Informational only, never blocking. |
|
|
263
282
|
| `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. |
|
|
264
283
|
| `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, linked docs/tickets, memory) before a review. Prevents false positives about intentionally deferred work. |
|
|
265
284
|
| `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. Pairs with `thatch-coding-workflow`. |
|
|
@@ -287,14 +306,14 @@ response, walkthrough, and workflow skills that support the review pipeline:
|
|
|
287
306
|
|
|
288
307
|
| Skill | opencode | Claude Code | Cursor |
|
|
289
308
|
|-------|----------|-------------|--------|
|
|
290
|
-
| Memory skills
|
|
291
|
-
| Review specialists
|
|
309
|
+
| Memory skills | Yes | Yes | Yes |
|
|
310
|
+
| Review specialists | Yes | Yes | Yes |
|
|
292
311
|
| Review synthesizer | Yes | Yes | Yes |
|
|
293
312
|
| Review context + code archaeology | Yes | Yes | Yes |
|
|
294
313
|
| Review followup | Yes | Yes | Yes |
|
|
295
314
|
| Review response (author-side) | Yes | Yes | Yes |
|
|
296
|
-
| Walkthrough skills
|
|
297
|
-
| Writing skills
|
|
315
|
+
| Walkthrough skills | Yes | Yes | Yes |
|
|
316
|
+
| Writing skills | Yes | Yes | Yes |
|
|
298
317
|
| Code review coordinator | Yes | No (requires sub-agents) | No (requires sub-agents) |
|
|
299
318
|
|
|
300
319
|
### Using review skills
|
|
@@ -379,19 +398,24 @@ Store defaults to your current git repo.
|
|
|
379
398
|
|
|
380
399
|
## Configuration
|
|
381
400
|
|
|
382
|
-
|
|
401
|
+
Most configuration needs none. Two layers exist:
|
|
383
402
|
|
|
384
|
-
- **
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
### Environment variables
|
|
403
|
+
- **Preferences the agent manages** live in
|
|
404
|
+
`~/.config/thatch/config.json` (beside the database): notification mode,
|
|
405
|
+
voice, and sound. Ask your agent ("set notifications to banner only") or
|
|
406
|
+
edit the file by hand. See [notifications.md](notifications.md).
|
|
407
|
+
- **Environment variables** for infrastructure:
|
|
390
408
|
|
|
391
409
|
| Variable | Default | Description |
|
|
392
410
|
|----------|---------|-------------|
|
|
393
|
-
| `THATCH_DB_PATH` | `$XDG_CONFIG_HOME/thatch/thatch.db` | Override database location |
|
|
411
|
+
| `THATCH_DB_PATH` | `$XDG_CONFIG_HOME/thatch/thatch.db` | Override database location (the config file follows it) |
|
|
394
412
|
| `THATCH_MODEL` | `Xenova/bge-small-en-v1.5` | Override embedding model |
|
|
413
|
+
| `THATCH_EMBEDDING_BACKEND` | `wasm` | Set to `native` to run embeddings on onnxruntime-node (NAPI) instead of the wasm runtime |
|
|
414
|
+
|
|
415
|
+
Unchanged defaults: the database is created automatically, the embedding
|
|
416
|
+
model downloads once and is cached, the store name is auto-detected from
|
|
417
|
+
`git remote get-url origin`, and search always includes the project store
|
|
418
|
+
and `global`.
|
|
395
419
|
|
|
396
420
|
`$XDG_CONFIG_HOME` defaults to `~/.config` when unset.
|
|
397
421
|
|
package/docs/user/code-review.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Code Review
|
|
2
2
|
|
|
3
|
-
Thatch ships a multi-agent code review pipeline.
|
|
3
|
+
Thatch ships a multi-agent code review pipeline. Nine specialist
|
|
4
4
|
review lenses run in parallel, then a synthesizer verifies and
|
|
5
5
|
deduplicates their findings into a single report.
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ the review:
|
|
|
22
22
|
3. **Research affected workflows**: load `thatch-code-archaeology`,
|
|
23
23
|
trace the code paths the change touches.
|
|
24
24
|
4. **Estimate complexity**: partition the diff into review units.
|
|
25
|
-
5. **Dispatch specialists**: fan out the
|
|
25
|
+
5. **Dispatch specialists**: fan out the nine specialists as
|
|
26
26
|
parallel sub-agents, each with the context brief.
|
|
27
27
|
6. **Synthesize**: the synthesizer reads all specialist output,
|
|
28
28
|
verifies each finding (cited text exists, claim is accurate,
|
|
@@ -31,7 +31,7 @@ the review:
|
|
|
31
31
|
re-verifies behavioral findings against current main and reports
|
|
32
32
|
merge-base-only findings as rebase notes rather than defects.
|
|
33
33
|
|
|
34
|
-
## The
|
|
34
|
+
## The nine specialists
|
|
35
35
|
|
|
36
36
|
| Skill | What it checks |
|
|
37
37
|
|-------|-------------|
|
|
@@ -43,6 +43,7 @@ the review:
|
|
|
43
43
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
|
|
44
44
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
45
45
|
| `thatch-review-highlights` | Positive finding detection: clever solutions, cleanup done along the way, documentation that helps. Medium-high bar. |
|
|
46
|
+
| `thatch-review-mentorship` | Peer-mentorship lens: teaching-grade notes on unseen helpers/internal packages, companion techniques, house patterns, test-craft, API-shape principles, next-reader discoverability. Informational only, never blocking. |
|
|
46
47
|
|
|
47
48
|
Each specialist is a self-contained static-analysis pass. They can run
|
|
48
49
|
individually or as part of the coordinated review.
|
package/docs/user/memory.md
CHANGED
|
@@ -49,6 +49,9 @@ store when recalling.
|
|
|
49
49
|
(MCP).
|
|
50
50
|
- `THATCH_MODEL`: Hugging Face model name for embeddings. Defaults to
|
|
51
51
|
`Xenova/bge-small-en-v1.5` (34 MB, 384-dimensional).
|
|
52
|
+
- `THATCH_EMBEDDING_BACKEND`: embedding compute backend. Defaults to
|
|
53
|
+
`wasm` (pure JavaScript/WebAssembly, no native addons). Set to
|
|
54
|
+
`native` to use the onnxruntime-node addon instead.
|
|
52
55
|
- `THATCH_RECALL_THRESHOLD`: cosine score threshold for the recall
|
|
53
56
|
nudge. Defaults to 0.55. Lower surfaces more matches (noisier);
|
|
54
57
|
higher surfaces fewer (stricter).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Notifications
|
|
2
|
+
|
|
3
|
+
Thatch can notify you out-of-band when something happens worth leaving the
|
|
4
|
+
terminal for: a CI run finishing, a merge or deploy completing, a watched PR
|
|
5
|
+
receiving a comment. The notification is a desktop banner, a spoken voice
|
|
6
|
+
announcement, or both, depending on your preferences.
|
|
7
|
+
|
|
8
|
+
This works on every host (opencode, Claude Code, Cursor) because it is plain
|
|
9
|
+
child processes, not host plumbing.
|
|
10
|
+
|
|
11
|
+
## The tools
|
|
12
|
+
|
|
13
|
+
| Tool | What it does |
|
|
14
|
+
|------|-------------|
|
|
15
|
+
| `thatch_notify_user` | Send a banner and/or spoken notification. |
|
|
16
|
+
| `thatch_config_get` | Read the current config, with defaults annotated. |
|
|
17
|
+
| `thatch_config_set` | Update config fields. Returns the resulting section. |
|
|
18
|
+
|
|
19
|
+
### notify_user
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
thatch_notify_user(message: "CI is green, clear for merge",
|
|
23
|
+
source: "PLAT-280")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **macOS**: banner via Notification Center (with an alert sound) and voice
|
|
27
|
+
via the built-in `say` command.
|
|
28
|
+
- **Linux**: banner via `notify-send` (libnotify) and voice via
|
|
29
|
+
`spd-say`/`espeak` when installed. Missing tools are reported, never fatal.
|
|
30
|
+
- **Windows**: not supported. The tool reports this instead of guessing.
|
|
31
|
+
|
|
32
|
+
The agent includes a `source` label (a ticket number or feature name) so you
|
|
33
|
+
know which of your concurrent sessions is speaking. Voice text spells out
|
|
34
|
+
letter sequences ("C I green", not "CI green") so text-to-speech pronounces
|
|
35
|
+
them.
|
|
36
|
+
|
|
37
|
+
The tool result reports command success only. macOS focus modes can silently
|
|
38
|
+
swallow banners; if you are not seeing them, check Focus settings and that
|
|
39
|
+
your terminal app has notification permission.
|
|
40
|
+
|
|
41
|
+
## Configuring notifications
|
|
42
|
+
|
|
43
|
+
You have two options, and they edit the same file:
|
|
44
|
+
|
|
45
|
+
1. **Ask your agent.** "Set notifications to banner only" -- the agent reads
|
|
46
|
+
current values with `config_get`, changes what you asked for with
|
|
47
|
+
`config_set`, and shows you the result.
|
|
48
|
+
2. **Edit the file yourself.** The config lives at
|
|
49
|
+
`~/.config/thatch/config.json` (next to `thatch.db`, or under
|
|
50
|
+
`$XDG_CONFIG_HOME`).
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"notifications": {
|
|
55
|
+
"mode": "both",
|
|
56
|
+
"voice": "Zarvox",
|
|
57
|
+
"sound": "Submarine"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
| Field | Values | Default | Applies to |
|
|
63
|
+
|-------|--------|---------|------------|
|
|
64
|
+
| `mode` | `both`, `banner`, `voice`, `none` | `both` | Which channels `notify_user` uses. `none` disables notifications entirely; the agent is told it no-opped. |
|
|
65
|
+
| `voice` | any installed voice name | `Zarvox` (macOS) | Spoken announcements. List macOS voices with `/usr/bin/say -v '?'`. |
|
|
66
|
+
| `sound` | any system sound name | `Submarine` (macOS) | Banner alert sound. Sounds live in `/System/Library/Sounds`. |
|
|
67
|
+
|
|
68
|
+
Fields you leave out fall back to the defaults. Unknown sections or fields
|
|
69
|
+
are rejected when the file is read, and the config is ignored with a warning
|
|
70
|
+
if it cannot be parsed -- a broken hand edit never crashes the agent, it just
|
|
71
|
+
falls back to defaults.
|
|
72
|
+
|
|
73
|
+
The agent can manage the whole file for you through `config_get` /
|
|
74
|
+
`config_set`; edits merge at the field level, so the agent changing your
|
|
75
|
+
voice cannot wipe your mode.
|
|
76
|
+
|
|
77
|
+
## Limitations
|
|
78
|
+
|
|
79
|
+
- Banners are best-effort by nature of the OS. The agent can only report
|
|
80
|
+
whether the command ran, not whether you saw the banner.
|
|
81
|
+
- Speech is awaited: the tool returns after the sentence finishes. Notifications
|
|
82
|
+
are short by design.
|
|
83
|
+
- There is no debounce. If an agent polls a status in a tight loop, it should
|
|
84
|
+
notify once at the end, not per poll.
|
package/docs/user/setup.md
CHANGED
|
@@ -75,6 +75,7 @@ and `--json` output for hook commands.
|
|
|
75
75
|
|----------|---------|-----------------|
|
|
76
76
|
| `THATCH_DB_PATH` | `~/.config/thatch/thatch.db` | SQLite database path |
|
|
77
77
|
| `THATCH_MODEL` | `Xenova/bge-small-en-v1.5` | Hugging Face model name for embeddings |
|
|
78
|
+
| `THATCH_EMBEDDING_BACKEND` | `wasm` | Set to `native` to run embeddings on onnxruntime-node (NAPI) instead of the wasm runtime |
|
|
78
79
|
| `THATCH_RECALL_THRESHOLD` | `0.55` | Cosine threshold for recall nudge |
|
|
79
80
|
| `THATCH_PREDICTION_THRESHOLD` | `0.60` | Cosine threshold for prediction auto-fire |
|
|
80
81
|
| `THATCH_BEHAVIOR_THRESHOLD` | `0.60` | Cosine threshold for behavior auto-fire |
|
|
@@ -101,8 +102,9 @@ instructions are deployed without requiring you to manually re-run
|
|
|
101
102
|
cached in `node_modules/@huggingface/transformers/.cache/`.
|
|
102
103
|
- There is no web UI or dashboard. All interaction is through the
|
|
103
104
|
agent's tool calls and the `thatch` CLI.
|
|
104
|
-
- The MCP server is a long-lived process that
|
|
105
|
-
|
|
105
|
+
- The MCP server is a long-lived process that keeps the embedding model
|
|
106
|
+
loaded while it is in use, releases it after 10 idle minutes, and
|
|
107
|
+
re-loads it on demand. Hook commands connect to it via a Unix domain
|
|
106
108
|
socket (the sideband) to avoid loading the model themselves.
|
|
107
109
|
|
|
108
110
|
See [memory.md](memory.md) for the memory system,
|
package/docs/user/skills.md
CHANGED
|
@@ -20,7 +20,7 @@ becomes part of the agent's context.
|
|
|
20
20
|
|
|
21
21
|
## What ships
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Skills are split into shared (all hosts) and opencode-only:
|
|
24
24
|
|
|
25
25
|
### Memory skills
|
|
26
26
|
|
|
@@ -45,6 +45,7 @@ becomes part of the agent's context.
|
|
|
45
45
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
|
|
46
46
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
47
47
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar. |
|
|
48
|
+
| `thatch-review-mentorship` | Peer-mentorship lens: teaching-grade notes on unseen helpers/internal packages, companion techniques, house patterns, test-craft, API-shape principles, next-reader discoverability. Informational only, never blocking. |
|
|
48
49
|
| `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a deduplicated, severity-grouped report. |
|
|
49
50
|
| `thatch-review-context` | Gathers project context (PRs, tickets, linked docs/designs followed from the change, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
|
|
50
51
|
| `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. The research skill; pair with `thatch-coding-workflow`. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffober/thatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
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",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@huggingface/transformers": "^4.0.0",
|
|
27
|
+
"onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
|
|
27
28
|
"zod": "^4.1.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
package/src/behavior.ts
CHANGED
|
@@ -82,7 +82,7 @@ export class BehaviorEngine {
|
|
|
82
82
|
return this.#engine.createMatcher(store, description, embedding, model);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
findNearestBehavior(store: string, embedding: Float32Array, threshold: number): BehaviorRow | null {
|
|
85
|
+
findNearestBehavior(store: string | string[], embedding: Float32Array, threshold: number): BehaviorRow | null {
|
|
86
86
|
return this.#engine.findNearestItem(store, embedding, threshold) as BehaviorRow | null;
|
|
87
87
|
}
|
|
88
88
|
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
|
|
6
|
+
// Thatch user config: one JSON file beside thatch.db, hand-editable and
|
|
7
|
+
// managed by the config_get / config_set tools. Sections are strict (unknown
|
|
8
|
+
// keys fail validation instead of being silently dropped) so a hand edit or a
|
|
9
|
+
// newer-version file can never lose data by round-tripping through an older
|
|
10
|
+
// process. config_set merges at the field level: omitted fields keep their
|
|
11
|
+
// values, so a partial section update never wipes sibling preferences.
|
|
12
|
+
|
|
13
|
+
export const notificationPrefsSchema = z.strictObject({
|
|
14
|
+
mode: z.enum(["both", "banner", "voice", "none"]).optional(),
|
|
15
|
+
voice: z.string().optional(),
|
|
16
|
+
sound: z.string().optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const configSchema = z.strictObject({
|
|
20
|
+
notifications: notificationPrefsSchema.optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export type NotificationPrefs = z.infer<typeof notificationPrefsSchema>;
|
|
24
|
+
export type Config = z.infer<typeof configSchema>;
|
|
25
|
+
|
|
26
|
+
/** Sections in presentation order. config_get / config_set iterate this. */
|
|
27
|
+
export const CONFIG_SECTIONS = ["notifications"] as const;
|
|
28
|
+
export type ConfigSection = (typeof CONFIG_SECTIONS)[number];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the config file path. By convention it lives next to thatch.db,
|
|
32
|
+
* so a custom THATCH_DB_PATH moves the config with it. Tests pass an
|
|
33
|
+
* explicit dbPath to keep writes inside a tempdir.
|
|
34
|
+
*/
|
|
35
|
+
export function configFilePath(dbPath?: string): string {
|
|
36
|
+
if (dbPath) return join(dirname(dbPath), "config.json");
|
|
37
|
+
const dir = process.env.THATCH_DB_PATH
|
|
38
|
+
? dirname(process.env.THATCH_DB_PATH)
|
|
39
|
+
: join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "thatch");
|
|
40
|
+
return join(dir, "config.json");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface LoadedConfig {
|
|
44
|
+
config: Config;
|
|
45
|
+
/** Non-null when the file exists but is unparseable; the file is ignored. */
|
|
46
|
+
warning: string | null;
|
|
47
|
+
path: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Reads the config file. A missing file is the empty config, not an error. */
|
|
51
|
+
export function loadConfig(dbPath?: string): LoadedConfig {
|
|
52
|
+
const path = configFilePath(dbPath);
|
|
53
|
+
let raw: string;
|
|
54
|
+
try {
|
|
55
|
+
raw = readFileSync(path, "utf8");
|
|
56
|
+
} catch {
|
|
57
|
+
return { config: {}, warning: null, path };
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const parsed = configSchema.parse(JSON.parse(raw));
|
|
61
|
+
return { config: parsed, warning: null, path };
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return {
|
|
64
|
+
config: {},
|
|
65
|
+
warning: `config file at ${path} is invalid and was ignored (${err instanceof Error ? err.message : String(err)})`,
|
|
66
|
+
path,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Writes the config atomically (temp file + rename) so a crash mid-write
|
|
73
|
+
* cannot leave a truncated file, and concurrent readers never see a partial
|
|
74
|
+
* document.
|
|
75
|
+
*/
|
|
76
|
+
export function saveConfig(config: Config, dbPath?: string): string {
|
|
77
|
+
const path = configFilePath(dbPath);
|
|
78
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
79
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
80
|
+
writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n");
|
|
81
|
+
renameSync(tmp, path);
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Field-level merge for one section: omitted fields keep their values. */
|
|
86
|
+
export function mergeNotificationPrefs(
|
|
87
|
+
current: NotificationPrefs | undefined,
|
|
88
|
+
patch: NotificationPrefs,
|
|
89
|
+
): NotificationPrefs {
|
|
90
|
+
return { ...current, ...patch };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Platform fallbacks shown by config_get and applied by notify_user when the
|
|
95
|
+
* user has not set a preference. Only darwin has opinionated defaults; other
|
|
96
|
+
* platforms use their tools' own voices and sounds.
|
|
97
|
+
*/
|
|
98
|
+
export function notificationDefaults(): { mode: "both" | "banner" | "voice" | "none"; voice?: string; sound?: string } {
|
|
99
|
+
if (process.platform === "darwin") {
|
|
100
|
+
return { mode: "both", voice: "Zarvox", sound: "Submarine" };
|
|
101
|
+
}
|
|
102
|
+
return { mode: "both" };
|
|
103
|
+
}
|
package/src/db.ts
CHANGED
|
@@ -612,7 +612,7 @@ export class ThatchDB {
|
|
|
612
612
|
return this.#predictions.createMatcher(store, description, embedding, model);
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
findNearestPrediction(store: string, embedding: Float32Array, threshold: number) {
|
|
615
|
+
findNearestPrediction(store: string | string[], embedding: Float32Array, threshold: number) {
|
|
616
616
|
return this.#predictions.findNearestPrediction(store, embedding, threshold);
|
|
617
617
|
}
|
|
618
618
|
|
|
@@ -672,7 +672,7 @@ export class ThatchDB {
|
|
|
672
672
|
return this.#behaviors.createBehaviorMatcher(store, description, embedding, model);
|
|
673
673
|
}
|
|
674
674
|
|
|
675
|
-
findNearestBehavior(store: string, embedding: Float32Array, threshold: number) {
|
|
675
|
+
findNearestBehavior(store: string | string[], embedding: Float32Array, threshold: number) {
|
|
676
676
|
return this.#behaviors.findNearestBehavior(store, embedding, threshold);
|
|
677
677
|
}
|
|
678
678
|
|