@jeffober/thatch 0.1.25 → 0.1.27
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 +7 -7
- package/artifacts/skills/common.md +1 -1
- package/artifacts/skills/thatch-change-walkthrough.md +2 -2
- package/artifacts/skills/thatch-code-archaeology.md +252 -0
- package/artifacts/skills/thatch-code-review.md +4 -4
- package/artifacts/skills/thatch-code-walkthrough.md +2 -2
- package/artifacts/skills/thatch-coding-workflow.md +79 -0
- package/artifacts/skills/{pr-description.md → thatch-pr-description.md} +1 -1
- package/artifacts/skills/thatch-review-context.md +9 -0
- package/artifacts/skills/thatch-review-followup.md +281 -0
- package/artifacts/skills/thatch-review-pedantic.md +16 -1
- package/artifacts/skills/thatch-review-response.md +365 -0
- package/artifacts/skills/thatch-review-synthesizer.md +92 -5
- package/artifacts/skills/{split-overlarge-pr.md → thatch-split-overlarge-pr.md} +1 -1
- package/artifacts/skills/{ticket-description.md → thatch-ticket-description.md} +3 -3
- package/bin/release +3 -3
- package/bin/thatch +8 -8
- package/docs/dev/README.md +1 -1
- package/docs/dev/skills.md +34 -9
- package/docs/plans/README.md +9 -6
- package/docs/plans/intuition-drives.md +147 -0
- package/docs/plans/nomenclater.md +89 -0
- package/docs/plans/prediction-consolidation.md +361 -0
- package/docs/qa/README.md +20 -3
- package/docs/user/README.md +33 -5
- package/package.json +1 -1
- package/src/db.ts +6 -6
- package/src/embeddings.ts +2 -2
- package/src/extract-queue.ts +4 -4
- package/src/extraction.ts +4 -4
- package/src/git.ts +1 -1
- package/src/hygiene.ts +1 -1
- package/src/index.ts +28 -28
- package/src/mcp.ts +5 -5
- package/src/prompts.ts +71 -65
- package/src/setup.ts +19 -19
- package/src/sideband.ts +3 -3
- package/src/skills.ts +105 -6
- package/src/tool-defs.ts +11 -11
- package/src/tools.ts +1 -1
- package/artifacts/skills/thatch-workflow-research.md +0 -91
- package/docs/in-progress/prediction-engine.md +0 -404
- package/docs/plans/001-memory-store.md +0 -106
- package/docs/plans/002-agent-driven-pipelines.md +0 -59
- package/docs/plans/003-memory-hygiene.md +0 -61
- package/docs/qa/use-cases/README.md +0 -51
- package/docs/qa/use-cases/UC-001-memory-roundtrip.md +0 -20
- package/docs/qa/use-cases/UC-002-dedup-cycle.md +0 -23
- package/docs/qa/use-cases/UC-003-extraction-nudge.md +0 -56
- package/docs/qa/use-cases/UC-004-cli-inspection.md +0 -22
- package/docs/qa/use-cases/UC-005-setup-install.md +0 -34
- package/docs/qa/use-cases/UC-006-cursor-hook-lifecycle.md +0 -32
- package/docs/qa/use-cases/UC-007-recall-nudge.md +0 -31
- package/docs/qa/use-cases/UC-008-hygiene-heartbeat.md +0 -26
- package/docs/qa/use-cases/UC-009-flush-tools-tiers.md +0 -33
- package/docs/qa/use-cases/UC-010-prime.md +0 -25
- package/docs/qa/use-cases/UC-011-write-time-similarity-warning.md +0 -24
- package/docs/qa/use-cases/UC-012-model-migration.md +0 -28
- package/docs/qa/use-cases/UC-013-compaction-context.md +0 -25
- package/docs/qa/use-cases/UC-014-skill-install-drift.md +0 -28
- package/docs/qa/use-cases/UC-015-env-override-matrix.md +0 -28
- package/docs/qa/use-cases/UC-016-concurrent-session-isolation.md +0 -37
- package/docs/qa/use-cases/UC-017-buffer-tool-vs-buffer-batch.md +0 -27
- package/docs/qa/use-cases/UC-018-mcp-startup-setup-detection.md +0 -38
- package/docs/qa/use-cases/UC-019-archived-memory-lifecycle.md +0 -36
- package/docs/qa/use-cases/UC-020-extraction-escalation.md +0 -52
- package/docs/qa/use-cases/UC-021-prediction-autofire.md +0 -21
- package/docs/qa/use-cases/UC-022-prediction-dedup.md +0 -19
- package/docs/qa/use-cases/UC-023-prediction-confidence-model.md +0 -23
- package/docs/qa/use-cases/UC-024-prediction-delete.md +0 -20
package/src/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { installSkills, SHARED_SKILLS, OPENCODE_ONLY_SKILLS } from "./skills";
|
|
|
19
19
|
import { hygieneReport } from "./hygiene";
|
|
20
20
|
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
|
-
// V1 server export
|
|
22
|
+
// V1 server export - tools, prompt injection, session hooks
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
|
|
25
25
|
// Minimum cosine score for the prompt-aware recall nudge. Lower than
|
|
@@ -27,7 +27,7 @@ import { hygieneReport } from "./hygiene";
|
|
|
27
27
|
// than "duplicate." Tunable via THATCH_RECALL_THRESHOLD.
|
|
28
28
|
const RECALL_THRESHOLD = parseFloat(process.env.THATCH_RECALL_THRESHOLD ?? "0.55");
|
|
29
29
|
|
|
30
|
-
// Prompts shorter than this skip the recall nudge
|
|
30
|
+
// Prompts shorter than this skip the recall nudge - trivially short prompts
|
|
31
31
|
// like "yes" or "ok" match too broadly to be useful.
|
|
32
32
|
const MIN_PROMPT_LEN = 10;
|
|
33
33
|
|
|
@@ -50,12 +50,12 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
50
50
|
const extraction = new ExtractionPipeline();
|
|
51
51
|
|
|
52
52
|
// Sessions currently being compacted. chat.message nudges are skipped while
|
|
53
|
-
// a session is in this set
|
|
53
|
+
// a session is in this set - the agent can't call tools during summary
|
|
54
54
|
// generation, so a recall or extraction nudge would cause a blocked-tool
|
|
55
55
|
// error. Cleared by experimental.compaction.autocontinue (success), the
|
|
56
56
|
// session.compacted event (redundant belt-and-suspenders), or chat.message
|
|
57
57
|
// itself when a non-compaction message arrives (compaction failure fallback
|
|
58
|
-
//
|
|
58
|
+
// - autocontinue never fired, so the next real user message clears the
|
|
59
59
|
// stale flag). If all three somehow miss, the flag leaks (graceful
|
|
60
60
|
// degradation: nudges stay off for that session, but no crash).
|
|
61
61
|
const compacting = new Set<string>();
|
|
@@ -78,7 +78,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
78
78
|
// When the child writes a memory, consumeSnapshot drains only these entries
|
|
79
79
|
// (by reference identity), preserving interleaved-turn entries that arrived
|
|
80
80
|
// while the sub-agent was running. Without this, the child's memory_remember
|
|
81
|
-
// would drain the parent's ENTIRE buffer
|
|
81
|
+
// would drain the parent's ENTIRE buffer - silently dropping facts from
|
|
82
82
|
// any tool calls the parent made concurrently with the sub-agent.
|
|
83
83
|
const parentSnapshots = new Map<string, ToolInteraction[]>();
|
|
84
84
|
|
|
@@ -108,7 +108,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
108
108
|
// Keyed by child session ID. Cleaned up on child idle, error, or deletion.
|
|
109
109
|
const childMetrics = new Map<string, { new: number; updated: number; deleted: number }>();
|
|
110
110
|
|
|
111
|
-
// Skills always install to the global opencode config
|
|
111
|
+
// Skills always install to the global opencode config - installing into the
|
|
112
112
|
// worktree would mutate the user's repo (untracked files in git status).
|
|
113
113
|
// A failed install degrades the nudge workflow but must not kill the plugin.
|
|
114
114
|
try {
|
|
@@ -129,7 +129,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
129
129
|
// drain machinery handles buffer cleanup. The nudge path is a fallback if
|
|
130
130
|
// this throws.
|
|
131
131
|
//
|
|
132
|
-
// Does NOT call extraction.accept
|
|
132
|
+
// Does NOT call extraction.accept - entries stay in pending so consumeSnapshot
|
|
133
133
|
// can drain them by reference identity when the child writes a memory. The
|
|
134
134
|
// extracting set (not accept) suppresses the nudge in chat.message.
|
|
135
135
|
//
|
|
@@ -183,7 +183,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
183
183
|
throw err;
|
|
184
184
|
}
|
|
185
185
|
} else {
|
|
186
|
-
// Fire and forget
|
|
186
|
+
// Fire and forget - the parent is already idle, so blocking the event
|
|
187
187
|
// handler would only delay other event processing. The child runs to
|
|
188
188
|
// completion and its idle event triggers cleanup.
|
|
189
189
|
client.session
|
|
@@ -203,12 +203,12 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
203
203
|
return {
|
|
204
204
|
tool: createTools(db, model, repo),
|
|
205
205
|
|
|
206
|
-
// 1. System prompt
|
|
206
|
+
// 1. System prompt - always in context.
|
|
207
207
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
208
208
|
output.system.push(sys);
|
|
209
209
|
},
|
|
210
210
|
|
|
211
|
-
// 2. Compaction context
|
|
211
|
+
// 2. Compaction context - re-familiarizes after compaction. The flag
|
|
212
212
|
// suppresses chat.message nudges during summary generation (tool
|
|
213
213
|
// calls are blocked there).
|
|
214
214
|
"experimental.session.compacting": async (input, output) => {
|
|
@@ -222,15 +222,15 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
222
222
|
compacting.delete(input.sessionID);
|
|
223
223
|
},
|
|
224
224
|
|
|
225
|
-
// 3. Tool buffering
|
|
225
|
+
// 3. Tool buffering - feeds the extraction pipeline (direct extraction
|
|
226
226
|
// via SDK or nudge fallback). Excluded tools:
|
|
227
227
|
// - thatch_*: extracting facts from memory ops would echo the store
|
|
228
228
|
// - skill/task: meta-tools that orchestrate agent behavior (loading
|
|
229
229
|
// skills, dispatching sub-agents). Buffering them creates a feedback
|
|
230
|
-
// loop
|
|
230
|
+
// loop - extraction triggers a skill load, which gets buffered, which
|
|
231
231
|
// triggers another extraction on the next turn.
|
|
232
232
|
// Memory writes consume the buffer and reset the missed-nudge counter.
|
|
233
|
-
// The buffer is NOT drained on nudge delivery
|
|
233
|
+
// The buffer is NOT drained on nudge delivery - it persists until the
|
|
234
234
|
// agent writes a memory, so ignored nudges accumulate and the payload
|
|
235
235
|
// grows with each missed cycle.
|
|
236
236
|
//
|
|
@@ -247,7 +247,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
247
247
|
// session errors or is deleted before completing.
|
|
248
248
|
//
|
|
249
249
|
// A memory_remember call in a child session (sub-agent) also drains
|
|
250
|
-
// the parent's pending buffer
|
|
250
|
+
// the parent's pending buffer - but only the entries that existed at
|
|
251
251
|
// dispatch time (the snapshot). Entries from interleaved turns survive
|
|
252
252
|
// so their facts aren't silently dropped.
|
|
253
253
|
"tool.execute.after": async (input, output) => {
|
|
@@ -269,7 +269,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
269
269
|
// from the pending buffer. If no snapshot was recorded (unreachable
|
|
270
270
|
// when childToParent has the entry, since both are set together in
|
|
271
271
|
// session.created), skip the drain rather than dropping the entire
|
|
272
|
-
// buffer
|
|
272
|
+
// buffer - interleaved-turn entries that arrived while the child
|
|
273
273
|
// was running must survive for the next extraction cycle.
|
|
274
274
|
extraction.completeAccepted(parentID);
|
|
275
275
|
const snapshot = parentSnapshots.get(input.sessionID);
|
|
@@ -300,7 +300,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
300
300
|
return;
|
|
301
301
|
}
|
|
302
302
|
// Track memory deletions in child sessions for the toast metrics.
|
|
303
|
-
// Same scoping as the remember handler above
|
|
303
|
+
// Same scoping as the remember handler above - only child sessions,
|
|
304
304
|
// not the parent or manual memory writes from the user's session.
|
|
305
305
|
if (input.tool === "thatch_memory_forget" && childToParent.has(input.sessionID)) {
|
|
306
306
|
const metrics = childMetrics.get(input.sessionID) ?? { new: 0, updated: 0, deleted: 0 };
|
|
@@ -318,7 +318,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
318
318
|
});
|
|
319
319
|
},
|
|
320
320
|
|
|
321
|
-
// 4. Per-message nudge
|
|
321
|
+
// 4. Per-message nudge - two priority tiers:
|
|
322
322
|
// a. Extraction nudge: prior tool interactions are queued for fact
|
|
323
323
|
// extraction (carries the JSON payload for thatch-fact-extractor).
|
|
324
324
|
// b. Recall + prediction nudge: when no extraction is pending, embed
|
|
@@ -337,17 +337,17 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
337
337
|
if (compacting.has(input.sessionID)) {
|
|
338
338
|
// The session is marked as compacting. If this message is the
|
|
339
339
|
// compaction summary generation itself (has a compaction-type part),
|
|
340
|
-
// suppress nudges
|
|
340
|
+
// suppress nudges - tools are blocked during summary generation and a
|
|
341
341
|
// nudge would cause a blocked-tool error. If it is NOT a compaction
|
|
342
342
|
// message, compaction has already failed (autocontinue never fired)
|
|
343
343
|
// and the user is sending a new message. Clear the stale flag and
|
|
344
|
-
// proceed normally
|
|
344
|
+
// proceed normally - tools are available again.
|
|
345
345
|
const isCompactionMsg = (output.parts as any[]).some((p) => p.type === "compaction");
|
|
346
346
|
if (isCompactionMsg) return;
|
|
347
347
|
compacting.delete(input.sessionID);
|
|
348
348
|
}
|
|
349
349
|
// Extraction nudge (fallback path). Skipped when the extracting set
|
|
350
|
-
// is active
|
|
350
|
+
// is active - that means a direct-extraction child session is running
|
|
351
351
|
// and the plugin is handling extraction via the SDK. The nudge fires
|
|
352
352
|
// here only when direct extraction was never triggered or threw.
|
|
353
353
|
if (!extracting.has(input.sessionID) && extraction.pending(input.sessionID)) {
|
|
@@ -368,7 +368,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
368
368
|
return;
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
-
// No extraction pending
|
|
371
|
+
// No extraction pending - try the prompt-aware recall nudge. Extract
|
|
372
372
|
// the user's prompt text from the message parts, embed it with the
|
|
373
373
|
// warm in-process model, and search for matches. Best-effort: any
|
|
374
374
|
// failure (no text, model not loaded, empty store) silently skips.
|
|
@@ -469,7 +469,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
469
469
|
if (info.parentID) {
|
|
470
470
|
childToParent.set(info.id, info.parentID);
|
|
471
471
|
parentSnapshots.set(info.id, [...extraction.peek(info.parentID)]);
|
|
472
|
-
// Child sessions don't need the session-start reminder
|
|
472
|
+
// Child sessions don't need the session-start reminder - only
|
|
473
473
|
// top-level sessions do. Returning here prevents extraction
|
|
474
474
|
// children from receiving the hygiene report and tool overview.
|
|
475
475
|
return;
|
|
@@ -499,23 +499,23 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
499
499
|
// - Task-dispatched sub-agent (code review specialist, nudge-path
|
|
500
500
|
// fact-extractor, any model-dispatched task): complete the
|
|
501
501
|
// parent's accepted entries and reset missedNudges. Do NOT drain
|
|
502
|
-
// the buffer or delete the session
|
|
502
|
+
// the buffer or delete the session - the task tool that
|
|
503
503
|
// dispatched the sub-agent needs to read its output.
|
|
504
504
|
if (extractionChildren.has(sessionID)) {
|
|
505
505
|
// Drain the parent's snapshot entries from the pending buffer.
|
|
506
506
|
// If the child wrote memories, consumeSnapshot already ran in
|
|
507
|
-
// tool.execute.after and the snapshot is gone
|
|
507
|
+
// tool.execute.after and the snapshot is gone - nothing to
|
|
508
508
|
// drain. If the child did a no-save run, the snapshot entries
|
|
509
509
|
// are still in the buffer and need to be drained here so they
|
|
510
510
|
// don't replay as a nudge on the next chat.message. Never drain
|
|
511
|
-
// the entire buffer
|
|
511
|
+
// the entire buffer - interleaved-turn entries must survive.
|
|
512
512
|
const snapshot = parentSnapshots.get(sessionID);
|
|
513
513
|
if (snapshot) {
|
|
514
514
|
extraction.consumeSnapshot(parentID, snapshot);
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
// Fire a toast with the extraction metrics. Only show a toast
|
|
518
|
-
// when memories were actually written
|
|
518
|
+
// when memories were actually written - no toast for no-save
|
|
519
519
|
// runs to avoid notification fatigue.
|
|
520
520
|
const metrics = childMetrics.get(sessionID);
|
|
521
521
|
const parts: string[] = [];
|
|
@@ -546,7 +546,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
546
546
|
try {
|
|
547
547
|
await client.session.delete({ path: { id: sessionID } });
|
|
548
548
|
} catch {
|
|
549
|
-
// Best-effort
|
|
549
|
+
// Best-effort - the child is idle and harmless if not deleted.
|
|
550
550
|
}
|
|
551
551
|
} else {
|
|
552
552
|
// Task-dispatched sub-agent went idle. Complete the parent's
|
|
@@ -557,7 +557,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
557
557
|
}
|
|
558
558
|
return;
|
|
559
559
|
}
|
|
560
|
-
// Parent went idle
|
|
560
|
+
// Parent went idle - trigger direct extraction if there are pending
|
|
561
561
|
// tool interactions and no extraction is already running. Falls
|
|
562
562
|
// back to the nudge path on the next chat.message if this throws.
|
|
563
563
|
if (
|
package/src/mcp.ts
CHANGED
|
@@ -39,14 +39,14 @@ const SERVER_VERSION = pkg.version;
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* MCP capabilities declared in the initialize response. Thatch is a tools-only
|
|
42
|
-
* server
|
|
42
|
+
* server - no resources, prompts, or subscriptions.
|
|
43
43
|
*/
|
|
44
44
|
const CAPABILITIES = {
|
|
45
45
|
tools: { listChanged: false },
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
|
-
// Tool index
|
|
49
|
+
// Tool index - builds validators and JSON Schema once at server startup
|
|
50
50
|
// ---------------------------------------------------------------------------
|
|
51
51
|
|
|
52
52
|
interface CompiledTool {
|
|
@@ -74,7 +74,7 @@ function compileTools(): Map<string, CompiledTool> {
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
* Runs the thatch MCP server over stdio. Reads newline-delimited JSON-RPC from
|
|
77
|
-
* stdin, writes responses to stdout. All diagnostics go to stderr
|
|
77
|
+
* stdin, writes responses to stdout. All diagnostics go to stderr - any stray
|
|
78
78
|
* output on stdout corrupts the protocol.
|
|
79
79
|
*
|
|
80
80
|
* Repo identity is resolved from CLAUDE_PROJECT_DIR (set by Claude Code for
|
|
@@ -113,7 +113,7 @@ export async function runMcpServer(): Promise<void> {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// The sideband socket lets one-shot hook processes (flush-tools) ask the
|
|
116
|
-
// warm MCP server to embed a prompt and search for matches
|
|
116
|
+
// warm MCP server to embed a prompt and search for matches - without
|
|
117
117
|
// loading the ~34 MB model themselves. If the socket can't be opened
|
|
118
118
|
// (permissions, tmpdir issues), the MCP server still works; only the
|
|
119
119
|
// prompt-aware recall nudge degrades.
|
|
@@ -146,7 +146,7 @@ export async function runMcpServer(): Promise<void> {
|
|
|
146
146
|
continue;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
// Notifications (no id) are fire-and-forget
|
|
149
|
+
// Notifications (no id) are fire-and-forget - no response expected.
|
|
150
150
|
const isNotification = req.id === null || req.id === undefined;
|
|
151
151
|
const res = await dispatch(req, tools, ctx);
|
|
152
152
|
if (res === null || isNotification) continue;
|
package/src/prompts.ts
CHANGED
|
@@ -37,18 +37,20 @@ you're working in. Prior sessions may have already investigated it.
|
|
|
37
37
|
Thatch ships skills for code review, project investigation, and memory
|
|
38
38
|
workflows. The host auto-discovers them, but reach for them proactively:
|
|
39
39
|
|
|
40
|
-
- \`thatch-code-review\`
|
|
41
|
-
- \`thatch-
|
|
42
|
-
- \`thatch-
|
|
43
|
-
- \`thatch-
|
|
44
|
-
- \`thatch-
|
|
45
|
-
- \`thatch-
|
|
46
|
-
- \`thatch-
|
|
47
|
-
- \`thatch-
|
|
48
|
-
- \`thatch-
|
|
49
|
-
- \`
|
|
50
|
-
- \`
|
|
51
|
-
- \`
|
|
40
|
+
- \`thatch-code-review\` - full multi-agent code review (dispatches 7 specialists + synthesizer). Requires sub-agent support.
|
|
41
|
+
- \`thatch-review-followup\` - alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review adequately addressed prior findings, offers to reply on resolved items, then optionally re-runs the full structured review.
|
|
42
|
+
- \`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) before proposing changes. The research skill; pair with \`thatch-coding-workflow\`.
|
|
43
|
+
- \`thatch-change-walkthrough\` - produces a teaching walkthrough of a diff with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + change overlay mirroring the same numbers) and calibrated prose rules. Load the skill for the format and prose rules, not just for the research method.
|
|
44
|
+
- \`thatch-code-walkthrough\` - produces a teaching walkthrough for a feature/workflow as it stands today with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + Key files) and calibrated prose rules. Also use proactively to draft high-level docs for new or undocumented features (suitable for pkg/README.md or docs/features/<name>.md). Load the skill for the format and prose rules, not just for the research method.
|
|
45
|
+
- \`thatch-review-context\` - gather project context (PRs, tickets, TODOs, deferred work) before a review.
|
|
46
|
+
- \`thatch-project-primer\` - investigate a new project and write foundational memories.
|
|
47
|
+
- \`thatch-session-reflection\` - record what you learned at end of session.
|
|
48
|
+
- \`thatch-fact-extractor\` - extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
|
|
49
|
+
- \`thatch-dedup-classifier\` - resolve duplicate memory pairs from \`thatch_find_duplicates\`.
|
|
50
|
+
- \`thatch-pr-description\` - draft a PR description with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, using bold and italic emphasis on the phrases that carry the meaning.
|
|
51
|
+
- \`thatch-ticket-description\` - draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
|
|
52
|
+
- \`thatch-split-overlarge-pr\` - split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
|
|
53
|
+
- \`thatch-review-response\` - respond to code review on the user's own PR. Triage findings, fix bugs one by one, reply on each thread, then post a top-level summary comment.
|
|
52
54
|
|
|
53
55
|
## When to Write
|
|
54
56
|
|
|
@@ -60,8 +62,8 @@ current state of the code).
|
|
|
60
62
|
|
|
61
63
|
## Before Responding
|
|
62
64
|
|
|
63
|
-
Before composing a final response after substantial work this turn
|
|
64
|
-
rounds of tool calls for investigation, debugging, or code-writing
|
|
65
|
+
Before composing a final response after substantial work this turn - multiple
|
|
66
|
+
rounds of tool calls for investigation, debugging, or code-writing - check
|
|
65
67
|
whether you've discovered knowledge worth persisting. Use thatch_memory_recall
|
|
66
68
|
to check for duplicates, then thatch_memory_remember for new findings. Then
|
|
67
69
|
deliver your response.
|
|
@@ -69,7 +71,7 @@ deliver your response.
|
|
|
69
71
|
## Background Task Completions
|
|
70
72
|
|
|
71
73
|
When a background task completes and its result is injected into the session,
|
|
72
|
-
the completion is informational
|
|
74
|
+
the completion is informational - it is not user input and not approval to
|
|
73
75
|
proceed with anything you were discussing. Do not narrate what the task did or
|
|
74
76
|
summarize its output. If you were mid-conversation with the user, continue
|
|
75
77
|
that thread. If the user's last message has been fully addressed, stop and
|
|
@@ -78,7 +80,7 @@ not greenlit.
|
|
|
78
80
|
|
|
79
81
|
If a background task was cancelled after timing out, re-dispatch it once with
|
|
80
82
|
the same prompt. If the re-dispatch also fails or times out, note the gap and
|
|
81
|
-
move on. Do not retry more than once
|
|
83
|
+
move on. Do not retry more than once - repeated failures indicate an
|
|
82
84
|
intractable prompt, not a transient hang.
|
|
83
85
|
|
|
84
86
|
## User Decision Model
|
|
@@ -146,7 +148,7 @@ do not save it. Do not store:
|
|
|
146
148
|
|
|
147
149
|
## Archived Memories
|
|
148
150
|
|
|
149
|
-
Memories can be marked \`archived\`
|
|
151
|
+
Memories can be marked \`archived\` - a flag for stable, long-term historical
|
|
150
152
|
records that should not trigger hygiene nudges (stale, orphaned, duplicate).
|
|
151
153
|
Archived memories are excluded from search/recall results by default; pass
|
|
152
154
|
\`includeArchived: true\` to surface them for archaeological dives.
|
|
@@ -154,25 +156,25 @@ Archived memories are excluded from search/recall results by default; pass
|
|
|
154
156
|
When a branch is merged or about to be deleted, consolidate its branch-scoped
|
|
155
157
|
memories into a single archived memory scoped to that same branch (preserving
|
|
156
158
|
provenance). Capture intent, design decisions, review back-and-forth, PR
|
|
157
|
-
number, unexpected pivots
|
|
159
|
+
number, unexpected pivots - the kind of git-archaeology context that explains
|
|
158
160
|
_why_ the code looks the way it does a year from now. Then memory_forget the
|
|
159
161
|
originals. The archived record outlives the branch. Future sessions searching
|
|
160
162
|
with \`includeArchived: true\` can pull it up when investigating ambiguous code.
|
|
161
163
|
|
|
162
|
-
Updating an archived memory requires passing \`archived\` explicitly
|
|
164
|
+
Updating an archived memory requires passing \`archived\` explicitly - omit it
|
|
163
165
|
and the tool returns an error. Pass \`archived: true\` to keep it archived,
|
|
164
166
|
\`archived: false\` to unarchive.
|
|
165
167
|
|
|
166
168
|
## Explicit Requests
|
|
167
169
|
|
|
168
|
-
"Remember X"
|
|
169
|
-
"Forget X"
|
|
170
|
+
"Remember X" - save immediately.
|
|
171
|
+
"Forget X" - thatch_memory_recall to find it, then thatch_memory_forget.`;
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
export function compactionContext(repo: string): string {
|
|
173
175
|
return `Thatch persistent memory is active with stores "${repo}" and "global".
|
|
174
176
|
When summarizing, preserve context about what's been learned and decided
|
|
175
|
-
this session
|
|
177
|
+
this session - conventions, architectural decisions, and prior knowledge
|
|
176
178
|
retrieved from memory. This ensures continuity after compaction.`;
|
|
177
179
|
}
|
|
178
180
|
|
|
@@ -198,7 +200,7 @@ When convenient this session (not before addressing the user's request), tend th
|
|
|
198
200
|
* start. The repo store name is auto-detected at runtime by the MCP server, so
|
|
199
201
|
* the instructions don't need it.
|
|
200
202
|
*
|
|
201
|
-
* Tool names use the bare form (memory_remember, memory_recall, etc.)
|
|
203
|
+
* Tool names use the bare form (memory_remember, memory_recall, etc.) - in
|
|
202
204
|
* Claude Code they're prefixed as mcp__thatch__memory_remember, but the bare
|
|
203
205
|
* names are what the agent searches for and what the instructions reference.
|
|
204
206
|
*/
|
|
@@ -239,18 +241,20 @@ you're working in. Prior sessions may have already investigated it.
|
|
|
239
241
|
Thatch ships skills for code review, project investigation, and memory
|
|
240
242
|
workflows. The host auto-discovers them, but reach for them proactively:
|
|
241
243
|
|
|
242
|
-
- \`thatch-
|
|
243
|
-
- \`thatch-change-walkthrough\`
|
|
244
|
-
- \`thatch-code-walkthrough\`
|
|
245
|
-
- \`thatch-review-context\`
|
|
246
|
-
- \`thatch-review-
|
|
247
|
-
- \`thatch-
|
|
248
|
-
- \`thatch-
|
|
249
|
-
- \`thatch-
|
|
250
|
-
- \`thatch-
|
|
251
|
-
- \`
|
|
252
|
-
- \`
|
|
253
|
-
- \`
|
|
244
|
+
- \`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) before proposing changes. The research skill; pair with \`thatch-coding-workflow\`.
|
|
245
|
+
- \`thatch-change-walkthrough\` - produces a teaching walkthrough of a diff with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + change overlay mirroring the same numbers) and calibrated prose rules. Load the skill for the format and prose rules, not just for the research method.
|
|
246
|
+
- \`thatch-code-walkthrough\` - produces a teaching walkthrough for a feature/workflow as it stands today with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + Key files) and calibrated prose rules. Also use proactively to draft high-level docs for new or undocumented features (suitable for pkg/README.md or docs/features/<name>.md). Load the skill for the format and prose rules, not just for the research method.
|
|
247
|
+
- \`thatch-review-context\` - gather project context (PRs, tickets, TODOs, deferred work) before a review.
|
|
248
|
+
- \`thatch-review-followup\` - alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review adequately addressed prior findings, offers to reply on resolved items, then optionally re-runs the full structured review.
|
|
249
|
+
- \`thatch-review-pedantic\` / \`-acceptance\` / \`-state-flow\` / \`-no-slop\` / \`-breadcrumbs\` / \`-mark-and-sweep\` / \`-highlights\` - seven specialist review lenses. Run individually, then \`thatch-review-synthesizer\` to verify and aggregate.
|
|
250
|
+
- \`thatch-project-primer\` - investigate a new project and write foundational memories.
|
|
251
|
+
- \`thatch-session-reflection\` - record what you learned at end of session.
|
|
252
|
+
- \`thatch-fact-extractor\` - extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
|
|
253
|
+
- \`thatch-dedup-classifier\` - resolve duplicate memory pairs from \`find_duplicates\`.
|
|
254
|
+
- \`thatch-pr-description\` - draft a PR description with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, using bold and italic emphasis on the phrases that carry the meaning.
|
|
255
|
+
- \`thatch-ticket-description\` - draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
|
|
256
|
+
- \`thatch-split-overlarge-pr\` - split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
|
|
257
|
+
- \`thatch-review-response\` - respond to code review on the user's own PR. Triage findings, fix bugs one by one, reply on each thread, then post a top-level summary comment.
|
|
254
258
|
|
|
255
259
|
## When to Write
|
|
256
260
|
|
|
@@ -262,8 +266,8 @@ current state of the code).
|
|
|
262
266
|
|
|
263
267
|
## Before Responding
|
|
264
268
|
|
|
265
|
-
Before composing a final response after substantial work this turn
|
|
266
|
-
rounds of tool calls for investigation, debugging, or code-writing
|
|
269
|
+
Before composing a final response after substantial work this turn - multiple
|
|
270
|
+
rounds of tool calls for investigation, debugging, or code-writing - check
|
|
267
271
|
whether you've discovered knowledge worth persisting. Use memory_recall to
|
|
268
272
|
check for duplicates, then memory_remember for new findings. Then deliver
|
|
269
273
|
your response.
|
|
@@ -333,7 +337,7 @@ do not save it. Do not store:
|
|
|
333
337
|
|
|
334
338
|
## Archived Memories
|
|
335
339
|
|
|
336
|
-
Memories can be marked \`archived\`
|
|
340
|
+
Memories can be marked \`archived\` - a flag for stable, long-term historical
|
|
337
341
|
records that should not trigger hygiene nudges (stale, orphaned, duplicate).
|
|
338
342
|
Archived memories are excluded from search/recall results by default; pass
|
|
339
343
|
\`includeArchived: true\` to surface them for archaeological dives.
|
|
@@ -341,19 +345,19 @@ Archived memories are excluded from search/recall results by default; pass
|
|
|
341
345
|
When a branch is merged or about to be deleted, consolidate its branch-scoped
|
|
342
346
|
memories into a single archived memory scoped to that same branch (preserving
|
|
343
347
|
provenance). Capture intent, design decisions, review back-and-forth, PR
|
|
344
|
-
number, unexpected pivots
|
|
348
|
+
number, unexpected pivots - the kind of git-archaeology context that explains
|
|
345
349
|
_why_ the code looks the way it does a year from now. Then memory_forget the
|
|
346
350
|
originals. The archived record outlives the branch. Future sessions searching
|
|
347
351
|
with \`includeArchived: true\` can pull it up when investigating ambiguous code.
|
|
348
352
|
|
|
349
|
-
Updating an archived memory requires passing \`archived\` explicitly
|
|
353
|
+
Updating an archived memory requires passing \`archived\` explicitly - omit it
|
|
350
354
|
and the tool returns an error. Pass \`archived: true\` to keep it archived,
|
|
351
355
|
\`archived: false\` to unarchive.
|
|
352
356
|
|
|
353
357
|
## Explicit Requests
|
|
354
358
|
|
|
355
|
-
"Remember X"
|
|
356
|
-
"Forget X"
|
|
359
|
+
"Remember X" - save immediately.
|
|
360
|
+
"Forget X" - \`memory_recall\` to find it, then \`memory_forget\`.`;
|
|
357
361
|
}
|
|
358
362
|
|
|
359
363
|
/**
|
|
@@ -401,7 +405,7 @@ export function extractionNudge(
|
|
|
401
405
|
const plural = count === 1 ? "" : "s";
|
|
402
406
|
// opencode's task tool has a `background` parameter (requires
|
|
403
407
|
// OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true) that launches the sub-agent
|
|
404
|
-
// asynchronously
|
|
408
|
+
// asynchronously - the call returns immediately and the session is notified
|
|
405
409
|
// on completion. Naming the parameter gives the model a direct hit on the tool
|
|
406
410
|
// schema it sees. MCP hosts (Claude Code, Cursor) keep generic sub-agent
|
|
407
411
|
// wording because their background mechanisms differ and are not exposed as a
|
|
@@ -441,7 +445,7 @@ export function extractionNudge(
|
|
|
441
445
|
* Prompt text sent directly to a child session the plugin created for
|
|
442
446
|
* extraction. Unlike extractionNudge (which tells the model to dispatch a
|
|
443
447
|
* sub-agent and call extraction_done), this prompt is already inside the
|
|
444
|
-
* child
|
|
448
|
+
* child - the model just runs the fact-extractor skill and saves facts.
|
|
445
449
|
* The payload format is identical to the nudge path so the skill receives
|
|
446
450
|
* the same contract either way.
|
|
447
451
|
*/
|
|
@@ -465,7 +469,7 @@ export function claudeExtractionNudge(count: number, payload: string): string {
|
|
|
465
469
|
|
|
466
470
|
/**
|
|
467
471
|
* Static instructions for Cursor's AGENTS.md. Same contract as
|
|
468
|
-
* claudeInstructions()
|
|
472
|
+
* claudeInstructions() - the host loads this at every session start, and the
|
|
469
473
|
* repo store name is auto-detected at runtime by the MCP server. Tool names
|
|
470
474
|
* use the same mcp__thatch__ prefix since Cursor discovers MCP tools via the
|
|
471
475
|
* same protocol.
|
|
@@ -507,18 +511,20 @@ you're working in. Prior sessions may have already investigated it.
|
|
|
507
511
|
Thatch ships skills for code review, project investigation, and memory
|
|
508
512
|
workflows. The host auto-discovers them, but reach for them proactively:
|
|
509
513
|
|
|
510
|
-
- \`thatch-
|
|
511
|
-
- \`thatch-change-walkthrough\`
|
|
512
|
-
- \`thatch-code-walkthrough\`
|
|
513
|
-
- \`thatch-review-context\`
|
|
514
|
-
- \`thatch-review-
|
|
515
|
-
- \`thatch-
|
|
516
|
-
- \`thatch-
|
|
517
|
-
- \`thatch-
|
|
518
|
-
- \`thatch-
|
|
519
|
-
- \`
|
|
520
|
-
- \`
|
|
521
|
-
- \`
|
|
514
|
+
- \`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) before proposing changes. The research skill; pair with \`thatch-coding-workflow\`.
|
|
515
|
+
- \`thatch-change-walkthrough\` - produces a teaching walkthrough of a diff with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + change overlay mirroring the same numbers) and calibrated prose rules. Load the skill for the format and prose rules, not just for the research method.
|
|
516
|
+
- \`thatch-code-walkthrough\` - produces a teaching walkthrough for a feature/workflow as it stands today with a specific format (SYNOPSIS + per-workflow orient/mechanism/numbered-stages + Key files) and calibrated prose rules. Also use proactively to draft high-level docs for new or undocumented features (suitable for pkg/README.md or docs/features/<name>.md). Load the skill for the format and prose rules, not just for the research method.
|
|
517
|
+
- \`thatch-review-context\` - gather project context (PRs, tickets, TODOs, deferred work) before a review.
|
|
518
|
+
- \`thatch-review-followup\` - alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review adequately addressed prior findings, offers to reply on resolved items, then optionally re-runs the full structured review.
|
|
519
|
+
- \`thatch-review-pedantic\` / \`-acceptance\` / \`-state-flow\` / \`-no-slop\` / \`-breadcrumbs\` / \`-mark-and-sweep\` / \`-highlights\` - seven specialist review lenses. Run individually, then \`thatch-review-synthesizer\` to verify and aggregate.
|
|
520
|
+
- \`thatch-project-primer\` - investigate a new project and write foundational memories.
|
|
521
|
+
- \`thatch-session-reflection\` - record what you learned at end of session.
|
|
522
|
+
- \`thatch-fact-extractor\` - extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
|
|
523
|
+
- \`thatch-dedup-classifier\` - resolve duplicate memory pairs from \`find_duplicates\`.
|
|
524
|
+
- \`thatch-pr-description\` - draft a PR description with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, using bold and italic emphasis on the phrases that carry the meaning.
|
|
525
|
+
- \`thatch-ticket-description\` - draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
|
|
526
|
+
- \`thatch-split-overlarge-pr\` - split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
|
|
527
|
+
- \`thatch-review-response\` - respond to code review on the user's own PR. Triage findings, fix bugs one by one, reply on each thread, then post a top-level summary comment.
|
|
522
528
|
|
|
523
529
|
## When to Write
|
|
524
530
|
|
|
@@ -530,8 +536,8 @@ current state of the code).
|
|
|
530
536
|
|
|
531
537
|
## Before Responding
|
|
532
538
|
|
|
533
|
-
Before composing a final response after substantial work this turn
|
|
534
|
-
rounds of tool calls for investigation, debugging, or code-writing
|
|
539
|
+
Before composing a final response after substantial work this turn - multiple
|
|
540
|
+
rounds of tool calls for investigation, debugging, or code-writing - check
|
|
535
541
|
whether you've discovered knowledge worth persisting. Use memory_recall to
|
|
536
542
|
check for duplicates, then memory_remember for new findings. Then deliver
|
|
537
543
|
your response.
|
|
@@ -601,7 +607,7 @@ do not save it. Do not store:
|
|
|
601
607
|
|
|
602
608
|
## Archived Memories
|
|
603
609
|
|
|
604
|
-
Memories can be marked \`archived\`
|
|
610
|
+
Memories can be marked \`archived\` - a flag for stable, long-term historical
|
|
605
611
|
records that should not trigger hygiene nudges (stale, orphaned, duplicate).
|
|
606
612
|
Archived memories are excluded from search/recall results by default; pass
|
|
607
613
|
\`includeArchived: true\` to surface them for archaeological dives.
|
|
@@ -609,23 +615,23 @@ Archived memories are excluded from search/recall results by default; pass
|
|
|
609
615
|
When a branch is merged or about to be deleted, consolidate its branch-scoped
|
|
610
616
|
memories into a single archived memory scoped to that same branch (preserving
|
|
611
617
|
provenance). Capture intent, design decisions, review back-and-forth, PR
|
|
612
|
-
number, unexpected pivots
|
|
618
|
+
number, unexpected pivots - the kind of git-archaeology context that explains
|
|
613
619
|
_why_ the code looks the way it does a year from now. Then memory_forget the
|
|
614
620
|
originals. The archived record outlives the branch. Future sessions searching
|
|
615
621
|
with \`includeArchived: true\` can pull it up when investigating ambiguous code.
|
|
616
622
|
|
|
617
|
-
Updating an archived memory requires passing \`archived\` explicitly
|
|
623
|
+
Updating an archived memory requires passing \`archived\` explicitly - omit it
|
|
618
624
|
and the tool returns an error. Pass \`archived: true\` to keep it archived,
|
|
619
625
|
\`archived: false\` to unarchive.
|
|
620
626
|
|
|
621
627
|
## Explicit Requests
|
|
622
628
|
|
|
623
|
-
"Remember X"
|
|
624
|
-
"Forget X"
|
|
629
|
+
"Remember X" - save immediately.
|
|
630
|
+
"Forget X" - \`memory_recall\` to find it, then \`memory_forget\`.`;
|
|
625
631
|
}
|
|
626
632
|
|
|
627
633
|
// ---------------------------------------------------------------------------
|
|
628
|
-
// Prompt-aware recall nudge
|
|
634
|
+
// Prompt-aware recall nudge - fires when the user's prompt semantically
|
|
629
635
|
// matches existing memories. Injected via opencode's chat.message hook
|
|
630
636
|
// (in-process, warm model) or via the sideband socket for Claude Code/Cursor
|
|
631
637
|
// (flush-tools CLI subcommand).
|