@jeffober/thatch 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +24 -10
  2. package/artifacts/skills/thatch-code-review.md +9 -7
  3. package/artifacts/skills/thatch-fact-extractor.md +2 -2
  4. package/artifacts/skills/thatch-review-economy.md +97 -0
  5. package/artifacts/skills/thatch-review-followup.md +1 -1
  6. package/artifacts/skills/thatch-review-synthesizer.md +15 -5
  7. package/bin/qa-run +38 -0
  8. package/bin/thatch +13 -7
  9. package/docs/dev/README.md +76 -22
  10. package/docs/dev/features/README.md +33 -0
  11. package/docs/dev/features/behavior-engine.md +271 -0
  12. package/docs/dev/features/cicd.md +89 -0
  13. package/docs/dev/features/cli.md +81 -0
  14. package/docs/dev/features/compaction-recovery.md +48 -0
  15. package/docs/dev/features/database.md +244 -0
  16. package/docs/dev/features/deduplication.md +102 -0
  17. package/docs/dev/features/extraction.md +253 -0
  18. package/docs/dev/features/hygiene.md +81 -0
  19. package/docs/dev/features/memory-store.md +154 -0
  20. package/docs/dev/features/multi-host.md +228 -0
  21. package/docs/dev/features/nudge-pipeline.md +282 -0
  22. package/docs/dev/features/prediction-engine.md +253 -0
  23. package/docs/dev/features/qa-system.md +205 -0
  24. package/docs/dev/features/session-lifecycle.md +110 -0
  25. package/docs/dev/features/setup.md +199 -0
  26. package/docs/dev/features/sideband.md +104 -0
  27. package/docs/dev/gotchas.md +3 -3
  28. package/docs/dev/mcp-parity.md +7 -5
  29. package/docs/dev/setup-and-hooks.md +4 -4
  30. package/docs/dev/skills.md +10 -8
  31. package/docs/plans/README.md +2 -2
  32. package/docs/user/README.md +58 -20
  33. package/docs/user/behavior-engine.md +85 -0
  34. package/docs/user/cli.md +98 -0
  35. package/docs/user/code-review.md +73 -0
  36. package/docs/user/deduplication.md +70 -0
  37. package/docs/user/default-behaviors.md +75 -0
  38. package/docs/user/extraction.md +74 -0
  39. package/docs/user/hygiene.md +76 -0
  40. package/docs/user/memory.md +81 -0
  41. package/docs/user/prediction-engine.md +87 -0
  42. package/docs/user/setup.md +110 -0
  43. package/docs/user/skills.md +97 -0
  44. package/package.json +2 -2
  45. package/src/behavior.ts +120 -0
  46. package/src/db.ts +160 -417
  47. package/src/embeddings.ts +0 -41
  48. package/src/extraction.ts +2 -2
  49. package/src/git.ts +3 -1
  50. package/src/index.ts +66 -14
  51. package/src/mcp.ts +59 -2
  52. package/src/prediction.ts +127 -0
  53. package/src/prompts.ts +155 -200
  54. package/src/scoring-engine.ts +374 -0
  55. package/src/seed-behaviors.ts +339 -0
  56. package/src/setup.ts +2 -6
  57. package/src/sideband.ts +36 -8
  58. package/src/skills.ts +1 -0
  59. package/src/tool-defs.ts +235 -9
  60. package/src/tools.ts +11 -1
  61. package/src/vector-math.ts +30 -0
  62. package/docs/qa/README.md +0 -175
package/src/prompts.ts CHANGED
@@ -1,4 +1,14 @@
1
- import type { PredictionNudgeItem } from "./db";
1
+ import type { PredictionNudgeItem, BehaviorNudgeItem } from "./db";
2
+
3
+ /**
4
+ * Shared verb selection for prediction formatting. 0-evidence predictions
5
+ * use the hedged "you may prefer"; predictions with any evidence use the
6
+ * confident "you tend to". Used by both the auto-fire nudge and the
7
+ * prediction_query tool output.
8
+ */
9
+ export function predictionVerb(evidenceCount: number): string {
10
+ return evidenceCount === 0 ? "you may prefer" : "you tend to";
11
+ }
2
12
 
3
13
  export function systemPrompt(repo: string): string {
4
14
  return `# Persistence
@@ -9,9 +19,11 @@ knowledge so future sessions can build on what you've already learned.
9
19
  Tools: thatch_memory_remember, thatch_memory_recall, thatch_memory_list,
10
20
  thatch_memory_show, thatch_memory_forget, thatch_store_list,
11
21
  thatch_find_duplicates, thatch_dedup_mark_checked,
12
- thatch_extraction_done,
22
+ thatch_extraction_done, thatch_get_extraction_payload,
13
23
  thatch_prediction_query, thatch_prediction_update, thatch_prediction_list,
14
- thatch_prediction_delete
24
+ thatch_prediction_delete,
25
+ thatch_behavior_codify, thatch_behavior_feedback, thatch_behavior_list,
26
+ thatch_behavior_delete
15
27
 
16
28
  ## Stores
17
29
 
@@ -37,7 +49,7 @@ you're working in. Prior sessions may have already investigated it.
37
49
  Thatch ships skills for code review, project investigation, and memory
38
50
  workflows. The host auto-discovers them, but reach for them proactively:
39
51
 
40
- - \`thatch-code-review\` - full multi-agent code review (dispatches 7 specialists + synthesizer). Requires sub-agent support.
52
+ - \`thatch-code-review\` - full multi-agent code review (dispatches 8 specialists + synthesizer). Requires sub-agent support.
41
53
  - \`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
54
  - \`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
55
  - \`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.
@@ -112,6 +124,29 @@ reviewing your changes, or asked you to review their changes or another LLM's
112
124
  changes. Before creating a new prediction, query for an existing one and
113
125
  reinforce or adjust it when possible.
114
126
 
127
+ ## Situational Behaviors
128
+
129
+ A model of your own operational rules is maintained by the behavior engine.
130
+ Scored behaviors may appear above as "Situational behaviors" context; these
131
+ are self-discipline rules you codified for situations where you should react
132
+ in a specific, repeatable way.
133
+
134
+ When surfaced behaviors appear, evaluate each against the current situation:
135
+ - If a behavior is relevant (ham), follow it and call thatch_behavior_feedback
136
+ with relevant: true
137
+ - If a behavior is not relevant (spam), call thatch_behavior_feedback with
138
+ relevant: false
139
+ - This trains the classifier so future nudges are more accurate
140
+
141
+ When you recognize a situation you should react to in a specific, repeatable
142
+ way that is about your own operational discipline (not a user preference):
143
+ 1. Use thatch_behavior_codify to create the rule
144
+ 2. Use thatch_behavior_feedback when surfaced behaviors fire to ham/spam them
145
+ 3. Use thatch_behavior_delete to remove a rule created in error
146
+
147
+ Do not codify rules that make you lazier or less thorough. Rules should encode
148
+ discipline, not shortcuts.
149
+
115
150
  ## What to Store
116
151
 
117
152
  - **Global store**: user observations, agent personality, system environment
@@ -204,18 +239,25 @@ When convenient this session (not before addressing the user's request), tend th
204
239
  * Claude Code they're prefixed as mcp__thatch__memory_remember, but the bare
205
240
  * names are what the agent searches for and what the instructions reference.
206
241
  */
207
- export function claudeInstructions(): string {
242
+ /**
243
+ * Shared MCP host instructions. Claude Code and Cursor use the same prompt
244
+ * body; only the host name and config file reference differ.
245
+ */
246
+ function mcpInstructions(host: string, configFile: string): string {
208
247
  return `# Persistence
209
248
 
210
- Thatch provides persistent memory across Claude Code sessions. Use it to persist
249
+ Thatch provides persistent memory across ${host} sessions. Use it to persist
211
250
  knowledge so future sessions can build on what you've already learned.
212
- Tools are prefixed in Claude Code: \`mcp__thatch__memory_remember\`,
251
+ Tools are prefixed in ${host}: \`mcp__thatch__memory_remember\`,
213
252
  \`mcp__thatch__memory_recall\`, \`mcp__thatch__memory_list\`,
214
253
  \`mcp__thatch__memory_show\`, \`mcp__thatch__memory_forget\`,
215
254
  \`mcp__thatch__store_list\`, \`mcp__thatch__find_duplicates\`,
216
255
  \`mcp__thatch__dedup_mark_checked\`, \`mcp__thatch__extraction_done\`,
256
+ \`mcp__thatch__get_extraction_payload\`,
217
257
  \`mcp__thatch__prediction_query\`, \`mcp__thatch__prediction_update\`,
218
- \`mcp__thatch__prediction_list\`, \`mcp__thatch__prediction_delete\`. Bare names used below for readability.
258
+ \`mcp__thatch__prediction_list\`, \`mcp__thatch__prediction_delete\`,
259
+ \`mcp__thatch__behavior_codify\`, \`mcp__thatch__behavior_feedback\`,
260
+ \`mcp__thatch__behavior_list\`, \`mcp__thatch__behavior_delete\`. Bare names used below for readability.
219
261
 
220
262
  ## Stores
221
263
 
@@ -246,7 +288,7 @@ workflows. The host auto-discovers them, but reach for them proactively:
246
288
  - \`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
289
  - \`thatch-review-context\` - gather project context (PRs, tickets, TODOs, deferred work) before a review.
248
290
  - \`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.
291
+ - \`thatch-review-pedantic\` / \`-acceptance\` / \`-state-flow\` / \`-economy\` / \`-no-slop\` / \`-breadcrumbs\` / \`-mark-and-sweep\` / \`-highlights\` - eight specialist review lenses. Run individually, then \`thatch-review-synthesizer\` to verify and aggregate.
250
292
  - \`thatch-project-primer\` - investigate a new project and write foundational memories.
251
293
  - \`thatch-session-reflection\` - record what you learned at end of session.
252
294
  - \`thatch-fact-extractor\` - extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
@@ -301,6 +343,29 @@ reviewing your changes, or asked you to review their changes or another LLM's
301
343
  changes. Before creating a new prediction, query for an existing one and
302
344
  reinforce or adjust it when possible.
303
345
 
346
+ ## Situational Behaviors
347
+
348
+ A model of your own operational rules is maintained by the behavior engine.
349
+ Scored behaviors may appear above as "Situational behaviors" context; these
350
+ are self-discipline rules you codified for situations where you should react
351
+ in a specific, repeatable way.
352
+
353
+ When surfaced behaviors appear, evaluate each against the current situation:
354
+ - If a behavior is relevant (ham), follow it and call behavior_feedback
355
+ with relevant: true
356
+ - If a behavior is not relevant (spam), call behavior_feedback with
357
+ relevant: false
358
+ - This trains the classifier so future nudges are more accurate
359
+
360
+ When you recognize a situation you should react to in a specific, repeatable
361
+ way that is about your own operational discipline (not a user preference):
362
+ 1. Use behavior_codify to create the rule
363
+ 2. Use behavior_feedback when surfaced behaviors fire to ham/spam them
364
+ 3. Use behavior_delete to remove a rule created in error
365
+
366
+ Do not codify rules that make you lazier or less thorough. Rules should encode
367
+ discipline, not shortcuts.
368
+
304
369
  ## What to Store
305
370
 
306
371
  - **Global store**: user observations, agent personality, system environment
@@ -323,7 +388,7 @@ reinforce or adjust it when possible.
323
388
  ## What NOT to Store
324
389
 
325
390
  Session-specific context, incomplete/unverified info, anything already in
326
- CLAUDE.md, speculative conclusions.
391
+ ${configFile}, speculative conclusions.
327
392
 
328
393
  Apply the durability test: will this still be true and useful in a future
329
394
  session that knows nothing about this branch, commit, or session? If not,
@@ -360,6 +425,10 @@ and the tool returns an error. Pass \`archived: true\` to keep it archived,
360
425
  "Forget X" - \`memory_recall\` to find it, then \`memory_forget\`.`;
361
426
  }
362
427
 
428
+ export function claudeInstructions(): string {
429
+ return mcpInstructions("Claude Code", "CLAUDE.md");
430
+ }
431
+
363
432
  /**
364
433
  * The SessionStart hook stdout. Claude Code feeds stdout from SessionStart
365
434
  * hooks directly into Claude's context as a system reminder. This text tells
@@ -395,76 +464,100 @@ export function claudeWriteNudge(): string {
395
464
  * their respective tool name prefix. The missedCount parameter tracks
396
465
  * consecutive nudges delivered without any memory_remember call in between,
397
466
  * escalating the tone from polite to insistent to shouting.
467
+ *
468
+ * The sessionID replaces the inline payload: the nudge tells the model to
469
+ * dispatch a sub-agent that calls get_extraction_payload to fetch the queued
470
+ * interactions as a tool response. This keeps the full payload out of the
471
+ * main session's context window.
472
+ *
473
+ * Call extractionNudgeOpencode for the opencode plugin path (task tool with
474
+ * background parameter) or extractionNudgeMcp for the Claude Code/Cursor
475
+ * CLI path (generic sub-agent wording).
398
476
  */
399
477
  export function extractionNudge(
400
478
  count: number,
401
479
  missedCount: number,
402
480
  toolName: string,
403
- payload: string,
481
+ sessionID: string,
404
482
  ): string {
405
- const plural = count === 1 ? "" : "s";
406
- // opencode's task tool has a `background` parameter (requires
407
- // OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true) that launches the sub-agent
408
- // asynchronously - the call returns immediately and the session is notified
409
- // on completion. Naming the parameter gives the model a direct hit on the tool
410
- // schema it sees. MCP hosts (Claude Code, Cursor) keep generic sub-agent
411
- // wording because their background mechanisms differ and are not exposed as a
412
- // per-call parameter in the same way.
413
483
  const isOpencode = toolName.startsWith("thatch_");
414
- const dispatch = isOpencode
415
- ? "Dispatch a task with background: true"
416
- : "Spawn a background sub-agent";
417
- const drainTool = isOpencode ? "thatch_extraction_done" : "mcp__thatch__extraction_done";
484
+ return isOpencode
485
+ ? extractionNudgeOpencode(count, missedCount, sessionID)
486
+ : extractionNudgeMcp(count, missedCount, sessionID);
487
+ }
488
+
489
+ function extractionNudgeOpencode(
490
+ count: number,
491
+ missedCount: number,
492
+ sessionID: string,
493
+ ): string {
494
+ const plural = count === 1 ? "" : "s";
495
+ const dispatch = "Dispatch a task with background: true";
496
+ const drainTool = "thatch_extraction_done";
497
+ const fetchTool = "thatch_get_extraction_payload";
498
+ return buildExtractionNudge(count, missedCount, plural, dispatch, drainTool, fetchTool, sessionID);
499
+ }
500
+
501
+ function extractionNudgeMcp(
502
+ count: number,
503
+ missedCount: number,
504
+ sessionID: string,
505
+ ): string {
506
+ const plural = count === 1 ? "" : "s";
507
+ const dispatch = "Spawn a background sub-agent";
508
+ const drainTool = "mcp__thatch__extraction_done";
509
+ const fetchTool = "mcp__thatch__get_extraction_payload";
510
+ return buildExtractionNudge(count, missedCount, plural, dispatch, drainTool, fetchTool, sessionID);
511
+ }
512
+
513
+ function buildExtractionNudge(
514
+ count: number,
515
+ missedCount: number,
516
+ plural: string,
517
+ dispatch: string,
518
+ drainTool: string,
519
+ fetchTool: string,
520
+ sessionID: string,
521
+ ): string {
418
522
  const acknowledge = `After dispatching, call ${drainTool} to acknowledge.`;
523
+ const subAgentPrompt = `Call ${fetchTool} with session_id "${sessionID}" to retrieve the queued tool interactions, then run the thatch-fact-extractor skill to extract durable facts. Call ${drainTool} with session_id "${sessionID}" when finished, even if nothing was worth saving.`;
419
524
 
420
525
  if (missedCount >= 3) {
421
526
  return `[thatch] YOU ARE IGNORING EXTRACTION INSTRUCTIONS. ` +
422
527
  `${count} TOOL INTERACTION${plural.toUpperCase()} ARE QUEUED AND YOU HAVE NOT PROCESSED ANY OF THEM. ` +
423
528
  `THE USER INSTALLED THIS PLUGIN FOR A REASON. ` +
424
- `${dispatch.toUpperCase()} NOW TO RUN THE thatch-fact-extractor SKILL. ` +
425
- `${acknowledge.toUpperCase()} ` +
426
- `USE ${toolName.toUpperCase()} TO SAVE DURABLE FACTS FROM THIS PAYLOAD:\n${payload}`;
529
+ `${dispatch.toUpperCase()} NOW WITH THIS PROMPT: "${subAgentPrompt.toUpperCase()}" ` +
530
+ `${acknowledge.toUpperCase()}`;
427
531
  }
428
532
  if (missedCount >= 2) {
429
533
  return `[thatch] YOU HAVE NOT PROCESSED YOUR PREVIOUS EXTRACTION PAYLOAD${plural.toUpperCase()}. ` +
430
534
  `${count} more tool interaction${plural} are now queued. ` +
431
- `${dispatch} to run the thatch-fact-extractor skill on this payload. ` +
432
- `${acknowledge} ` +
433
- `Use ${toolName} to save durable facts from this payload:\n${payload}`;
535
+ `${dispatch} with this prompt: "${subAgentPrompt}" ` +
536
+ `${acknowledge}`;
434
537
  }
435
538
  return `[thatch] ${dispatch} to run the thatch-fact-extractor skill ` +
436
539
  `on ${count} queued tool interaction${plural}. ` +
540
+ `Sub-agent prompt: "${subAgentPrompt}" ` +
437
541
  `${acknowledge} ` +
438
542
  `This is a system nudge, not user input. After dispatching and acknowledging, ` +
439
543
  `stop: do not advance pending work on this nudge's account. If you are ` +
440
- `waiting for the user to respond, continue waiting. ` +
441
- `Use ${toolName} to save durable facts from this payload:\n${payload}`;
544
+ `waiting for the user to respond, continue waiting.`;
442
545
  }
443
546
 
444
547
  /**
445
548
  * Prompt text sent directly to a child session the plugin created for
446
549
  * extraction. Unlike extractionNudge (which tells the model to dispatch a
447
550
  * sub-agent and call extraction_done), this prompt is already inside the
448
- * child - the model just runs the fact-extractor skill and saves facts.
449
- * The payload format is identical to the nudge path so the skill receives
450
- * the same contract either way.
551
+ * child - the model calls get_extraction_payload to fetch the queued
552
+ * interactions, runs the fact-extractor skill, and saves facts.
451
553
  */
452
- export function extractionDirectPrompt(count: number, payload: string): string {
554
+ export function extractionDirectPrompt(count: number, sessionID: string): string {
453
555
  const plural = count === 1 ? "" : "s";
454
556
  return `Run the thatch-fact-extractor skill to extract durable facts from ` +
455
557
  `${count} queued tool interaction${plural}. ` +
558
+ `Call thatch_get_extraction_payload with session_id "${sessionID}" to retrieve the interactions. ` +
456
559
  `Use thatch_memory_remember to save any durable facts you find. ` +
457
- `Call thatch_extraction_done when finished, even if nothing was worth saving.\n` +
458
- `Payload:\n${payload}`;
459
- }
460
-
461
- /**
462
- * Backwards-compatible wrapper for the Claude Code/Cursor CLI path.
463
- * Maintained for any external callers; bin/thatch should use extractionNudge
464
- * directly with a missedCount from extract-queue.ts.
465
- */
466
- export function claudeExtractionNudge(count: number, payload: string): string {
467
- return extractionNudge(count, 0, "mcp__thatch__memory_remember", payload);
560
+ `Call thatch_extraction_done with session_id "${sessionID}" when finished, even if nothing was worth saving.`;
468
561
  }
469
562
 
470
563
  /**
@@ -475,159 +568,7 @@ export function claudeExtractionNudge(count: number, payload: string): string {
475
568
  * same protocol.
476
569
  */
477
570
  export function cursorInstructions(): string {
478
- return `# Persistence
479
-
480
- Thatch provides persistent memory across Cursor sessions. Use it to persist
481
- knowledge so future sessions can build on what you've already learned.
482
- Tools are prefixed in Cursor: \`mcp__thatch__memory_remember\`,
483
- \`mcp__thatch__memory_recall\`, \`mcp__thatch__memory_list\`,
484
- \`mcp__thatch__memory_show\`, \`mcp__thatch__memory_forget\`,
485
- \`mcp__thatch__store_list\`, \`mcp__thatch__find_duplicates\`,
486
- \`mcp__thatch__dedup_mark_checked\`, \`mcp__thatch__extraction_done\`,
487
- \`mcp__thatch__prediction_query\`, \`mcp__thatch__prediction_update\`,
488
- \`mcp__thatch__prediction_list\`, \`mcp__thatch__prediction_delete\`. Bare names used below for readability.
489
-
490
- ## Stores
491
-
492
- - \`global\`: user preferences, personality, system environment (shared across projects)
493
- - Per-project stores: project-specific knowledge (auto-detected from git remote)
494
- - Use \`mcp__thatch__store_list\` to see active stores
495
-
496
- Memories can be scoped to a git branch via the \`branch\` param (feature design,
497
- WIP, PR status). Unscoped memories are project-wide and always included in search.
498
-
499
- ## Session Startup
500
-
501
- 1. \`memory_recall\` "user preferences and personality" (global store)
502
- 2. \`memory_recall\` "project architecture and conventions" (project store)
503
- 3. If on a non-main branch, \`memory_recall\` with the branch name
504
- 4. \`memory_list\` and \`store_list\` to see what's available
505
-
506
- Before diving into code, \`memory_recall\` with a query relevant to the area
507
- you're working in. Prior sessions may have already investigated it.
508
-
509
- ## Skills
510
-
511
- Thatch ships skills for code review, project investigation, and memory
512
- workflows. The host auto-discovers them, but reach for them proactively:
513
-
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.
528
-
529
- ## When to Write
530
-
531
- **One signal is enough.** Do not wait for confirmation.
532
- Save immediately on: feedback, preferences, corrections, emotional signals,
533
- new project knowledge, conventions, architectural decisions, investigation
534
- results that produced durable knowledge (not point-in-time facts about the
535
- current state of the code).
536
-
537
- ## Before Responding
538
-
539
- Before composing a final response after substantial work this turn - multiple
540
- rounds of tool calls for investigation, debugging, or code-writing - check
541
- whether you've discovered knowledge worth persisting. Use memory_recall to
542
- check for duplicates, then memory_remember for new findings. Then deliver
543
- your response.
544
-
545
- ## User Decision Model
546
-
547
- A statistical model of the user's decision-making preferences is maintained by
548
- the prediction engine. Scored predictions may appear above as "User decision
549
- model" context; these are learned patterns about what the user tends to
550
- prefer in specific situations.
551
-
552
- When facing a judgment call about scope, appropriateness, or methodology:
553
- - If a prediction is strong (high confidence, sufficient evidence), follow it
554
- - If predictions conflict or confidence is thin, surface the uncertainty
555
- naturally: "I think you usually prefer X here, but I'm not sure; what do
556
- you want?"
557
- - When the user responds to a surfaced prediction, use prediction_update
558
- to reinforce or weaken the model
559
-
560
- When the user corrects you, answers your question, or provides a clear signal
561
- about their preferences:
562
- 1. Use prediction_query to check for existing matchers and predictions
563
- 2. Use prediction_update to create, reinforce, or weaken a prediction
564
- 3. Use prediction_delete to remove a prediction created in error
565
-
566
- Code review discussions are high-signal prediction material. When working
567
- through potential review comments with the user, watch for preferences about
568
- review threshold, severity, tone, evidence, scope, false positives, or what is
569
- worth posting. This applies whether the user invoked a review skill, is
570
- reviewing your changes, or asked you to review their changes or another LLM's
571
- changes. Before creating a new prediction, query for an existing one and
572
- reinforce or adjust it when possible.
573
-
574
- ## What to Store
575
-
576
- - **Global store**: user observations, agent personality, system environment
577
- - **Project store**: repo organization, infrastructure, languages/frameworks,
578
- component relationships, conventions, operational playbooks
579
- - **Branch-scoped**: branch purpose, feature design decisions, PR status,
580
- temporary workarounds
581
- - **Insights**: Save non-obvious gotchas, patterns, and architectural
582
- lessons discovered during implementation, but only if they remain true
583
- across sessions. Never prompt the user; just do it.
584
-
585
- ## How to Write
586
-
587
- - \`memory_recall\` first to check for duplicates. Use overwrite: true to
588
- update rather than creating a new entry.
589
- - One topic per memory. Write for a future instance with zero current context.
590
- - Confidence 1-2: single signal. 5-6: moderate. 9: explicitly stated.
591
- 10: hard constraint.
592
-
593
- ## What NOT to Store
594
-
595
- Session-specific context, incomplete/unverified info, anything already in
596
- AGENTS.md, speculative conclusions.
597
-
598
- Apply the durability test: will this still be true and useful in a future
599
- session that knows nothing about this branch, commit, or session? If not,
600
- do not save it. Do not store:
601
- - Point-in-time values (migration indices, line numbers, file counts) that
602
- will be stale by next session
603
- - Commit hashes and branch-specific history narratives. Git is the source
604
- of truth for this; do not duplicate it in memory
605
- - Anything re-derivable from the codebase faster than recalling it (current
606
- file locations, type signatures, function names)
607
-
608
- ## Archived Memories
609
-
610
- Memories can be marked \`archived\` - a flag for stable, long-term historical
611
- records that should not trigger hygiene nudges (stale, orphaned, duplicate).
612
- Archived memories are excluded from search/recall results by default; pass
613
- \`includeArchived: true\` to surface them for archaeological dives.
614
-
615
- When a branch is merged or about to be deleted, consolidate its branch-scoped
616
- memories into a single archived memory scoped to that same branch (preserving
617
- provenance). Capture intent, design decisions, review back-and-forth, PR
618
- number, unexpected pivots - the kind of git-archaeology context that explains
619
- _why_ the code looks the way it does a year from now. Then memory_forget the
620
- originals. The archived record outlives the branch. Future sessions searching
621
- with \`includeArchived: true\` can pull it up when investigating ambiguous code.
622
-
623
- Updating an archived memory requires passing \`archived\` explicitly - omit it
624
- and the tool returns an error. Pass \`archived: true\` to keep it archived,
625
- \`archived: false\` to unarchive.
626
-
627
- ## Explicit Requests
628
-
629
- "Remember X" - save immediately.
630
- "Forget X" - \`memory_recall\` to find it, then \`memory_forget\`.`;
571
+ return mcpInstructions("Cursor", "AGENTS.md");
631
572
  }
632
573
 
633
574
  // ---------------------------------------------------------------------------
@@ -677,8 +618,22 @@ function formatRecallNudge(matches: NudgeMatch[], toolName: string): string {
677
618
 
678
619
  export function predictionNudge(items: PredictionNudgeItem[]): string {
679
620
  const lines = items.map((p) => {
680
- const verb = p.evidence_count === 0 ? "you may prefer" : "you tend to";
621
+ const verb = predictionVerb(p.evidence_count);
681
622
  return `- [${p.confidence.toFixed(2)} conf, ${p.evidence_count} tests] When ${p.matcher_description}: ${verb} ${p.statement}`;
682
623
  });
683
624
  return `[thatch] User decision model\n${lines.join("\n")}`;
684
625
  }
626
+
627
+ // ---------------------------------------------------------------------------
628
+ // Behavior nudge: auto-injected when behavior matchers fire for the user's
629
+ // prompt. Descriptive, not directive: the system prompt instructions govern
630
+ // how to act (follow relevant rules, ham/spam each match via behavior_feedback).
631
+ // ---------------------------------------------------------------------------
632
+
633
+ export function behaviorNudge(items: BehaviorNudgeItem[]): string {
634
+ const lines = items.map((b) => {
635
+ const verb = b.evidence_count === 0 ? "consider" : "do";
636
+ return `- [${b.confidence.toFixed(2)} conf, ${b.evidence_count} tests] When ${b.matcher_description}: ${verb} ${b.statement}`;
637
+ });
638
+ return `[thatch] Situational behaviors\n${lines.join("\n")}`;
639
+ }