@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.
@@ -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-wide search for a near-identical prediction
89
- (cosine >= 0.85). If found, links this matcher to it via an edge rather than
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 95 QA use cases that verify end-to-end behavior. Each use case is
4
- a `bun:test` file that runs in an isolated environment — a temp-directory copy
5
- of the repo, not the working tree itself. Use cases are split into
6
- **automatable** (no LLM, fast) and **live** (spawns opencode, costs model
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 (73)
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 (20)
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. All 20 are marked
73
- `manualOnly: true` — the opencode binary is not available in CI, and three
74
- (UC-006, UC-010, UC-013) are manual-only for fundamental reasons (Cursor hook
75
- lifecycle, nested opencode session timeout, compaction trigger). Run them
76
- locally with `mise run qa-live`.
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` | 75 automatable use case files |
186
- | `tests/qa/live/uc-NNN-*.ts` | 20 live use case files |
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.** All
195
- 20 are marked `manualOnly` — the opencode binary is not available in CI.
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,
@@ -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.
@@ -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** (18 shared + 7 opencode-only, 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 18 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 watchers) are opencode-only — MCP hosts have no poller or proactive-prompt channel |
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 |
@@ -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 26 skills
32
+ ## The skills
33
33
 
34
- **Shared (25)** — installed everywhere; no sub-agents required:
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 (1)** — the coordinator needs sub-agent support:
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 8 specialists in parallel, synthesize with a workflow-change preface and prior-comment cross-reference. |
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[] = [ /* 26 skills above */ ];
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 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.
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
@@ -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 (6) | Yes | Yes | Yes |
291
- | Review specialists (8) | Yes | Yes | Yes |
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 (2) | Yes | Yes | Yes |
297
- | Writing skills (3) | Yes | Yes | Yes |
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
- No configuration needed. The default behavior:
401
+ Most configuration needs none. Two layers exist:
383
402
 
384
- - **Database**: `~/.config/thatch/thatch.db` (created automatically)
385
- - **Embedding model**: bge-small-en-v1.5 (downloaded once, cached locally)
386
- - **Store name**: auto-detected from `git remote get-url origin`
387
- - **Search scope**: always includes the project store and `global`
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
 
@@ -1,6 +1,6 @@
1
1
  # Code Review
2
2
 
3
- Thatch ships a multi-agent code review pipeline. Eight specialist
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 eight specialists as
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 eight specialists
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.
@@ -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.
@@ -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 holds the warm embedding
105
- model in memory. Hook commands connect to it via a Unix domain
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,
@@ -20,7 +20,7 @@ becomes part of the agent's context.
20
20
 
21
21
  ## What ships
22
22
 
23
- 26 skills total (25 shared, 1 opencode-only):
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.38",
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