@jeffober/thatch 0.1.6 → 0.1.9
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/bin/release +24 -3
- package/docs/dev/README.md +3 -2
- package/docs/dev/setup-and-hooks.md +3 -2
- package/docs/dev/skills.md +13 -6
- package/package.json +1 -1
- package/src/index.ts +24 -2
- package/src/prompts.ts +3 -3
- package/src/skills.ts +167 -9
package/bin/release
CHANGED
|
@@ -22,9 +22,30 @@ echo " bump: $v"
|
|
|
22
22
|
echo " next: $next"
|
|
23
23
|
echo
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
# Pre-flight: verify the current version is published on npm before allowing a
|
|
26
|
+
# new release. A tagged-but-unpublished version means the prior publish failed;
|
|
27
|
+
# stacking another release on top hides the gap and complicates recovery.
|
|
28
|
+
if git rev-parse -q --verify "refs/tags/v$curr" >/dev/null 2>&1; then
|
|
29
|
+
pub_status=$(npm view "@jeffober/thatch@$curr" version 2>&1 || true)
|
|
30
|
+
if ! echo "$pub_status" | grep -q "^$curr$"; then
|
|
31
|
+
if echo "$pub_status" | grep -q "E404"; then
|
|
32
|
+
echo "ERROR: v$curr is tagged but not published to npm."
|
|
33
|
+
echo " The previous release failed. Check: gh run view --workflow=publish.yml"
|
|
34
|
+
echo " Fix the workflow, delete and re-tag v$curr, push, then re-run this release."
|
|
35
|
+
echo " To re-tag: git tag -d v$curr && git tag v$curr <commit> && git push origin :refs/tags/v$curr && git push origin v$curr"
|
|
36
|
+
exit 1
|
|
37
|
+
else
|
|
38
|
+
echo "WARN: npm registry check failed (not a 404 — may be a network issue or npm outage):"
|
|
39
|
+
echo " $pub_status"
|
|
40
|
+
echo " Proceeding anyway. Verify v$curr is published before relying on this."
|
|
41
|
+
echo
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo "▸ running checks (typecheck + tests + markdown lint)..."
|
|
47
|
+
mise run check
|
|
48
|
+
echo " ✓ checks passed"
|
|
28
49
|
echo
|
|
29
50
|
|
|
30
51
|
echo "▸ bumping version..."
|
package/docs/dev/README.md
CHANGED
|
@@ -70,9 +70,10 @@ bin/thatch → CLI: stores|list|show|forget|search|mcp|reminder|hygi
|
|
|
70
70
|
| Hook | What it does |
|
|
71
71
|
|------|-------------|
|
|
72
72
|
| `experimental.chat.system.transform` | Appends the thatch system prompt (store names, usage rules). |
|
|
73
|
-
| `experimental.session.compacting` |
|
|
73
|
+
| `experimental.session.compacting` | Marks the session as compacting and appends re-familiarization context so a compacted session still knows thatch exists. |
|
|
74
|
+
| `experimental.compaction.autocontinue` | Clears the compacting flag so `chat.message` nudges resume. Without this, nudges that instruct tool calls would fire during summary generation where tools are blocked. |
|
|
74
75
|
| `tool.execute.after` | Buffers every non-`thatch_*` tool call into the session's extraction buffer. This is a plugin hook, NOT a bus event — do not move it into the `event` handler; the event bus has no such event and it will silently never fire. |
|
|
75
|
-
| `chat.message` | Two priority tiers: (a) if extraction buffer has interactions, flushes them as a synthetic text part carrying the extraction nudge + JSON payload; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). |
|
|
76
|
+
| `chat.message` | Two priority tiers: (a) if extraction buffer has interactions, flushes them as a synthetic text part carrying the extraction nudge + JSON payload; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). Skipped entirely while the session is compacting (tool calls are blocked during summary generation). |
|
|
76
77
|
| `event` (`session.created`) | Sends the session-start reminder via `client.session.prompt`, carrying the hygiene heartbeat (pending dedup pairs, stale count, orphaned branch memories) when any signal is non-zero. The session id is at `event.properties.info.id`. |
|
|
77
78
|
| `dispose` | Closes the DB. |
|
|
78
79
|
|
|
@@ -17,9 +17,10 @@ The plugin entry (`src/index.ts`) registers these hooks in code:
|
|
|
17
17
|
| Hook | Input | Output | Behavior |
|
|
18
18
|
|------|-------|--------|----------|
|
|
19
19
|
| `experimental.chat.system.transform` | `{}` | `{ system: string[] }` | Pushes the system prompt (store names, usage rules). |
|
|
20
|
-
| `experimental.session.compacting` | `{}` | `{ context: string[] }` |
|
|
20
|
+
| `experimental.session.compacting` | `{ sessionID }` | `{ context: string[] }` | Marks the session as compacting, pushes re-familiarization context. |
|
|
21
|
+
| `experimental.compaction.autocontinue` | `{ sessionID }` | `{ enabled: boolean }` | Clears the compacting flag so `chat.message` nudges resume post-compaction. |
|
|
21
22
|
| `tool.execute.after` | `{ tool, sessionID, callID, args }` | `{ title, output, metadata }` | Buffers non-`thatch_` tool calls into the in-memory extraction ring buffer (max 20). |
|
|
22
|
-
| `chat.message` | `{ sessionID, messageID }` | `{ message, parts }` | Two tiers: extraction nudge if pending, else prompt-aware recall nudge. |
|
|
23
|
+
| `chat.message` | `{ sessionID, messageID }` | `{ message, parts }` | Two tiers: extraction nudge if pending, else prompt-aware recall nudge. Skipped while the session is compacting. |
|
|
23
24
|
| `event` (`session.created`) | `{ event: { type, properties: { info: { id } } } }` | — | Calls `client.session.prompt` with the reminder + hygiene heartbeat. |
|
|
24
25
|
| `dispose` | — | — | Closes the DB. |
|
|
25
26
|
|
package/docs/dev/skills.md
CHANGED
|
@@ -21,9 +21,9 @@ description: Extract durable project facts ... Use when ...
|
|
|
21
21
|
- `description` drives when the agent loads the skill (both opencode and
|
|
22
22
|
Cursor auto-discover skills and use the description for relevance).
|
|
23
23
|
|
|
24
|
-
## The
|
|
24
|
+
## The 12 skills
|
|
25
25
|
|
|
26
|
-
**Shared (
|
|
26
|
+
**Shared (11)** — installed everywhere; no sub-agents required:
|
|
27
27
|
|
|
28
28
|
| Skill | Role |
|
|
29
29
|
|-------|------|
|
|
@@ -36,13 +36,14 @@ description: Extract durable project facts ... Use when ...
|
|
|
36
36
|
| `thatch-review-no-slop` | AI writing anti-patterns: change narration, fourth-wall breaks, em dashes, filler. |
|
|
37
37
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of behavior? |
|
|
38
38
|
| `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. |
|
|
39
|
+
| `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. |
|
|
39
40
|
| `thatch-session-reflection` | End-of-session memory recording (project, user, tools, self). |
|
|
40
41
|
|
|
41
42
|
**opencode-only (1)** — the coordinator needs sub-agent support:
|
|
42
43
|
|
|
43
44
|
| Skill | Role |
|
|
44
45
|
|-------|------|
|
|
45
|
-
| `thatch-code-review` | Resolve review target, estimate complexity, partition, dispatch the 5 specialists in parallel, synthesize. |
|
|
46
|
+
| `thatch-code-review` | Resolve review target, gather context, estimate complexity, partition, dispatch the 5 specialists in parallel, synthesize. |
|
|
46
47
|
|
|
47
48
|
## REVIEW_COMMON
|
|
48
49
|
|
|
@@ -57,6 +58,12 @@ The five review specialists share a framework interpolated via `${REVIEW_COMMON}
|
|
|
57
58
|
trigger; "the code allows this" is not enough.
|
|
58
59
|
- **Intent verification** — trace callers, check git history, and `thatch_memory_recall`
|
|
59
60
|
for design rationale before flagging a behavior as a bug.
|
|
61
|
+
- **Project context awareness** — if a context brief is provided (from the
|
|
62
|
+
coordinator or from loading `thatch-review-context`), use it to avoid false
|
|
63
|
+
positives about intentionally deferred work.
|
|
64
|
+
- **TODO ($ticket) markers** — recognize `TODO ($TICKET-ID): ...` as legitimate
|
|
65
|
+
breadcrumbs for deferred work, not stale artifacts. Flag only if the referenced
|
|
66
|
+
ticket is closed or merged.
|
|
60
67
|
- **Output format** — `[SEVERITY] [CATEGORY] file:line` with finding, evidence
|
|
61
68
|
(quoted), trigger, reachability, source of truth, producer chain, provenance.
|
|
62
69
|
|
|
@@ -66,7 +73,7 @@ The synthesizer reuses the same verification rigor but has its own structure
|
|
|
66
73
|
## The two arrays
|
|
67
74
|
|
|
68
75
|
```ts
|
|
69
|
-
const SHARED_SKILLS: SkillDef[] = [ /*
|
|
76
|
+
const SHARED_SKILLS: SkillDef[] = [ /* 11 skills above */ ];
|
|
70
77
|
const OPENCODE_ONLY_SKILLS: SkillDef[] = [ /* code-review coordinator */ ];
|
|
71
78
|
```
|
|
72
79
|
|
|
@@ -100,8 +107,8 @@ and `--cursor` pass only the shared set.
|
|
|
100
107
|
## Memory review skills in practice
|
|
101
108
|
|
|
102
109
|
- **Quick single lens**: load any specialist directly and point it at a branch.
|
|
103
|
-
- **Full review on opencode**: load `thatch-code-review` — it dispatches all 5
|
|
104
|
-
specialists in parallel, then synthesizes.
|
|
110
|
+
- **Full review on opencode**: load `thatch-code-review` — it gathers project context, dispatches all 5
|
|
111
|
+
specialists in parallel (with context injected into each briefing), then synthesizes.
|
|
105
112
|
- **Full review on Claude Code/Cursor**: run each specialist in sequence, then
|
|
106
113
|
run `thatch-review-synthesizer` to verify and aggregate.
|
|
107
114
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffober/thatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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",
|
package/src/index.ts
CHANGED
|
@@ -41,6 +41,14 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
41
41
|
const model = new BgeEmbeddingModel(modelName);
|
|
42
42
|
const extraction = new ExtractionPipeline();
|
|
43
43
|
|
|
44
|
+
// Sessions currently being compacted. chat.message nudges are skipped while
|
|
45
|
+
// a session is in this set — the agent can't call tools during summary
|
|
46
|
+
// generation, so a recall or extraction nudge would cause a blocked-tool
|
|
47
|
+
// error. Cleared by experimental.compaction.autocontinue. If compaction
|
|
48
|
+
// fails, the entry leaks (graceful degradation: nudges stay off for that
|
|
49
|
+
// session, but no crash).
|
|
50
|
+
const compacting = new Set<string>();
|
|
51
|
+
|
|
44
52
|
// Skills always install to the global opencode config — installing into the
|
|
45
53
|
// worktree would mutate the user's repo (untracked files in git status).
|
|
46
54
|
// A failed install degrades the nudge workflow but must not kill the plugin.
|
|
@@ -64,11 +72,20 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
64
72
|
output.system.push(sys);
|
|
65
73
|
},
|
|
66
74
|
|
|
67
|
-
// 2. Compaction context — re-familiarizes after compaction.
|
|
68
|
-
|
|
75
|
+
// 2. Compaction context — re-familiarizes after compaction. The flag
|
|
76
|
+
// suppresses chat.message nudges during summary generation (tool
|
|
77
|
+
// calls are blocked there).
|
|
78
|
+
"experimental.session.compacting": async (input, output) => {
|
|
79
|
+
compacting.add(input.sessionID);
|
|
69
80
|
output.context.push(compact);
|
|
70
81
|
},
|
|
71
82
|
|
|
83
|
+
// 2b. Clear the compacting flag after compaction succeeds so chat.message
|
|
84
|
+
// nudges resume for the synthetic auto-continue turn and beyond.
|
|
85
|
+
"experimental.compaction.autocontinue": async (input) => {
|
|
86
|
+
compacting.delete(input.sessionID);
|
|
87
|
+
},
|
|
88
|
+
|
|
72
89
|
// 3. Tool buffering — feeds the extraction nudge. Thatch's own tools are
|
|
73
90
|
// excluded: extracting facts from memory operations would just echo the
|
|
74
91
|
// store back into itself.
|
|
@@ -89,7 +106,12 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
89
106
|
// b. Recall nudge: the user's prompt semantically matches existing
|
|
90
107
|
// memories — surface that prior knowledge exists before the agent
|
|
91
108
|
// responds. Uses the in-process warm model (no sideband needed).
|
|
109
|
+
//
|
|
110
|
+
// Skipped during compaction: the agent can't call tools while generating
|
|
111
|
+
// a summary, so a nudge that says "use thatch_memory_recall" triggers a
|
|
112
|
+
// blocked-tool error.
|
|
92
113
|
"chat.message": async (input, output) => {
|
|
114
|
+
if (compacting.has(input.sessionID)) return;
|
|
93
115
|
if (extraction.pending(input.sessionID)) {
|
|
94
116
|
const batch = extraction.flush(input.sessionID);
|
|
95
117
|
const payload = extraction.buildPayload(batch, repo);
|
package/src/prompts.ts
CHANGED
|
@@ -64,9 +64,9 @@ CLAUDE.md or OPENCODE.md, speculative conclusions.
|
|
|
64
64
|
|
|
65
65
|
export function compactionContext(repo: string): string {
|
|
66
66
|
return `Thatch persistent memory is active with stores "${repo}" and "global".
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
When summarizing, preserve context about what's been learned and decided
|
|
68
|
+
this session — conventions, architectural decisions, and prior knowledge
|
|
69
|
+
retrieved from memory. This ensures continuity after compaction.`;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export function sessionStartReminder(repo: string, hygiene?: string | null): string {
|
package/src/skills.ts
CHANGED
|
@@ -72,6 +72,8 @@ Identify the application's runtime model early: Is it a CLI tool (process exits
|
|
|
72
72
|
## Reachability gate
|
|
73
73
|
For every potential finding, you MUST describe a concrete scenario where a real user triggers the problem through normal usage. "The code allows this" is not sufficient — show how a user actually encounters it given the application's runtime model. If the only trigger requires conditions that cannot occur in actual usage, it is not a finding.
|
|
74
74
|
|
|
75
|
+
Before claiming a value can hold a problematic state (NULL, orphaned, out-of-range, wrong-type), read the artifact that governs that state: the column definition, type declaration, FK/NOT NULL constraint, validation, or guard. Quote it in your finding. If a schema constraint, type, or guard makes the state unreachable, it is not a finding. "The join could drop rows" requires proving a droppable row can exist — cite the constraint that permits it.
|
|
76
|
+
|
|
75
77
|
## Intent verification
|
|
76
78
|
Before flagging behavior as a bug, verify intent:
|
|
77
79
|
1. **Trace callers.** Read every caller of the cited code. The behavior may be intentional given how the feature is actually used.
|
|
@@ -80,6 +82,18 @@ Before flagging behavior as a bug, verify intent:
|
|
|
80
82
|
|
|
81
83
|
If any of these reveals the behavior is intentional, it is not a finding. If you cannot determine intent after all three steps, you may report it — but note that you could not confirm whether the behavior is intentional.
|
|
82
84
|
|
|
85
|
+
## Project context awareness
|
|
86
|
+
If your briefing includes a project context brief (from the coordinator or from loading thatch-review-context), use it to calibrate your findings:
|
|
87
|
+
- **Deferred work** listed in the brief is intentionally excluded from this PR. Do not flag the absence of deferred pieces as bugs, inconsistencies, or missing functionality.
|
|
88
|
+
- **Dependencies** in the brief tell you whether base-branch behavior is expected to be present or not. Do not assert that base-branch behavior exists without verifying it landed.
|
|
89
|
+
- **Relevant constraints** may explain why code is structured a certain way. Consider them before flagging design choices.
|
|
90
|
+
|
|
91
|
+
## TODO ($ticket) markers
|
|
92
|
+
Code may contain \`TODO ($TICKET-ID): description\` comments that mark intentionally deferred work: temporary code, placeholders for future tickets, or planned cleanups. These are legitimate breadcrumbs, not stale artifacts.
|
|
93
|
+
- Do NOT flag a TODO ($ticket) marker as a stale artifact if the ticket it references is still open or future work.
|
|
94
|
+
- DO flag it if you can verify the referenced ticket is closed or merged (the TODO is now stale).
|
|
95
|
+
- If your briefing includes a context brief that lists the deferred work, use it to determine whether the ticket is still pending.
|
|
96
|
+
|
|
83
97
|
## Output format
|
|
84
98
|
Produce findings as markdown. For each finding:
|
|
85
99
|
|
|
@@ -453,11 +467,13 @@ For each, walk through actual function calls, tracking data shape at each step.
|
|
|
453
467
|
|
|
454
468
|
### 4. Prove the producer chain
|
|
455
469
|
For every finding about invalid state, missing data, shape mismatches, or cross-module behavior, trace the full causal chain:
|
|
456
|
-
- Who produces the state or value?
|
|
470
|
+
- Who produces the state or value? Cite the file:line that writes the problematic value.
|
|
457
471
|
- Which functions transform it?
|
|
458
472
|
- Which consumer or branch fails?
|
|
459
473
|
- Which real entrypoint/workflow exercises that chain?
|
|
460
474
|
|
|
475
|
+
The producer must be a specific file:line in current code that writes the problematic value. "Source deletion could orphan this" is not a producer; the file:line where a row is written with a dangling reference is. If no such write site exists in the codebase, the state is unreachable — do not report it.
|
|
476
|
+
|
|
461
477
|
If you cannot identify a real producer in current code, or the only way to trigger the issue is by manually fabricating invalid state/data, do not report it as a real finding.
|
|
462
478
|
|
|
463
479
|
### 5. Identify the implicit FSM
|
|
@@ -490,6 +506,10 @@ For each new module or significant change:
|
|
|
490
506
|
- **DEAD_PATH**: Code path exists but cannot be reached given current callers/preconditions
|
|
491
507
|
|
|
492
508
|
For each finding, cite both sides of any contract (file:line for caller and callee).
|
|
509
|
+
|
|
510
|
+
## Worked non-finding (negative example)
|
|
511
|
+
|
|
512
|
+
Example non-finding: "INNER JOIN on source_id silently drops rows whose source was deleted." Before reporting, read the FK: if source_id is NOT NULL with a foreign key and deletion cascades to children, an orphaned row cannot exist and the drop is unreachable. Reporting it anyway is the canonical reachability failure. The fix is not to switch to LEFT JOIN (which would add dead code for an impossible case) but to verify the constraint that governs the state.
|
|
493
513
|
`;
|
|
494
514
|
|
|
495
515
|
const REVIEW_NO_SLOP = `---
|
|
@@ -660,6 +680,8 @@ For each finding from the specialists:
|
|
|
660
680
|
- Identify the real entrypoint/workflow that exercises this chain.
|
|
661
681
|
If the only way to trigger the issue is by manually fabricating invalid data/state or bypassing the real producers/guards, reject the finding. If the citation is real but you cannot prove the producer chain, classify as UNVERIFIABLE rather than CONFIRMED.
|
|
662
682
|
|
|
683
|
+
5a. **Verify governing constraints for data-shape findings.** For findings claiming a field can be NULL/missing/orphaned/malformed, locate and read the field's definition (schema migration, model, type declaration). If a NOT NULL, FK, enum, or type constraint forecloses the claimed state, REJECT and cite the constraint. Do not classify such a finding CONFIRMED without having read the governing definition.
|
|
684
|
+
|
|
663
685
|
6. **Verify intent (behavioral findings only).** If the specialist flagged behavior as a bug but the code appears to work as designed, check whether the behavior is intentional:
|
|
664
686
|
- Read the callers of the cited code to see if the pattern makes sense in context.
|
|
665
687
|
- Check git log or git blame on the cited file for commit messages explaining the decision.
|
|
@@ -673,9 +695,9 @@ For each finding from the specialists:
|
|
|
673
695
|
Runtime reachability, producer chains, and intent verification do not apply. A mechanical finding is not a "bug" and does not need a "trigger scenario."
|
|
674
696
|
|
|
675
697
|
7. **Classify:**
|
|
676
|
-
- **CONFIRMED**: For behavioral findings: the cited code matches, the claim is accurate, the bug is reachable through realistic usage, you proved the workflow/producer chain where applicable,
|
|
677
|
-
- **REJECTED**: For behavioral findings: the citation is wrong, the claim is inaccurate, the bug cannot manifest in the actual runtime context,
|
|
678
|
-
- **UNVERIFIABLE**: The citation is correct but you cannot confirm the claim without deeper tracing. This is the default for plausible behavioral claims that lack a proven trigger path, producer chain, or authoritative source of truth. Mechanical findings should rarely be UNVERIFIABLE — if the text exists and violates the guideline, it is CONFIRMED.
|
|
698
|
+
- **CONFIRMED**: For behavioral findings: the cited code matches, the claim is accurate, the bug is reachable through realistic usage, you proved the workflow/producer chain where applicable, the behavior is not intentional, and for data-shape findings you read and cited the governing constraint confirming the claimed state is reachable. For mechanical findings: the cited text exists, is branch-introduced or newly made relevant, and violates the stated guideline or specialist taxonomy.
|
|
699
|
+
- **REJECTED**: For behavioral findings: the citation is wrong, the claim is inaccurate, the bug cannot manifest in the actual runtime context, the behavior is an intentional design decision (explain why briefly), or a governing constraint (NOT NULL, FK, type, guard) forecloses the claimed state. Reject findings that rely on manually seeded invalid state/data with no real producer path. For mechanical findings: the cited text does not exist, does not violate the stated guideline, is unchanged legacy outside the touched scope, or the finding duplicates another confirmed finding.
|
|
700
|
+
- **UNVERIFIABLE**: The citation is correct but you cannot confirm the claim without deeper tracing. This is the default for plausible behavioral claims that lack a proven trigger path, producer chain, or authoritative source of truth. A data-shape finding that lacks the governing-constraint citation is UNVERIFIABLE, not CONFIRMED. Mechanical findings should rarely be UNVERIFIABLE — if the text exists and violates the guideline, it is CONFIRMED.
|
|
679
701
|
|
|
680
702
|
## Deduplication
|
|
681
703
|
|
|
@@ -691,6 +713,8 @@ Assign final severity based on YOUR verification:
|
|
|
691
713
|
- **MEDIUM**: Edge cases, UX friction, or issues where the citation is correct but the impact is limited or requires unusual conditions.
|
|
692
714
|
- **LOW**: Mechanical issues (stale docs, guideline violations, naming) that don't affect correctness.
|
|
693
715
|
|
|
716
|
+
A data-shape or reachability finding that lacks the governing-constraint citation (the schema, type, or guard definition you read to confirm the state is reachable) is capped at UNVERIFIABLE. It cannot be classified CONFIRMED or assigned a severity. This removes the path where a plausible-but-unchecked claim lands at MEDIUM.
|
|
717
|
+
|
|
694
718
|
## Report format
|
|
695
719
|
|
|
696
720
|
You MUST produce the full report structure below. Do not simplify or omit sections. Every confirmed finding must include all numbered fields. If a section has no entries, write "None" — do not skip the section.
|
|
@@ -721,6 +745,122 @@ Findings you verified as real but pre-existing, with a one-line note on the issu
|
|
|
721
745
|
Note which files or areas were NOT covered by any specialist.
|
|
722
746
|
`;
|
|
723
747
|
|
|
748
|
+
// ---------------------------------------------------------------------------
|
|
749
|
+
// Review context builder — gathers project/feature context before fan-out
|
|
750
|
+
// ---------------------------------------------------------------------------
|
|
751
|
+
|
|
752
|
+
const REVIEW_CONTEXT = `---
|
|
753
|
+
name: thatch-review-context
|
|
754
|
+
description: Gather project and feature context before a code review. Investigates PR descriptions, git history, ticket references, docs, and memory to build a context brief that prevents false positives about intentionally deferred work. Use before dispatching review specialists or running a solo review.
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
You are a review context builder. Your job is to gather project context that gives reviewers the background they need to avoid false positives about intentionally deferred work, incomplete features, and multi-ticket dependencies.
|
|
758
|
+
|
|
759
|
+
## Why this matters
|
|
760
|
+
|
|
761
|
+
A specialist reviewer without project context will flag missing pieces of a feature as bugs or inconsistencies. If the PR is one ticket in a multi-ticket effort, the "missing" piece may be scheduled for the next ticket. Context prevents these false positives.
|
|
762
|
+
|
|
763
|
+
## Sources to investigate
|
|
764
|
+
|
|
765
|
+
Work through these sources in order. Not every source will yield information for every change. Skip sources that produce nothing rather than forcing a narrative.
|
|
766
|
+
|
|
767
|
+
### 1. PR description
|
|
768
|
+
If reviewing a PR, read the description:
|
|
769
|
+
- \`gh pr view N --json title,body,labels,milestone\` (or the local branch's PR if detected)
|
|
770
|
+
- Extract: stated scope, what is intentionally excluded, ticket references, linked PRs
|
|
771
|
+
|
|
772
|
+
### 2. Branch name
|
|
773
|
+
Branch names often contain ticket identifiers. Look for patterns:
|
|
774
|
+
- \`user/ticket-123\`, \`user/plat-122\`, \`feature/PROJ-456\`
|
|
775
|
+
- Extract the ticket ID and use it to search other sources
|
|
776
|
+
|
|
777
|
+
### 3. Git archaeology
|
|
778
|
+
- \`git log --oneline merge-base..HEAD\` — commit messages may reference tickets, describe scope, or mention future work
|
|
779
|
+
- \`git log --all --oneline --grep="TICKET-ID"\` — find related commits on other branches
|
|
780
|
+
- \`git log -S "TODO (TICKET"\` — find TODO markers that reference this or related tickets
|
|
781
|
+
- \`git branch -a\` — other branches may show planned or in-progress related work
|
|
782
|
+
|
|
783
|
+
### 4. TODO ($ticket) markers in the diff
|
|
784
|
+
Scan the diff for TODO markers that reference ticket identifiers:
|
|
785
|
+
- Pattern: \`TODO ($TICKET-ID): description\`
|
|
786
|
+
- Example: \`// TODO (PLAT-123): replace this temporary flag with the real config loader\`
|
|
787
|
+
- Example: \`// TODO (PLAT-124): this fallback will be removed when the new API lands\`
|
|
788
|
+
- These mark intentionally deferred work: cleanups, temporary code, or pieces to be introduced later
|
|
789
|
+
- Each marker tells a reviewer "this is known and scheduled, not missing"
|
|
790
|
+
- Extract the ticket IDs and note what is deferred
|
|
791
|
+
|
|
792
|
+
### 5. Thatch memories (RAG)
|
|
793
|
+
Call \`thatch_memory_recall\` with queries like:
|
|
794
|
+
- The feature or project name (if known from the PR or branch)
|
|
795
|
+
- The ticket identifier
|
|
796
|
+
- "feature status" or "milestone" or "roadmap"
|
|
797
|
+
- Any architectural decisions or design docs related to the changed area
|
|
798
|
+
|
|
799
|
+
### 6. Project documentation
|
|
800
|
+
- README, docs/, design docs, ADRs
|
|
801
|
+
- CONTRIBUTING.md or equivalent for conventions
|
|
802
|
+
- Any roadmap, milestone, or project plan documents
|
|
803
|
+
|
|
804
|
+
### 7. Issue tracker (if accessible)
|
|
805
|
+
If ticket IDs were found:
|
|
806
|
+
- \`gh issue list --search "TICKET-ID"\` or \`gh issue view N\`
|
|
807
|
+
- Look for milestone assignments, dependencies, and blocking relationships
|
|
808
|
+
- Check for epic or parent issues that describe the overall feature
|
|
809
|
+
|
|
810
|
+
## Context brief format
|
|
811
|
+
|
|
812
|
+
Produce a structured brief:
|
|
813
|
+
|
|
814
|
+
### Project context
|
|
815
|
+
- What larger initiative or feature this change is part of
|
|
816
|
+
- The ticket or milestone this PR implements
|
|
817
|
+
|
|
818
|
+
### This change's scope
|
|
819
|
+
- What this PR is scoped to deliver (from PR description, commit messages, diff analysis)
|
|
820
|
+
- What is explicitly excluded or deferred
|
|
821
|
+
|
|
822
|
+
### Deferred work
|
|
823
|
+
List each deferred piece:
|
|
824
|
+
- What is deferred
|
|
825
|
+
- Which ticket will deliver it (if known)
|
|
826
|
+
- Any TODO ($ticket) markers in the code that annotate it
|
|
827
|
+
|
|
828
|
+
### Dependencies
|
|
829
|
+
- What other tickets or PRs this depends on (must merge first)
|
|
830
|
+
- What tickets or PRs depend on this (are blocked by it)
|
|
831
|
+
- Whether base branches have landed (for stacked PRs)
|
|
832
|
+
|
|
833
|
+
### Relevant constraints
|
|
834
|
+
- Design decisions or architectural constraints from memories or docs
|
|
835
|
+
- Conventions that reviewers should be aware of
|
|
836
|
+
|
|
837
|
+
## If context is sparse
|
|
838
|
+
|
|
839
|
+
Not every PR will have rich context. If you find minimal context:
|
|
840
|
+
- State what you looked for and what you found
|
|
841
|
+
- Note that the change appears to be standalone (no multi-ticket dependencies detected)
|
|
842
|
+
- Flag any TODO ($ticket) markers in the diff even if you could not resolve the ticket
|
|
843
|
+
|
|
844
|
+
## The TODO ($ticket) convention
|
|
845
|
+
|
|
846
|
+
When code is intentionally temporary or incomplete because work is split across tickets, mark it with a TODO that references the ticket that will resolve it:
|
|
847
|
+
|
|
848
|
+
\`\`\`
|
|
849
|
+
// TODO ($TICKET-ID): description of what will be done or removed here
|
|
850
|
+
\`\`\`
|
|
851
|
+
|
|
852
|
+
Examples:
|
|
853
|
+
- \`// TODO (PLAT-123): replace this temporary flag with the real config loader\`
|
|
854
|
+
- \`// TODO (PLAT-124): this fallback will be removed when the new API lands\`
|
|
855
|
+
- \`# TODO (INFRA-456): delete this compatibility shim once all callers migrate\`
|
|
856
|
+
|
|
857
|
+
These markers serve as breadcrumbs for reviewers (human and LLM) who lack project context:
|
|
858
|
+
- They signal "this is known and scheduled, not a bug or oversight"
|
|
859
|
+
- They link the code to the ticket that will resolve it
|
|
860
|
+
- They should NOT be flagged as stale artifacts (the work is not yet completed)
|
|
861
|
+
- They SHOULD be flagged if the referenced ticket is closed or merged (the TODO is now stale)
|
|
862
|
+
`;
|
|
863
|
+
|
|
724
864
|
// ---------------------------------------------------------------------------
|
|
725
865
|
// Session reflection — end-of-session memory recording guidance
|
|
726
866
|
// ---------------------------------------------------------------------------
|
|
@@ -821,7 +961,22 @@ Fetch any refs not locally reachable so branches and PRs that were never checked
|
|
|
821
961
|
|
|
822
962
|
Run git diff --stat on the resolved range and git log --oneline to understand the change.
|
|
823
963
|
|
|
824
|
-
## Step 2:
|
|
964
|
+
## Step 2: Gather project context
|
|
965
|
+
|
|
966
|
+
Load the thatch-review-context skill and follow its methodology to build a context brief for this change. Investigate:
|
|
967
|
+
- PR description (if a PR was specified or detected via the branch)
|
|
968
|
+
- Branch name for ticket identifiers
|
|
969
|
+
- Git log for commit messages referencing tickets or describing scope
|
|
970
|
+
- TODO ($ticket) markers in the diff
|
|
971
|
+
- thatch_memory_recall for feature/project status, design decisions, ticket dependencies
|
|
972
|
+
- Project docs, READMEs, design docs
|
|
973
|
+
- Issue tracker (gh issue/view) if ticket IDs are found
|
|
974
|
+
|
|
975
|
+
Produce the context brief in the format the skill prescribes (project context, this change's scope, deferred work, dependencies, relevant constraints).
|
|
976
|
+
|
|
977
|
+
If context is sparse (no PR description, no ticket references, no relevant memories), note that the change appears standalone. Even a sparse brief is valuable: it tells specialists you looked and found nothing, so they do not need to repeat the search.
|
|
978
|
+
|
|
979
|
+
## Step 3: Estimate complexity
|
|
825
980
|
|
|
826
981
|
Estimate the review effort in scrum points (1-13 scale):
|
|
827
982
|
- **1**: Trivial — typo fix, config tweak, single-line change.
|
|
@@ -835,7 +990,7 @@ Points reflect *review complexity*, not implementation effort.
|
|
|
835
990
|
|
|
836
991
|
Identify files to exclude from review: vendored dependencies, generated files, lockfiles, compiled assets.
|
|
837
992
|
|
|
838
|
-
## Step
|
|
993
|
+
## Step 4: Partition (if > 3 points)
|
|
839
994
|
|
|
840
995
|
For changes estimated at more than 3 points, partition into review units of approximately 3 points each:
|
|
841
996
|
- Group files by logical component or feature, not by directory.
|
|
@@ -845,7 +1000,7 @@ For changes estimated at more than 3 points, partition into review units of appr
|
|
|
845
1000
|
|
|
846
1001
|
For changes estimated at 3 points or fewer, skip partitioning — dispatch one set of specialists covering the full scope. A single 3-point unit is not large enough to warrant decomposition.
|
|
847
1002
|
|
|
848
|
-
## Step
|
|
1003
|
+
## Step 5: Dispatch specialist sub-agents
|
|
849
1004
|
|
|
850
1005
|
For each review unit, dispatch sub-agents using the Task tool. Each sub-agent runs one specialist lens on one review unit. The five specialists are:
|
|
851
1006
|
|
|
@@ -864,7 +1019,7 @@ For the integration review unit (5+ points), dispatch a sub-agent focused on:
|
|
|
864
1019
|
- Boundary correctness — race conditions, ordering dependencies, shared state issues at boundaries.
|
|
865
1020
|
- Top-level coherence — does the overall change make sense as a unit?
|
|
866
1021
|
|
|
867
|
-
## Step
|
|
1022
|
+
## Step 6: Synthesize
|
|
868
1023
|
|
|
869
1024
|
After all sub-agents complete, load the thatch-review-synthesizer skill to verify findings, deduplicate across specialists, classify (CONFIRMED/REJECTED/UNVERIFIABLE), and produce the final severity-grouped report.
|
|
870
1025
|
|
|
@@ -885,10 +1040,12 @@ When dispatching each sub-agent, include in the prompt:
|
|
|
885
1040
|
- The specific files in this unit's scope
|
|
886
1041
|
- The specialist focus (from the five specialists above)
|
|
887
1042
|
- The diff stat for this unit's files
|
|
1043
|
+
- **The project context brief** from Step 2, filtered to what is relevant to this unit's scope. Explicitly list any deferred work that falls within this unit's files, and call out TODO ($ticket) markers the specialists should recognize as intentional.
|
|
888
1044
|
- Any design context or specific concerns
|
|
889
1045
|
- Explicit scope boundaries ("your scope is X; do NOT review Y")
|
|
890
1046
|
- Instruction to produce markdown findings with: severity, category, file:line, finding, evidence, trigger scenario, reachability, source of truth, producer chain, provenance
|
|
891
|
-
- Instruction to apply the reachability gate and intent verification before reporting
|
|
1047
|
+
- Instruction to apply the reachability gate (including reading and citing governing constraints for data-state claims) and intent verification before reporting
|
|
1048
|
+
- Instruction to respect the project context brief: do not flag deferred work as bugs or inconsistencies, and recognize TODO ($ticket) markers as intentional breadcrumbs
|
|
892
1049
|
`;
|
|
893
1050
|
|
|
894
1051
|
// ---------------------------------------------------------------------------
|
|
@@ -906,6 +1063,7 @@ const SHARED_SKILLS: SkillDef[] = [
|
|
|
906
1063
|
{ name: "thatch-review-no-slop", content: REVIEW_NO_SLOP },
|
|
907
1064
|
{ name: "thatch-review-breadcrumbs", content: REVIEW_BREADCRUMBS },
|
|
908
1065
|
{ name: "thatch-review-synthesizer", content: REVIEW_SYNTHESIZER },
|
|
1066
|
+
{ name: "thatch-review-context", content: REVIEW_CONTEXT },
|
|
909
1067
|
{ name: "thatch-session-reflection", content: SESSION_REFLECTION },
|
|
910
1068
|
];
|
|
911
1069
|
|