@jeffober/thatch 0.1.19 → 0.1.20

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 CHANGED
@@ -2,24 +2,14 @@
2
2
 
3
3
  [![CI](https://github.com/sysread/thatch/actions/workflows/ci.yml/badge.svg)](https://github.com/sysread/thatch/actions/workflows/ci.yml)
4
4
 
5
- ## Synopsis
5
+ Persistent memory and useful dev skills for AI coding agents. Works with
6
+ **OpenCode** (as a plugin), **Claude Code** (as a local MCP server), and
7
+ **Cursor** (as a local MCP server).
6
8
 
7
- Persistent memory and useful dev skills for AI coding agents that requires zero
8
- manual config.
9
-
10
- Works with **OpenCode** (as a plugin), **Claude Code** (as a local `stdio` MCP
11
- server), and **Cursor** (as a local `stdio` MCP server).
12
-
13
- Each session inherits the accumulated knowledge of every session before it —
14
- project architecture, conventions, gotchas, user preferences — so your agent
15
- starts with context instead of a blank slate. Stores are per-repo with a shared
16
- `global` store.
17
-
18
- On top of the memory layer, thatch ships a suite of skills for managing
19
- memories, performing in-depth, structured code reviews, managing the software
20
- development life cycle, and researching your code base.
21
-
22
- No API keys, no cloud services; everything runs on your machine.
9
+ Each session inherits the accumulated knowledge of every session before it:
10
+ project architecture, conventions, gotchas, user preferences. Your agent
11
+ starts with context instead of a blank slate. No API keys, no cloud services;
12
+ everything runs on your machine.
23
13
 
24
14
  ## Quick start
25
15
 
@@ -30,304 +20,86 @@ No API keys, no cloud services; everything runs on your machine.
30
20
  { "plugin": ["@jeffober/thatch"] }
31
21
  ```
32
22
 
33
- On next start, OpenCode npm-installs thatch (putting the `thatch` CLI on your
34
- PATH as a side effect) and its tools are available immediately.
35
-
36
- Set this environment variable so the extraction nudge can run the fact-extractor
37
- as a **background** sub-agent instead of blocking your turn:
23
+ On next start, OpenCode npm-installs thatch and its tools are available
24
+ immediately. For background extraction sub-agents:
38
25
 
39
26
  ```bash
40
27
  export OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true
41
28
  ```
42
29
 
43
- Without it, opencode hides the task tool's `background` parameter and every
44
- extraction nudge runs synchronously. Put it in your shell rc, `mise.toml`
45
- `[env]`, or `.envrc`.
46
-
47
- **Self-hosting** (local development):
48
-
49
- ```jsonc
50
- { "plugin": ["./path/to/thatch/src/index.ts"] }
51
- ```
52
-
53
- Or place the repo under `.opencode/plugins/` and OpenCode auto-loads it.
30
+ Then **prime your project memory** with by running `thatch prime` in your project directory.
31
+ This will launch an `opencode` session to build an initial map of the code base and its architecture to seed the memory.
54
32
 
55
- ### Claude Code
33
+ ### Claude Code and Cursor
56
34
 
57
- **Install thatch globally:**
35
+ Install globally, then run setup in your project:
58
36
 
59
37
  ```bash
60
38
  npm install -g @jeffober/thatch
61
- ```
62
-
63
- This puts the `thatch` binary on your PATH. It requires [Bun] to be installed
64
- (`curl -fsSL https://bun.sh/install | bash` if you don't have it).
65
-
66
- **Set up Claude Code in your project:**
67
-
68
- ```bash
69
39
  cd /path/to/your/project
70
- thatch setup --claude
71
- ```
72
-
73
- `setup` does four things:
74
- 1. Writes `.mcp.json` — registers the MCP server (Claude Code spawns `thatch mcp` as a stdio process)
75
- 2. Appends instructions to `CLAUDE.md` — session startup, when to write, what to store
76
- 3. Installs hooks in `.claude/settings.json` — `SessionStart` runs `thatch reminder` (recall nudge + hygiene), `PostToolBatch` feeds the extraction queue, `UserPromptSubmit` peeks the queue and nudges you to save new knowledge
77
- 4. Installs skill files to `~/.claude/skills/` — memory workflow skills (project primer, fact extractor, dedup classifier, session reflection), code review skills (6 review specialists + synthesizer + context + workflow research), walkthrough skills, and writing skills. See [Skills](#skills) below.
78
-
79
- Restart Claude Code and thatch's tools are available as `mcp__thatch__*`.
40
+ thatch setup --claude # or --cursor
80
41
 
81
- **Global setup** (all projects at once, no per-project config):
82
-
83
- ```bash
84
- thatch setup --claude --global
42
+ # set up in your global config for all projects
43
+ thatch setup --claude --global # or --cursor --global
85
44
  ```
86
45
 
87
- This writes to `~/.claude/CLAUDE.md` and `~/.claude/settings.json`, then prints
88
- the `claude mcp add` command to register the MCP server at user scope.
89
-
90
- **Local development** (from a thatch repo checkout):
91
-
92
- ```bash
93
- cd /path/to/thatch
94
- bun run bin/thatch setup --claude
95
- ```
96
-
97
- When `thatch` is not on PATH, setup uses the absolute path to `bin/thatch` in
98
- the hooks and MCP config. When it is on PATH (npm global install), setup uses
99
- the bare `thatch` command so the config survives updates.
46
+ `setup` installs the MCP server config, hooks, instructions, and skills.
47
+ Restart your editor and thatch's tools are available as `mcp__thatch__*`.
48
+ Requires [Bun] on PATH.
100
49
 
101
50
  ### Other MCP-compatible harnesses
102
51
 
103
- Thatch works as a `stdio` MCP server with any MCP client. Register it in your
104
- harness's MCP config by pointing to the `thatch` binary:
105
-
106
52
  ```json
107
53
  {
108
54
  "mcpServers": {
109
- "thatch": {
110
- "command": "thatch",
111
- "args": ["mcp"]
112
- }
55
+ "thatch": { "command": "thatch", "args": ["mcp"] }
113
56
  }
114
57
  }
115
58
  ```
116
59
 
117
- No `setup` step is needed for bare MCP usage; `setup` installs hooks and
118
- instructions specific to Claude Code and Cursor. For other harnesses, add the
119
- MCP server config above and include thatch's tools/instructions in your agent's
120
- system prompt manually (see [docs/dev/mcp-parity.md](docs/dev/mcp-parity.md)
121
- for the prompt text). [Bun] must be on PATH.
122
-
123
- ## Tools
124
-
125
- | Tool (opencode) | Tool (MCP) | What it does |
126
- |------------------|------------|-------------|
127
- | `thatch_memory_remember` | `mcp__thatch__memory_remember` | Save a memory with an embedding for later recall |
128
- | `thatch_memory_recall` | `mcp__thatch__memory_recall` | Semantic search across project + global stores |
129
- | `thatch_memory_list` | `mcp__thatch__memory_list` | List labels and metadata in a store |
130
- | `thatch_memory_show` | `mcp__thatch__memory_show` | Read full content by exact label |
131
- | `thatch_memory_forget` | `mcp__thatch__memory_forget` | Delete a memory |
132
- | `thatch_store_list` | `mcp__thatch__store_list` | List all stores |
133
- | `thatch_find_duplicates` | `mcp__thatch__find_duplicates` | Surface pairs of suspiciously similar memories |
134
- | `thatch_dedup_mark_checked` | `mcp__thatch__dedup_mark_checked` | Record a reviewed pair so it stops being re-reported |
135
- | `thatch_extraction_done` | `mcp__thatch__extraction_done` | Acknowledge extraction nudge was dispatched to a sub-agent; drains the buffer |
136
- | `thatch_prediction_query` | `mcp__thatch__prediction_query` | Query the user decision model for scored predictions matching a context |
137
- | `thatch_prediction_update` | `mcp__thatch__prediction_update` | Create, reinforce, or weaken a prediction about user preferences |
138
- | `thatch_prediction_list` | `mcp__thatch__prediction_list` | List all predictions with matchers, confidence, evidence, and provenance |
139
- | `thatch_prediction_delete` | `mcp__thatch__prediction_delete` | Delete a prediction created in error (cascades to edges and provenance) |
140
-
141
- ## Prediction engine
142
-
143
- Thatch maintains a statistical model of the user's decision-making preferences.
144
- When the user sends a prompt, the engine embeds it (sharing the embedding
145
- already computed for memory recall) and searches for **matchers** — context
146
- patterns that describe situations where the user has expressed preferences.
147
- Matching matchers fire linked **predictions** (scored by cosine similarity,
148
- edge weight, and Bayesian confidence), and a nudge is injected alongside the
149
- recall nudge:
150
-
151
- ```text
152
- [thatch] User decision model
153
- - [0.72 conf, 4 tests] When X: you tend to Y
154
- - [0.50 conf, 0 tests] When Z: you may prefer W
155
- ```
156
-
157
- The nudge is descriptive, not directive. The system prompt instructions tell
158
- the agent to follow strong predictions, surface uncertainty when confidence is
159
- thin, and update the model when the user responds. Predictions use a Bayesian
160
- posterior with a Beta prior (K=5, P0=0.5); signals are `confirm`,
161
- `disconfirm`, `soft` (weak disconfirm, weight 0.25), and `create`.
162
-
163
- The MCP path (Claude Code, Cursor) fires predictions via the same sideband
164
- socket used for recall nudges. The `flush-predictions` CLI subcommand provides
165
- standalone prediction-only output for testing.
166
-
167
- ## Skills
168
-
169
- Thatch ships skills that encode operational methodology — practices your
170
- agent follows to maintain its own memory and review code systematically.
171
-
172
- ### Memory workflows
173
-
174
- | Skill | What it does |
175
- |-------|-------------|
176
- | `thatch-project-primer` | Bootstrap a project's memory store by investigating the codebase and writing foundational memories |
177
- | `thatch-fact-extractor` | Extract durable facts from recent tool interactions and persist them to memory |
178
- | `thatch-dedup-classifier` | Classify and consolidate similar memories surfaced by `thatch_find_duplicates` |
179
- | `thatch-session-reflection` | Record what was learned during a session — project facts, user preferences, tool tips |
180
-
181
- ### Code review
182
-
183
- | Skill | What it does |
184
- |-------|-------------|
185
- | `thatch-review-pedantic` | Mechanical correctness — spelling, naming, doc accuracy, specs, stale artifacts |
186
- | `thatch-review-acceptance` | Behavioral and product review — UX coherency, behavioral delta, integration effects |
187
- | `thatch-review-state-flow` | Data flow and contracts — module boundaries, implicit state machines, error propagation |
188
- | `thatch-review-no-slop` | AI writing anti-pattern detection — change narration, fourth wall breaks, hedging |
189
- | `thatch-review-breadcrumbs` | Comment narrative — do comments form a coherent outline of the code's behavior? |
190
- | `thatch-review-mark-and-sweep` | Mechanical change completeness — whole-repo sweep for stragglers after renames, flag removals, API substitutions |
191
- | `thatch-review-synthesizer` | Verify specialist findings against actual code, deduplicate, produce severity-grouped report |
192
- | `thatch-review-context` | Gather project/feature context (PRs, tickets, TODOs, deferred work) before a review |
193
- | `thatch-workflow-research` | Research code workflows affected by a change or planned change, before reviewing or planning |
194
- | `thatch-change-walkthrough` | Explain a change as a teaching walkthrough with file:line citations |
195
- | `thatch-code-walkthrough` | Explain a feature, module, or workflow as a teaching walkthrough; also drafts high-level docs |
196
-
197
- ### Writing
198
-
199
- | Skill | What it does |
200
- |-------|-------------|
201
- | `pr-description` | Draft PR descriptions using instructional-design scaffolding with bold/italic emphasis for scanning |
202
- | `ticket-description` | Draft ticket or issue descriptions (Linear or Jira) with instructional-design scaffolding |
203
- | `split-overlarge-pr` | Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs |
204
-
205
- ### opencode-only
206
-
207
- | Skill | What it does |
208
- |-------|-------------|
209
- | `thatch-code-review` | Multi-agent review coordinator — triage, partition, dispatch specialists in parallel |
210
-
211
- The six review specialists run independently and can be used standalone. The
212
- synthesizer verifies their findings against the actual code — reading each
213
- cited location to confirm the evidence matches — before producing a final
214
- report. The coordinator (opencode only) orchestrates the full pipeline by
215
- dispatching specialist sub-agents in parallel.
216
-
217
- ## CLI
218
-
219
- The `thatch` CLI ships with the package (installed to your npm global bin by
220
- `npm install -g`). It requires [Bun] on your PATH — the bin script uses
221
- `#!/usr/bin/env bun` and all internal modules depend on `bun:sqlite`.
222
-
223
- ```bash
224
- thatch stores List all stores
225
- thatch list [store] List memory labels in a store
226
- thatch show <label> [store] Display a memory by label
227
- thatch forget <label> [store] Remove a memory by label
228
- thatch search <query> [store] Semantic search (cosine similarity)
229
- thatch prime Prime project memory (runs via opencode, Cursor, or claude)
230
- thatch mcp Start the stdio MCP server (for Claude Code and Cursor)
231
- thatch reminder [--json] Print session-start reminder (for hooks)
232
- thatch hygiene Print the hygiene report (standalone)
233
- thatch buffer-batch Append Claude Code PostToolBatch output to extraction queue
234
- thatch buffer-tool Append Cursor postToolUse output to extraction queue
235
- thatch flush-tools [--json] Peek extraction queue; print extraction + recall nudges
236
- thatch flush-predictions [--json] Query predictions for the prompt (hook or standalone)
237
- thatch setup --claude [--cursor] [--global] Install config + instructions + hooks + skills
238
- ```
239
-
240
- Stores default to the repo detected from `git remote`. Use `global` for the
241
- global store. Use `all` with `search` to search project + global together.
60
+ Include thatch's instructions in your agent's system prompt manually; see
61
+ [docs/dev/mcp-parity.md](docs/dev/mcp-parity.md) for the prompt text.
242
62
 
243
- ### Priming a new project
63
+ ## What's inside
244
64
 
245
- `thatch prime` bootstraps your project's memory store by having the agent
246
- investigate the codebase and write foundational memories:
65
+ - **Memory tools**: save, search, list, show, and forget memories with
66
+ semantic search (local embeddings, SQLite, brute-force cosine).
67
+ - **Prediction engine**: a statistical model of user decision-making
68
+ preferences. When a prompt matches learned contexts, predictions fire
69
+ alongside the recall nudge.
70
+ - **Skills**: 20 skills for memory workflows, structured multi-specialist
71
+ code review, change walkthroughs, and writing tasks (PR descriptions,
72
+ tickets, PR splitting).
247
73
 
248
- ```bash
249
- cd /path/to/your/project
250
- thatch prime
251
- ```
252
-
253
- This detects `opencode`, Cursor, or `claude` on your PATH and runs the
254
- `thatch-project-primer` skill, which guides the agent to:
255
-
256
- 1. Recall any existing project memories
257
- 2. Investigate docs, layout, architecture, commands, and conventions
258
- 3. Write focused memories with clear labels
259
- 4. Reconcile contradictions with existing knowledge
260
- 5. Run dedup to check for overlap
261
-
262
- After priming, your agent has context about the project's purpose, structure,
263
- tech stack, development commands, and conventions — reducing the need to
264
- re-research these topics in future sessions.
265
-
266
- ## How it works
267
-
268
- Thatch auto-detects your repo identity from `git remote get-url origin`
269
- (e.g., `sysread/thatch`). Memories are embedded with
270
- [bge-small-en-v1.5][bge] (384-dimensional vectors, ~34 MB model, cached
271
- locally) and stored in `~/.config/thatch/thatch.db` (SQLite, WAL mode).
272
- Search is brute-force cosine similarity — fast enough for thousands of entries.
273
-
274
- ### Memory capture
275
-
276
- Thatch doesn't call an LLM to extract facts. Instead, it buffers recent tool
277
- interactions and nudges the host agent to persist durable knowledge itself,
278
- using the `thatch-fact-extractor` skill. The agent's own model decides what's
279
- worth remembering — keeping thatch dependency-free and the agent in control.
280
- On OpenCode, the plugin hooks `tool.execute.after` and `chat.message` to
281
- buffer and peek (the buffer persists until the agent writes a memory). On
282
- Claude Code, `PostToolBatch` and `UserPromptSubmit` hooks drive a file-backed
283
- queue with the same peek-not-drain semantics. Both paths produce the same
284
- payload for the fact-extractor skill.
285
-
286
- ## OpenCode vs Claude Code vs Cursor parity
287
-
288
- | Feature | OpenCode (plugin) | Claude Code (MCP + hooks) | Cursor (MCP + hooks) |
289
- |---------|-------------------|--------------------------|---------------------|
290
- | Tools | Plugin tool registration | MCP `tools/list` + `tools/call` | MCP `tools/list` + `tools/call` |
291
- | System prompt | Injected at runtime with repo name | Static CLAUDE.md (repo auto-detected by MCP server) | Static AGENTS.md (repo auto-detected at startup) |
292
- | Session-start reminder | `session.created` event | `SessionStart` hook → `thatch reminder` | `sessionStart` hook → `thatch reminder --json` |
293
- | Compaction context | `experimental.session.compacting` hook | **Gap**: no equivalent (CLAUDE.md persists) | **Gap**: no equivalent |
294
- | Extraction nudge | `tool.execute.after` + `chat.message` | `PostToolBatch` + `UserPromptSubmit` (file-backed queue) | `postToolUse` + `beforeSubmitPrompt` (file-backed queue) |
295
- | Prediction auto-fire | `chat.message` hook, separate try/catch from recall | `flush-tools` tier 2 (sideband socket) | `flush-tools` tier 2 (sideband socket) |
296
- | Setup detection at startup | n/a (plugin auto-installs) | `checkSetup` in MCP server: detects missing/broken instructions | Same as Claude Code |
297
- | Skills | 19 (18 shared + coordinator) | 18 (shared only) | 18 (shared only) |
298
- | Store detection | `worktree` param from plugin | `CLAUDE_PROJECT_DIR` env var | `CURSOR_PROJECT_DIR` then `CLAUDE_PROJECT_DIR` |
299
-
300
- See [docs/dev/mcp-parity.md](docs/dev/mcp-parity.md) for the full analysis.
74
+ See the [user guide](docs/user/README.md) for the full tool list, CLI
75
+ commands, configuration, environment variables, and detailed setup for each
76
+ host.
301
77
 
302
78
  ## Privacy
303
79
 
304
80
  Everything is local. The embedding model downloads once from Hugging Face Hub
305
81
  and is cached. No data leaves your machine.
306
82
 
307
- ## Docs
308
-
309
- - [User guide](docs/user/README.md) — setup, tools, configuration
310
- - [Development](docs/dev/README.md) — architecture, module responsibilities, data flow
311
- - [MCP parity](docs/dev/mcp-parity.md) — OpenCode plugin vs Claude Code MCP feature comparison
312
- - [QA & tests](docs/qa/README.md) — test conventions, categories, use case format
313
- - [Plans](docs/plans/) — numbered design documents capturing decisions
314
-
315
83
  ## Development
316
84
 
317
85
  ```bash
318
- bun install # deps
319
- bun test # full suite: zero network, zero external deps
320
- bun test --watch # watch mode
86
+ bun install
321
87
  mise run check # typecheck + bun test + markdownlint (the CI gate)
322
88
  ```
323
89
 
324
90
  Tests never reach outside the sandbox: temp-directory SQLite files, mock
325
- embeddings, no network. `mise run check` is the full quality gate; `mise run
326
- typecheck` or `mise run lint-md` run those alone.
91
+ embeddings, no network.
92
+
93
+ ## Docs
94
+
95
+ - [User guide](docs/user/README.md) -- setup, tools, configuration, CLI
96
+ - [Development](docs/dev/README.md) -- architecture, module responsibilities
97
+ - [MCP parity](docs/dev/mcp-parity.md) -- OpenCode plugin vs MCP feature comparison
98
+ - [QA & tests](docs/qa/README.md) -- test conventions, use cases
99
+ - [Design docs](docs/in-progress/) -- in-progress design notes
327
100
 
328
101
  ## License
329
102
 
330
103
  MIT
331
104
 
332
105
  [Bun]: https://bun.sh
333
- [bge]: https://huggingface.co/BAAI/bge-small-en-v1.5
@@ -1,25 +1,35 @@
1
1
  ---
2
2
  name: pr-description
3
- description: Draft a PR description using instructional-design scaffolding (SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES) with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story. Use when the user asks you to write, draft, or update a PR description or PR body, or when running `gh pr create` and no body has been supplied. Do NOT use for commit messages, release notes, or changelog entries.
3
+ description: Draft a PR description (SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES) with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story. Use when the user asks you to write, draft, or update a PR description or PR body, or when running `gh pr create` and no body has been supplied. Do NOT use for commit messages, release notes, or changelog entries.
4
4
  ---
5
5
 
6
6
  # Writing PR descriptions
7
7
 
8
+ ## Core principle
9
+
10
+ Write for humans. Not for LLMs. Not to impress. Not to pad.
11
+
12
+ Every sentence earns its place or gets cut. Plain English over jargon. Concrete over abstract. Short over long. A description a human reads and understands beats one that looks thorough but says nothing.
13
+
14
+ If a word does not help a human understand the diff, it is dead weight. If a sentence restates the previous one, one is redundant. If a phrase sounds smart but you cannot explain it in simpler words, it is a buzzword. Cut, replace, or simplify.
15
+
16
+ Target a 7th-grade reading level. Not because the reader is dumb, but because plain prose is faster to read and harder to misread. Short sentences, common words, one idea each. The concepts stay technical; the language stays simple.
17
+
8
18
  ## The reader
9
19
 
10
20
  You are writing for a senior engineer who knows the tech stack and general engineering vocabulary but has never touched this feature, subsystem, or branch. They may not know subsystem-specific jargon or acronyms: a crypto term like DEK, an auth term like the SAML assertion, a scanning term like a ScanRun, a results term like the frozen materialized view. Their goal is to review the diff. Your goal is to raise their baseline understanding just enough that the diff becomes self-explanatory, without making them check out the branch or open a design doc.
11
21
 
12
- The description is not a design doc, changelog, or implementation journal. It is a scaffold that front-loads the context the reviewer needs, didactically layered so they absorb it in the order that makes the diff land.
22
+ The description is not a design doc, changelog, or implementation journal. It is a short, structured brief that gives the reviewer the context they need, in the order that makes the diff make sense.
13
23
 
14
- This is **instructional design**, not documentation. Each section has a cognitive goal for the reader:
24
+ Each section has one job:
15
25
  - SYNOPSIS: orient to the class of change and affected area.
16
26
  - PURPOSE: make the reader agree there is a problem worth solving.
17
27
  - DESCRIPTION: teach the system's current behavior and how this change alters it.
18
- - WALK-THROUGH (when needed): walk the reviewer through the changed workflow step by step.
28
+ - WALK-THROUGH (when needed): walk the reviewer through the new workflow step by step.
19
29
  - NOTES: flag scope limits, intentional regressions, and things AI reviewers will misread.
20
30
  - robots.txt (when needed): dense, machine-addressed context that heads off recurring false positives from automated reviewers.
21
31
 
22
- Layer the knowledge so each section builds on the previous one. The reader should never encounter a concept in layer N that was not introduced in layer N-1.
32
+ Each section builds on the previous one. The reader should never encounter a concept in section N that was not introduced in section N-1.
23
33
 
24
34
  AI-authored PRs tend to be large. The description is the reader's lever against that: a good one lets them say "small description, easy to scan" and then read the code critically. A bad one makes them skip the description, wade through the diff cold, and miss intent.
25
35
 
@@ -29,13 +39,13 @@ Sections, in order: SYNOPSIS, PURPOSE, DESCRIPTION, WALK-THROUGH (conditional),
29
39
 
30
40
  **SYNOPSIS, PURPOSE, and DESCRIPTION are mandatory** - even for a one-line, single-concern change. A tiny PR gets short sections, not fewer sections. WALK-THROUGH and NOTES appear only when warranted; omit them when empty. robots.txt appears only after an automated reviewer has produced a false positive worth heading off (see its section); it is always the final section.
31
41
 
32
- **Scale the body to the diff's conceptual size**, not its structure's capacity. A 2-file, single-concern change (add a flag, guard a branch, rename a symbol, bump a constant) is a few lines per section. SYNOPSIS one line, PURPOSE one to three, DESCRIPTION one short paragraph, NOTES if needed. The layered DESCRIPTION machinery below is for changes with real before/after mechanics to teach; when the diff is self-evident once you know the intent, collapse it. If your draft for a small change runs past ~15 lines of body, you are padding. Cut until each remaining line earns its place. Most of this skill's apparatus exists to tame large PRs; applying it wholesale to a small one produces exactly the bloat the skill warns against.
42
+ **Scale the body to the diff's conceptual size**, not its structure's capacity. A 2-file, single-concern change (add a flag, guard a branch, rename a symbol, bump a constant) is a few lines per section. SYNOPSIS one line, PURPOSE one to three, DESCRIPTION one short paragraph, NOTES if needed. The layered DESCRIPTION machinery below is for changes with real before/after mechanics to teach; when the diff is self-evident once you know the intent, collapse it. If your draft for a small change runs past ~15 lines of body, you are padding. Cut until each remaining line earns its place. Most of this skill's guidance exists to tame large PRs; applying it wholesale to a small one produces exactly the bloat the skill warns against.
33
43
 
34
44
  ### SYNOPSIS
35
45
 
36
46
  One to two lines. Orient only. The reader should come away knowing the class of change (bugfix, refactor, feature, revert, infra, cleanup) and the affected area.
37
47
 
38
- SYNOPSIS may use subsystem-specific terms as scan anchors (that is its job). It does not define them. The first teaching section (PURPOSE or DESCRIPTION) picks up that burden. An outsider who does not know the terms should still be able to orient from the plain-English nouns around them.
48
+ SYNOPSIS may use subsystem-specific terms as scan anchors (that is its job). It does not define them. The first teaching section (PURPOSE or DESCRIPTION) picks up that burden. An outsider who does not know the terms should still be able to orient from the plain-English nouns around them. Do not force all project context into SYNOPSIS; it is a TLDR, not the teaching section.
39
49
 
40
50
  Include a ticket link if one exists. Format: `Ticket: [PLAT-139](https://<host>/browse/PLAT-139)` on its own line directly under the SYNOPSIS text.
41
51
 
@@ -77,9 +87,9 @@ How much structure DESCRIPTION needs depends on the change's conceptual size.
77
87
  2. **What this PR changes.** For each decision point named in layer 1, say what it does now. Keep parallelism: same names, same order. The reader's mental model from layer 1 is the load-bearing structure here.
78
88
  3. **Why that fixes PURPOSE.** One or two sentences linking the mechanics in layer 2 to the harm named in PURPOSE. If the fix has limits (doesn't cover case Z, follow-up needed), call them out here in one line.
79
89
 
80
- The didactic spine: PURPOSE names a harm, layer 1 names the mechanism, layer 2 changes the mechanism, layer 3 shows the harm is gone. Names carry through. The reader builds one model, not four.
90
+ The structure is simple: PURPOSE names a harm, layer 1 names the mechanism, layer 2 changes the mechanism, layer 3 shows the harm is gone. Names carry through. The reader builds one model, not four.
81
91
 
82
- **Large change with a workflow or lifecycle**: keep DESCRIPTION to root-cause and design concept only (what is wrong, what is the approach). Use a separate WALK-THROUGH section for the step-by-step mechanics.
92
+ **Large change with a workflow or lifecycle**: keep DESCRIPTION to root-cause and design concept only (what is wrong, what is the approach). Use a separate WALK-THROUGH section for the step-by-step mechanics of the new flow.
83
93
 
84
94
  Organize by **workflow or data-flow**, not by touched symbol. A bullet list of API changes reads as disconnected touchpoints. A walkthrough following one object through the system reads as a story. If the change touches a request lifecycle, follow the request. If it touches a data pipeline, follow the data.
85
95
 
@@ -87,22 +97,44 @@ Organize by **workflow or data-flow**, not by touched symbol. A bullet list of A
87
97
 
88
98
  When the change has a sequence of steps - a lifecycle, a workflow, a data flow through the system - split the mechanics into a numbered WALK-THROUGH. Keep DESCRIPTION to root-cause + design concept only.
89
99
 
90
- Default to a numbered outline. A flat list of steps, with an occasional inline branch ("if the path is not in the registry, return a 404; otherwise continue to step 6"), covers almost every workflow. The bar for a diagram or Mermaid chart is high: reach for one only when the flow genuinely needs two dimensions to read - a graph network with many nodes and edges, or a workflow that recurses, forks, and rejoins in ways a linear outline cannot follow without constant back-references. If the flow is one or two levels deep and does not recurse or redirect, an outline is clearer and cheaper to maintain than a diagram.
100
+ Each numbered step describes the **existing behavior** at that stage of the workflow - what the reviewer already knows or can see in the current code. A sub-bullet below it describes what this PR changes, prefixed with **NOW**. For stages that are entirely new (no existing behavior to describe), use `N/A` as the numbered step.
91
101
 
92
- Each numbered step states what changed at that stage of the workflow. Bold the **key phrase** that identifies the step (the scan anchor). The rest of the step is plain prose.
102
+ This before/now pattern lets the reviewer anchor on what they already understand, then see the delta right below it. They never have to reconstruct the current state from inversions.
103
+
104
+ If the PR changes more than one workflow, split WALK-THROUGH into one subheading per workflow. Do not force unrelated processes into one numbered list. Each workflow gets its own 3-6 step before/now list. Keep subheads concrete: `### Request validation`, `### Background retry`, `### Finalization`, not `### Backend changes`.
93
105
 
94
106
  Format:
95
107
 
96
- 1. **Request enters the handler** - the new guard checks the tenant scope before dispatching.
97
- 2. **Validation runs** - the validator now rejects empty payloads that previously passed through.
98
- 3. **Database write** - the write happens inside the transaction boundary, not after it.
108
+ ```md
109
+ ### Workflow name
110
+
111
+ 1. **Existing behavior at this stage** - one sentence describing how the code works today.
112
+ - **NOW** - _what this PR changes about this stage._
113
+
114
+ 2. **N/A**
115
+ - **NOW** - _a new stage that did not exist before._
116
+ ```
117
+
118
+ Default to a numbered outline. A flat list of steps, with an occasional inline branch ("if the path is not in the registry, return a 404; otherwise continue to step 6"), covers almost every workflow. The bar for a diagram or Mermaid chart is high: reach for one only when the flow genuinely needs two dimensions to read - a graph network with many nodes and edges, or a workflow that recurses, forks, and rejoins in ways a linear outline cannot follow without constant back-references. If the flow is one or two levels deep and does not recurse or redirect, an outline is clearer and cheaper to maintain than a diagram.
119
+
120
+ Bold the **key phrase** that identifies each step (the scan anchor). The rest is plain prose. Italicize the NOW sub-bullet content so it visually separates from the numbered step above it.
99
121
 
100
122
  Rules:
123
+ - Aim for 3-6 steps. If you have more, you are over-decomposing. Group related stages into one step. A step is a phase the reviewer can hold in their head, not a single function call.
124
+ - The numbered step is one sentence describing existing behavior. The NOW sub-bullet is one sentence describing the change. If either needs two sentences, the step is doing too much; split the concept differently or move detail to DESCRIPTION.
101
125
  - One step per workflow stage, in execution order.
102
- - State what changed, not what you did. "The handler now checks tenant scope" not "I added a tenant scope check."
126
+ - No blank line between the numbered step and its NOW sub-bullet. GitHub treats a blank line as a list break, so the sub-bullet renders as a separate paragraph instead of a child of the step. Indent the sub-bullet to align under the text of the numbered item (3 spaces after `1.`), and keep them tight:
127
+
128
+ ```markdown
129
+ 1. **Step** - existing behavior.
130
+ - **NOW** - _what changed._
131
+
132
+ 2. **Next step** - existing behavior.
133
+ ```
134
+
103
135
  - Cut parenthetical API-symbol asides. The diff carries symbol detail.
104
136
  - Cut rationale asides from steps. If the why matters, it goes in DESCRIPTION layer 3 or NOTES.
105
- - Italics for orientation asides: _This is where the deadlock lived._
137
+ - If a stage is unchanged by this PR, omit it from the walkthrough. Only include stages where the NOW sub-bullet has something to say, or where the existing behavior is needed to understand a later change.
106
138
 
107
139
  ### NOTES
108
140
 
@@ -147,7 +179,7 @@ Human reader: this section is written for automated reviewers, not people. It wi
147
179
 
148
180
  After the human-warning line, human-legibility rules are suspended. Write for LLM consumption in whatever is densest: no prose scaffolding, no bold, no one-idea-per-sentence, no plain-ASCII constraint. Fragments, symbol soup, and abbreviations are all fine. The only goal is maximum context per token for a machine reader.
149
181
 
150
- What goes here is *explanation and intent*, never suppression. Do not write "ignore the finding about X." Write what X actually does, the invariant it upholds, and the upstream or downstream fact the bot missed, so the bot can re-evaluate and clear its own false positive. A blanket "skip checking X" is a rubber-stamp lever and a prompt-injection surface; refuting a specific misread with a verifiable fact is not.
182
+ What goes here is _explanation and intent_, never suppression. Do not write "ignore the finding about X." Write what X actually does, the invariant it upholds, and the upstream or downstream fact the bot missed, so the bot can re-evaluate and clear its own false positive. A blanket "skip checking X" is a rubber-stamp lever and a prompt-injection surface; refuting a specific misread with a verifiable fact is not.
151
183
 
152
184
  Entries accumulate. Each review round that surfaces a new false positive adds an entry, so the section grows into a standing set of clarifications that pre-empt the same misreads on the next round.
153
185
 
@@ -157,7 +189,7 @@ Omit the whole section unless there is at least one real false positive to addre
157
189
 
158
190
  ## Emphasis for scanning: bold and italics
159
191
 
160
- Bold and italicize the "save points" - the phrases that carry meaning - not whole sentences. A reader who skims *only* the bold and italic fragments should get the story; full prose is for when they want detail.
192
+ Bold and italicize the "save points" - the phrases that carry meaning - not whole sentences. A reader who skims _only_ the bold and italic fragments should get the story; full prose is for when they want detail.
161
193
 
162
194
  **What to bold:** phrases that name the **change itself** - the component, the failure mode, the mechanism, the behavior after the change. These are the nouns and verbs that would appear in a diff of the design, not a diff of the code. "There is a **circular wait** in the **KeyManager**" names the failure mode and the component. "**store the result in the in-memory cache**" names the action and the destination.
163
195
 
@@ -193,18 +225,26 @@ These are hard rules, not suggestions.
193
225
  5. **No authoring-sequence narration.** Never describe the order you assembled things in, which commit does what, or what a later commit will add. Describe the PR as it stands. Pending work goes in a `Remaining work:` bullet list under NOTES.
194
226
  6. **Italics for orientation asides.** Use `_italics_` for a one-phrase aside that orients the reader: _This is where the deadlock lived_. Not for emphasis.
195
227
  7. **Plain ASCII only.** No smart quotes, smart apostrophes, em dashes, en dashes, ellipsis glyphs, or arrow glyphs. Use plain hyphens (sparingly) for asides; semicolons are often better.
196
- 8. **No buzzwordy abstractions.** If a phrase sounds like it is trying to sound smart, cut or replace it. Name the code and behavior directly. "identity contract" -> "the struct field that identifies the owner". "canonical hash" -> "the SHA-256 we compute on ingestion".
197
- 9. **Avoid loaded language.** Use neutral, current terminology unless the repo's established name is different. Prefer allowlist/blocklist over whitelist/blacklist, primary/replica over master/slave, and precise role names over moralized labels like "bad" or "evil".
198
- 10. **No parenthetical API-symbol asides in WALK-THROUGH steps.** The diff carries symbol detail. If the reader needs the function name, they will find it in the diff.
228
+ 8. **No buzzwordy abstractions.** If a phrase sounds like it is trying to sound smart, cut or replace it. Name the code and behavior directly. "identity contract" -> "the struct field that identifies the owner". "canonical hash" -> "the SHA-256 we compute on ingestion". "shared seam" -> "shared helper" or "boundary" depending on what is meant. "leverage" -> "use". "utilize" -> "use". "facilitate" -> "help". If you cannot say what a phrase means in plain English, it does not belong. Buzzwords are the number-one signal that an AI wrote the description; do not send that signal.
229
+ 9. **Translate project-private labels.** If a phrase only makes sense to people already working on this project, replace it or explain it before using the label. This includes roadmap names, subsystem nicknames, architecture slogans, ticket shorthand, internal stack names, and labels invented by the current branch. Name the behavior first: what reads, writes, blocks, retries, ignores, repairs, or changes. The reader should understand the sentence before they learn the nickname.
230
+ 10. **Prefer concrete terms over ambiguous ones.** If a word can mean more than one thing in this PR, qualify it or replace it with the concrete behavior. Do not rely on the reader guessing the local meaning. Ordinary words can be ambiguous when the code gives them a special role: claim, owner, active, current, generation, repair, coalesce, terminal, source, scope, sync, publish, resolve. "Publish the value" is vague. "Persist the value in the database so the UI can display it" is concrete.
231
+ 11. **Clarity wins over compression.** Brevity means fewer claims, not denser claims. If a sentence needs hidden facts to make sense, split it. Keep the connective tissue that makes the idea parse on first read; cut a less important claim instead. Do not compress a missing explanation into a noun stack.
232
+ 12. **Explain operations before naming them.** Process words like refresh, repair, coalesce, project, projection, reconcile, classify, normalize, aggregate, route, resolve, hydrate, and fan out are not explanations by themselves. Name the object, the action, and the effect. "The cache refreshes in the background" is vague. "The worker waits up to 5 seconds, then reloads each stale cache key once" is clear. "Projection" is vague unless the sentence says what input is read and what output is computed or stored.
233
+ 13. **Do not inherit code wording blindly.** Code comments, function names, metrics labels, and existing PR text often use shorthand for people already in the area. Treat that wording as a clue, not prose to copy. If the code says "coalesce", the description may need "waits up to 5 seconds, then runs once for all requests seen during that window". Prefer the clearest reader-facing behavior over the code's nickname.
234
+ 14. **Name both sides of a contrast.** If the PR changes timing, ownership, source of truth, error handling, or ordering, state the old behavior and the new behavior close together. "Retries are synchronous now" is not enough. "The handler used to return before retrying failed webhook deliveries. It now retries once before returning, so callers see the final delivery result" gives the reader a reference point.
235
+ 15. **Show causal links.** If a sentence uses "so", "because", "therefore", "prevents", or "allows", make the middle step visible. "The importer uses stable IDs, so duplicate rows do not inflate counts" hides the mechanism. "Some rows arrive with both a display name and a stable ID. The importer counts the stable ID first and ignores the duplicate display-name row, so one item stays one count" explains the cause.
236
+ 16. **Avoid loaded language.** Use neutral, current terminology unless the repo's established name is different. Prefer allowlist/blocklist over whitelist/blacklist, primary/replica over master/slave, and precise role names over moralized labels like "bad" or "evil".
237
+ 17. **No parenthetical API-symbol asides in WALK-THROUGH steps.** The diff carries symbol detail. If the reader needs the function name, they will find it in the diff.
199
238
 
200
239
  ## Length and style
201
240
 
202
- Target: the reader can take in the whole description in under 60 seconds. Err on the shorter side.
241
+ Target for most PRs: the reader can take in the whole description in under 60 seconds. Err on the shorter side.
203
242
 
204
243
  Scale the body to the diff's conceptual size:
205
244
  - Trivial 2-file change: ~15-line ceiling. SYNOPSIS one line, PURPOSE one to three, DESCRIPTION one short paragraph, NOTES if needed.
206
245
  - Moderate refactor: one tight paragraph or bullet set per section.
207
- - Large change with WALK-THROUGH: as long as the walkthrough needs, but no longer. Each step earns its place.
246
+ - Large change with WALK-THROUGH: as long as the flow needs, but no longer. Aim for 3-6 steps; more means you are over-decomposing. Each step earns its place.
247
+ - Enormous PR: accept that the reader may need more than 60 seconds. Keep the same rules, but spend the extra words on context, concrete behavior, and reviewer safety. Do not chase a tiny body by compressing meaning.
208
248
 
209
249
  If your draft for a small change runs past ~15 lines of body, you are padding. Cut until each remaining line earns its place.
210
250
 
@@ -234,6 +274,23 @@ Do not turn this into a code-review checklist. The PR description does not need
234
274
 
235
275
  When there is no ticket, skip this step. The rest of the process works the same; PURPOSE is seeded from the diff and commit messages instead.
236
276
 
277
+ ## Project context for stacked work
278
+
279
+ Some PRs are slices of a larger project. The diff alone may not explain the project terms it uses. Before drafting, read enough context to define those terms correctly.
280
+
281
+ Read project context when the PR body, ticket, branch name, commit messages, code comments, or diff mentions:
282
+ - a related PR, parent PR, follow-up PR, or stacked branch;
283
+ - a deferred piece of the design;
284
+ - an upstream dependency;
285
+ - a project-specific term whose local meaning is not obvious from the diff;
286
+ - a roadmap label, subsystem nickname, architecture slogan, or branch-local name.
287
+
288
+ Use available source material: linked tickets, linked PRs, nearby docs, code comments, commit messages, and project memory. Build a private term map: term -> plain behavior -> source. Do not dump the map into the PR description. Use it to write the shortest useful explanation.
289
+
290
+ If a term controls the reader's understanding of the PR and you cannot resolve it from available context, stop and ask the user. Do not guess. Do not write around the missing definition with vaguer words.
291
+
292
+ Do not add a `## CONTEXT` section by default. Put a one- or two-sentence context bridge in PURPOSE or DESCRIPTION only when the reviewer needs it to understand this PR's delta.
293
+
237
294
  ## Link verification
238
295
 
239
296
  Before posting or updating a PR body, verify every link you can. Broken links in PR descriptions waste reviewer time and make the surrounding prose less trustworthy.
@@ -268,48 +325,61 @@ One line each. Fold into NOTES as bullets.
268
325
 
269
326
  ### Small change (collapsed DESCRIPTION)
270
327
 
271
- ## SYNOPSIS
272
- Narrow the **rotation advisory lock** to DB writes only; release across KMS I/O.
328
+ ```md
329
+ ## SYNOPSIS
330
+ Narrow the **rotation advisory lock** to DB writes only; release across KMS I/O.
273
331
 
274
- Ticket: [PLAT-412](https://example.atlassian.net/browse/PLAT-412)
332
+ Ticket: [PLAT-412](https://example.atlassian.net/browse/PLAT-412)
275
333
 
276
- ## PURPOSE
277
- The secret rotation worker currently holds a Postgres advisory lock for the full rotation batch, including network I/O to KMS. A batch of 500 keys blocks all other rotations for ~3 min, stalling unrelated tenants sharing the worker pool.
334
+ ## PURPOSE
335
+ The secret rotation worker currently holds a Postgres advisory lock for the full rotation batch, including network I/O to KMS. A batch of 500 keys blocks all other rotations for ~3 min, stalling unrelated tenants sharing the worker pool.
278
336
 
279
- ## DESCRIPTION
280
- `rotateBatch` acquires `pg_advisory_lock(rotation_ns)` once, then loops: read key, call KMS encrypt, write ciphertext, advance cursor. The lock spans the whole loop.
337
+ ## DESCRIPTION
338
+ `rotateBatch` acquires `pg_advisory_lock(rotation_ns)` once, then loops: read key, call KMS encrypt, write ciphertext, advance cursor. The lock spans the whole loop.
281
339
 
282
- This PR moves the lock acquisition inside the loop, around only the DB read+write. KMS calls run unlocked. Cursor advancement unchanged.
340
+ This PR moves the lock acquisition inside the loop, around only the DB read+write. KMS calls run unlocked. Cursor advancement unchanged.
283
341
 
284
- Net effect: concurrent rotations for other tenants no longer block on KMS I/O, removing the stall in PURPOSE. A crash mid-batch resumes from the cursor, which was already the behavior on any non-lock failure.
342
+ Net effect: concurrent rotations for other tenants no longer block on KMS I/O, removing the stall in PURPOSE. A crash mid-batch resumes from the cursor, which was already the behavior on any non-lock failure.
285
343
 
286
- ## NOTES
287
- - **lock is no longer held across KMS** - intentional narrowing, not a regression.
344
+ ## NOTES
345
+ - **lock is no longer held across KMS** - intentional narrowing, not a regression.
346
+ ```
288
347
 
289
348
  ### Large change (with WALK-THROUGH)
290
349
 
291
- ## SYNOPSIS
292
- Move **connection acquisition** inside the transaction boundary to prevent **lock leaks across retry loops**.
350
+ ```md
351
+ ## SYNOPSIS
352
+ Move **connection acquisition** inside the transaction boundary to prevent **lock leaks across retry loops**.
353
+
354
+ Ticket: [PLAT-501](https://example.atlassian.net/browse/PLAT-501)
355
+
356
+ ## PURPOSE
357
+ The batch processor opens a database connection before entering the retry loop, then begins a transaction inside each retry attempt. If a retry fails and the loop continues, the connection is reused for the next attempt without releasing the transaction savepoint. This holds locks from the failed attempt across the retry, blocking concurrent writers.
293
358
 
294
- Ticket: [PLAT-501](https://example.atlassian.net/browse/PLAT-501)
359
+ ## DESCRIPTION
360
+ The root cause is a mismatch between connection lifecycle and transaction lifecycle. The connection is acquired once and held for the whole batch. The transaction is per-attempt but the savepoint release is skipped on error. The fix is to acquire a fresh connection per attempt, so each retry starts with a clean connection and a clean transaction boundary.
295
361
 
296
- ## PURPOSE
297
- The batch processor opens a database connection before entering the retry loop, then begins a transaction inside each retry attempt. If a retry fails and the loop continues, the connection is reused for the next attempt without releasing the transaction savepoint. This holds locks from the failed attempt across the retry, blocking concurrent writers.
362
+ ## WALK-THROUGH
298
363
 
299
- ## DESCRIPTION
300
- The root cause is a mismatch between connection lifecycle and transaction lifecycle. The connection is acquired once and held for the whole batch. The transaction is per-attempt but the savepoint release is skipped on error. The fix is to acquire a fresh connection per attempt, so each retry starts with a clean connection and a clean transaction boundary.
364
+ 1. **Connection acquired once at the top** - the handler opens a database connection before entering the retry loop and holds it for the whole batch.
365
+ - **NOW** - _a fresh connection is acquired per attempt, so each retry starts with a clean connection._
301
366
 
302
- ## WALK-THROUGH
367
+ 2. **Transaction begins inside each retry** - `BEGIN` is issued inside the retry loop, but the connection from the failed attempt is reused without releasing the savepoint.
368
+ - **NOW** - _`BEGIN` is issued immediately after acquisition, so the connection and transaction lifecycles are aligned._
303
369
 
304
- 1. **Batch processor receives work item** - the handler now calls `acquireConnection` per attempt instead of once at the top.
305
- 2. **Connection enters transaction** - `BEGIN` is issued immediately after acquisition, so the connection and transaction lifecycles are aligned.
306
- 3. **Work executes** - the batch runs its queries inside the transaction. _This is where the lock leak originated: the old code held the connection open across retries, dragging the previous transaction's locks into the next attempt._
307
- 4. **Retry on failure** - on error, the connection is released and a new one is acquired for the next attempt. The savepoint from the failed attempt is gone with the connection.
308
- 5. **Commit on success** - the transaction commits and the connection is released. Clean exit.
370
+ 3. **Work executes inside the transaction** - the batch runs its queries, holding locks from the failed attempt across the retry.
371
+ - **NOW** - _the batch runs inside a clean transaction. The previous attempt's locks are gone with the released connection._
309
372
 
310
- ## NOTES
311
- - **connection pool pressure** - acquiring per attempt increases pool churn under heavy retry load. Acceptable because retries are rare (observed <0.1% in prod).
312
- - **PLAT-501 scope** - this addresses the lock leak. The retry backoff strategy described in the ticket is deferred to a follow-up.
373
+ 4. **Retry reuses the connection** - on error, the loop continues with the same connection, dragging the previous transaction's locks into the next attempt.
374
+ - **NOW** - _on error, the connection is released and a new one is acquired. The savepoint from the failed attempt is gone with the connection._
375
+
376
+ 5. **Commit releases the connection** - on success, the transaction commits but the connection was already held for the whole batch.
377
+ - **NOW** - _the transaction commits and the connection is released. Clean exit per attempt._
378
+
379
+ ## NOTES
380
+ - **connection pool pressure** - acquiring per attempt increases pool churn under heavy retry load. Acceptable because retries are rare (observed <0.1% in prod).
381
+ - **PLAT-501 scope** - this addresses the lock leak. The retry backoff strategy described in the ticket is deferred to a follow-up.
382
+ ```
313
383
 
314
384
  Scan the bolds only:
315
385
  > rotation advisory lock ... KMS I/O ... connection acquisition ... lock leaks across retry loops ... Batch processor receives work item ... Connection enters transaction ... Work executes ... Retry on failure ... Commit on success ... lock is no longer held across KMS ... connection pool pressure ... PLAT-501 scope
@@ -320,17 +390,19 @@ That reading alone conveys the shape and scope of both changes. The prose is for
320
390
 
321
391
  1. **Gather**: `git log $MERGE_BASE..HEAD`, `git diff $MERGE_BASE..HEAD --stat`, commit messages, current branch name. Apply the ticket resolution order (SYNOPSIS section) - infer first, ask only if nothing matches. Skim the diff; identify decision points (components or branches where behavior differs before vs after). Identify the workflow or lifecycle path if the change has one.
322
392
  2. **Read ticket context**: if a ticket is resolved, fetch its description. Use it to seed PURPOSE and identify reviewer-relevant plan changes: revisions, pivots caused by code reality, discoveries after the ticket was written, and deferred or unnecessary ticket items.
323
- 3. **Draft PURPOSE first**, in one breath, without looking at code. If you cannot state the harm in two sentences, you do not understand the PR yet. Go back and read. When a ticket is available, seed PURPOSE from its problem statement, but verify against the code.
324
- 4. **Write DESCRIPTION**: choose the right depth (collapsed for small, three-layer for medium, root-cause + concept for large with WALK-THROUGH). Name everything you will refer to later. Organize by workflow/data-flow, not by touched symbol.
325
- 5. **Write WALK-THROUGH** (if needed): numbered steps in execution order. Bold the step leads. State what changed, not what you did.
326
- 6. **Write SYNOPSIS last** - it is a compression of PURPOSE + the core mechanic.
327
- 7. **Bold and italicize the save points** in the allowed locations. Bold phrases that name the change (components, mechanisms, behaviors). Italicize phrases that orient to significance (conclusions, payoffs), at most one per paragraph. Apply the scan check: read only the bold and italic fragments and verify the shape comes through.
328
- 8. **Add NOTES** for AI-reviewer defensive lines, scope disclaimers, ticket scope mismatches, and remaining work. Use `## NOTES` header. Omit if empty.
329
- 9. **robots.txt only when earned**: do not add it during initial authoring. It is added later, in response to an automated reviewer's false positive (see its section). When you do add it, use the collapsed `<details>` format with `<summary>robots.txt</summary>`, keep the editing HTML comment at the top of the block, and keep the human-warning line first after the comment.
330
- 10. **Verify links**: check ticket/PR links, repo file links, and external docs where tooling allows. Do not claim an unverified link was verified.
331
- 11. **Verify prose style**: check each rule in Prose style. Cut design-narration, authoring-sequence, and buzzwordy abstractions. Verify plain ASCII. Verify first-use definitions for subsystem jargon. Verify plain English nouns (no code-domain nouns in prose). Verify conclusion-first in PURPOSE. Verify NOTES bullets are either short pointers or self-contained. Verify one-paragraph-one-physical-line for GitHub rendering. The robots.txt section is exempt from these prose rules below its human-warning line.
332
- 12. **Verify length**: if the body exceeds the ceiling for its conceptual size, cut until each line earns its place.
333
- 13. **Submit** via `gh pr create --body "$(cat <<'EOF' ... EOF)"` to preserve formatting.
393
+ 3. **Read project context for stacked work**: if the PR refers to related PRs, follow-ups, deferred design, upstream dependencies, or unexplained project terms, read the linked source material before drafting. Build a private term map. If a term controls the PR and you cannot resolve it, ask the user.
394
+ 4. **Draft PURPOSE first**, in one breath, without looking at code. If you cannot state the harm in two sentences, you do not understand the PR yet. Go back and read. When a ticket is available, seed PURPOSE from its problem statement, but verify against the code.
395
+ 5. **Write DESCRIPTION**: choose the right depth (collapsed for small, three-layer for medium, root-cause + concept for large with WALK-THROUGH). Name everything you will refer to later. Organize by workflow/data-flow, not by touched symbol. Add a one- or two-sentence context bridge only when stacked-project context is needed to understand this PR's delta.
396
+ 6. **Write WALK-THROUGH** (if needed): numbered steps in execution order. Bold the step leads. State what changed, not what you did.
397
+ 7. **Write SYNOPSIS last** - it is a compression of PURPOSE + the core mechanic.
398
+ 8. **Bold and italicize the save points** in the allowed locations. Bold phrases that name the change (components, mechanisms, behaviors). Italicize phrases that orient to significance (conclusions, payoffs), at most one per paragraph. Apply the scan check: read only the bold and italic fragments and verify the shape comes through.
399
+ 9. **Add NOTES** for AI-reviewer defensive lines, scope disclaimers, ticket scope mismatches, and remaining work. Use `## NOTES` header. Omit if empty.
400
+ 10. **robots.txt only when earned**: do not add it during initial authoring. It is added later, in response to an automated reviewer's false positive (see its section). When you do add it, use the collapsed `<details>` format with `<summary>robots.txt</summary>`, keep the editing HTML comment at the top of the block, and keep the human-warning line first after the comment.
401
+ 11. **Verify links**: check ticket/PR links, repo file links, and external docs where tooling allows. Do not claim an unverified link was verified.
402
+ 12. **Verify prose style and core principle**: check each rule in Prose style. Cut design-narration, authoring-sequence, and buzzwordy abstractions. Verify plain ASCII. Verify first-use definitions for subsystem jargon. Verify project-private labels are translated before use. Verify plain English nouns (no code-domain nouns in prose). Verify conclusion-first in PURPOSE. Verify NOTES bullets are either short pointers or self-contained. Verify one-paragraph-one-physical-line for GitHub rendering. The robots.txt section is exempt from these prose rules below its human-warning line.
403
+ 13. **Clarity pass**: read the draft as a cold reviewer skimming the PR. Rewrite before returning it; do not tell the user you performed this pass. Check: does every project-specific term get plain-English meaning before or with the label? Are ambiguous terms qualified or replaced with concrete behavior? Did you replace code/comment shorthand with reader-facing behavior when the shorthand is less clear? Does every process word name object/action/effect? Does every contrast name old and new behavior? Does every causal sentence show the middle step? Did you preserve connective tissue instead of compressing meaning into noun stacks? If the draft got longer, cut a lower-value claim instead of compressing a high-value one.
404
+ 14. **Verify length**: if the body exceeds the ceiling for its conceptual size, cut until each line earns its place. For enormous PRs, accept extra length only when it buys context, concrete behavior, or reviewer safety.
405
+ 15. **Submit** via `gh pr create --body "$(cat <<'EOF' ... EOF)"` to preserve formatting.
334
406
 
335
407
  ## Anti-patterns
336
408
 
@@ -346,7 +418,12 @@ That reading alone conveys the shape and scope of both changes. The prose is for
346
418
  - **Orphaned synopsis.** A bold lead paragraph with no `## SYNOPSIS` header above a body that does use headers. Add the header; it is mandatory.
347
419
  - **Bare `Notes:` line.** Use `## NOTES` header or omit the section entirely.
348
420
  - **Organizing by touched symbol.** A bullet list of "changed X in file A, changed Y in file B" reads as disconnected touchpoints. Follow the data flow.
349
- - **Buzzwordy abstractions.** "identity contract", "canonical hash", "check in isolation" - if it sounds like it is trying to sound smart, replace it with plain concrete wording.
421
+ - **Buzzwordy abstractions.** "identity contract", "canonical hash", "check in isolation", "shared seam" - if it sounds like it is trying to sound smart, replace it with plain concrete wording. If "seam" means a conceptual border, say "boundary". If it means common code, say "shared helper", "shared function", or "shared SQL expression".
422
+ - **Project-private labels as explanations.** Roadmap names, subsystem nicknames, architecture slogans, ticket shorthand, internal stack names, and branch-local labels are not explanations. Say what the code does first. The label can follow only if it helps a reviewer connect the prose to the code.
423
+ - **Compressed meaning.** "Coalesced refresh", "synchronous repair", "derived projection", "normalized identity", "resolved state", and similar phrases are not clear unless the sentence says what object changes and what the result is. If a reader has to infer the missing action, expand the sentence or cut the claim.
424
+ - **Copied code shorthand.** A term from a function name, code comment, metric, or existing PR body is not automatically good prose. If the code's word is less concrete than the behavior, translate it.
425
+ - **Invisible contrast.** "X is synchronous now" or "Y is now shared" means little unless the old behavior is nearby. Name both sides of the change.
426
+ - **Missing causal step.** A sentence with "so", "because", "therefore", "prevents", or "allows" must show the mechanism. If the cause and effect do not obviously touch, add the missing step or remove the causal claim.
350
427
  - **Loaded language.** Using avoidable loaded terms when neutral terms exist. Prefer allowlist/blocklist, primary/replica, and precise role names.
351
428
  - **Smart punctuation.** Em dashes, smart quotes, ellipsis glyphs. Use plain ASCII.
352
429
  - **Splitting paragraphs across lines.** GitHub renders each line break as a visible break. One paragraph = one physical line.
@@ -358,3 +435,4 @@ That reading alone conveys the shape and scope of both changes. The prose is for
358
435
  - **NOTES bullets that are both wordy and terse.** A bullet that compresses a paragraph of rationale into one dense sentence reads as a private note. Either flag the thing and point to the full explanation, or write a self-contained sentence or two. Not the middle thing.
359
436
  - **robots.txt as a suppression lever.** Writing "ignore the finding about X" or "skip checking X" in robots.txt turns it into a rubber stamp and a prompt-injection surface. Explain what X does and the intent behind it so the reviewer clears its own false positive; never instruct it to stop looking.
360
437
  - **Preemptive robots.txt.** Adding the section before any automated reviewer has actually produced a false positive. It is a response to a demonstrated misread, not scaffolding.
438
+ - **Over-decomposed WALK-THROUGH.** Nine steps for a refresh flow means you are listing function calls, not workflow phases. Group related stages. A step is a phase the reviewer can hold in their head, not a single operation. If a step's bold lead is a function name, you went too granular.
@@ -104,7 +104,15 @@ For the integration review unit (5+ points), dispatch a sub-agent focused on:
104
104
 
105
105
  ## Step 7: Synthesize
106
106
 
107
- 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.
107
+ 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 report.
108
+
109
+ Pass the synthesizer:
110
+ - The project context brief from Step 2.
111
+ - The workflow guide from Step 3.
112
+ - The specialist findings.
113
+ - The prior-comments register when present.
114
+
115
+ The final user-facing report MUST begin with a concise explanation of the workflow(s) this PR changes before listing findings. Use one `### Workflow changes` section, with one subheading per affected workflow when there are multiple. Use the before/now walkthrough shape from the pr-description skill: numbered step = existing behavior; `NOW` sub-bullet = what the PR changes; `N/A` for new stages. This gives the user a map of the change before the findings. Keep it short: 3-6 steps per workflow.
108
116
 
109
117
  Confirmed LOW findings are mandatory in the final report, including mechanical findings (pedantic, no-slop, breadcrumbs, docs, naming, style, comments). Do not omit them for being non-functional.
110
118
 
@@ -117,7 +125,7 @@ Alternatively, perform the synthesis yourself:
117
125
  4. Classify each as CONFIRMED, REJECTED, or UNVERIFIABLE. For behavioral findings, apply citation verification, reachability, and intent verification. For mechanical findings, verify the cited text exists, is branch-introduced or newly made relevant, and violates the stated guideline or specialist taxonomy.
118
126
  5. Cross-reference against the prior-comments register if one was built in Step 2: tag matching findings `Provenance: previously identified by @author, PR #N, DATE` and produce the `### Previously identified findings` appendix per the synthesizer skill.
119
127
  6. Calibrate severity (BLOCKING > HIGH > MEDIUM > LOW) based on your verification.
120
- 7. Produce a final report grouped by severity, with coverage gaps noted. Include every confirmed LOW finding.
128
+ 7. Produce a final report with a workflow-change preface, findings grouped by severity, and coverage gaps noted. Include every confirmed LOW finding.
121
129
 
122
130
  ## Specialist briefing template
123
131
 
@@ -90,11 +90,36 @@ You MUST produce the full report structure below. Do not simplify or omit sectio
90
90
 
91
91
  Confirmed LOW findings are mandatory. Do not summarize them away or omit them for being non-functional. Pedantic, no-slop, breadcrumbs, docs, naming, style, and comment findings are first-class review findings when confirmed. Group them under LOW, but include every one.
92
92
 
93
+ The report is user-facing. Start by teaching the changed workflows before listing findings. Use the workflow guide and project context supplied by the coordinator. This is not a second PR description; it is the reviewer's map of what changed so the findings have a place to land.
94
+
95
+ For each affected workflow, use the same before/now shape as PR descriptions:
96
+ - Numbered step: existing behavior or current workflow stage.
97
+ - `NOW` sub-bullet: what this PR changes at that stage.
98
+ - `N/A` as the numbered item for a new stage.
99
+
100
+ Keep this section short. Aim for 3-6 steps per workflow. If there are multiple affected workflows, use one subheading per workflow. If the change is small and no workflow changed, write "None — no workflow-level behavior changed".
101
+
102
+ Apply the same clarity rules as the writing skills: prefer concrete terms over ambiguous ones, translate project-private labels before using them, name object/action/effect for process words, show both sides of contrasts, and show causal middle steps. Do not copy code-comment shorthand when reader-facing behavior is clearer.
103
+
93
104
  ### Scope
105
+
94
106
  - Branch/range reviewed
95
107
  - Design context (if provided)
96
108
 
109
+ ### Workflow changes
110
+
111
+ For each affected workflow:
112
+
113
+ #### Workflow name
114
+
115
+ 1. **Existing behavior or stage** — one sentence describing how the code worked before this PR.
116
+ - **NOW** — _one sentence describing what this PR changes._
117
+
118
+ 2. **N/A**
119
+ - **NOW** — _one sentence describing a new stage this PR adds._
120
+
97
121
  ### Confirmed findings
122
+
98
123
  For each finding, grouped by severity (BLOCKING > HIGH > MEDIUM > LOW). Each finding MUST include all of these fields:
99
124
  1. **Severity** and **category** (from the specialist's taxonomy)
100
125
  2. **Source**: which specialist found it
@@ -105,12 +130,15 @@ For each finding, grouped by severity (BLOCKING > HIGH > MEDIUM > LOW). Each fin
105
130
  7. **Provenance**: branch-introduced or pre-existing. If the finding matches a prior review comment, append `; previously identified by @author, PR #N, DATE` to this field. For findings matching an `addressed` prior comment, also add a one-line note on why the finding persists so the user can investigate whether the prior resolution is incomplete or the issue has regressed.
106
131
 
107
132
  ### Rejected findings (appendix, brief)
133
+
108
134
  Findings you rejected and a one-line reason why. Include the specialist and location for each.
109
135
 
110
136
  ### Pre-existing bugs (appendix, brief)
137
+
111
138
  Findings you verified as real but pre-existing, with a one-line note on the issue and its potential impact.
112
139
 
113
140
  ### Previously identified findings (appendix — only when a prior-comments register was provided)
141
+
114
142
  List every entry from the prior-comments register here. For each entry, produce a one-block record:
115
143
  1. **Author and date** of the original comment
116
144
  2. **Original location** (`file:line @ commit-SHA`, or `summary review`) and **current HEAD location** (`file:line`) if locatable
@@ -125,4 +153,5 @@ List every entry from the prior-comments register here. For each entry, produce
125
153
  If no prior-comments register was provided (local-branch review or first round on the PR/MR), state `None — no prior review comments to cross-reference` and move on.
126
154
 
127
155
  ### Coverage gaps
156
+
128
157
  Note which files or areas were NOT covered by any specialist.
@@ -1,10 +1,20 @@
1
1
  ---
2
2
  name: ticket-description
3
- description: Draft a ticket description using instructional-design scaffolding (SYNOPSIS / PROBLEM / BACKGROUND / PROPOSED APPROACH / ACCEPTANCE CRITERIA / RELEASE PLAN / VALIDATION / DEPENDENCIES / NOTES) with bold and italic emphasis on the phrases that carry the meaning, so a reader skimming only the emphasized fragments still gets the story. Use when the user asks you to write, draft, or file a ticket, issue, or work item (Linear or Jira). Do NOT use for PR descriptions (use pr-description), commit messages, or design docs.
3
+ description: Draft a ticket description (SYNOPSIS / PROBLEM / BACKGROUND / PROPOSED APPROACH / ACCEPTANCE CRITERIA / RELEASE PLAN / VALIDATION / DEPENDENCIES / NOTES) with bold and italic emphasis on the phrases that carry the meaning, so a reader skimming only the emphasized fragments still gets the story. Use when the user asks you to write, draft, or file a ticket, issue, or work item (Linear or Jira). Do NOT use for PR descriptions (use pr-description), commit messages, or design docs.
4
4
  ---
5
5
 
6
6
  # Writing ticket descriptions
7
7
 
8
+ ## Core principle
9
+
10
+ Write for humans. Not for LLMs. Not to impress. Not to pad.
11
+
12
+ Every sentence earns its place or gets cut. Plain English over jargon. Concrete over abstract. Short over long. A ticket a human reads once and can start work from beats one that looks thorough but says nothing.
13
+
14
+ If a word does not help a human understand the work, it is dead weight. If a sentence restates the previous one, one is redundant. If a phrase sounds smart but you cannot explain it in simpler words, it is a buzzword. Cut, replace, or simplify.
15
+
16
+ Target a 7th-grade reading level. Not because the reader is dumb, but because plain prose is faster to read and harder to misread. Short sentences, common words, one idea each. The concepts stay technical; the language stays simple.
17
+
8
18
  ## The reader
9
19
 
10
20
  You are writing for two people who share one trait: neither has your context, and neither knows this subsystem's jargon.
@@ -15,7 +25,7 @@ The second reader is an **implementer** picking up the ticket cold. They need to
15
25
 
16
26
  The description is not a design doc. It is a specification that makes work startable. A design doc (when one is warranted) may live in repo docs, Linear, Notion, Archbee, Google Docs, Figma, or another system; link it from the ticket instead of inlining it. The ticket's job is to define the problem, propose a direction, and set the gates that define "done."
17
27
 
18
- This is **instructional design**, not documentation. Each section has a cognitive goal:
28
+ Each section has one job:
19
29
  - SYNOPSIS: orient to the class of work and affected area.
20
30
  - PROBLEM: make the reader agree there is something worth solving.
21
31
  - BACKGROUND: give the implementer the context they would otherwise re-derive.
@@ -26,7 +36,7 @@ This is **instructional design**, not documentation. Each section has a cognitiv
26
36
  - DEPENDENCIES: explain ordering constraints, not just list them.
27
37
  - NOTES: flag scope limits, intentional non-goals, and things that look in-scope but aren't.
28
38
 
29
- Layer the knowledge so each section builds on the previous one. The reader should never encounter a concept in section N that was not introduced in section N-1.
39
+ Each section builds on the previous one. The reader should never encounter a concept in section N that was not introduced in section N-1.
30
40
 
31
41
  ## Structure
32
42
 
@@ -119,7 +129,7 @@ Only when prod verification is non-trivial. A pure refactor with good tests does
119
129
 
120
130
  ### DEPENDENCIES (conditional)
121
131
 
122
- Blocking relationships and ordering constraints. "Blocked by PLAT-126" is the tracker field; the *why* belongs here: "PLAT-125 partitions by location_fingerprint, so it can only run after backfill completes (count == 0), not merely after PLAT-124 merges." That kind of nuance is what prevents a well-intentioned lead from reordering the queue.
132
+ Blocking relationships and ordering constraints. "Blocked by PLAT-126" is the tracker field; the _why_ belongs here: "PLAT-125 partitions by location_fingerprint, so it can only run after backfill completes (count == 0), not merely after PLAT-124 merges." That kind of nuance is what prevents a well-intentioned lead from reordering the queue.
123
133
 
124
134
  Distinguish hard data dependencies (cannot run until X completes) from soft dependencies (should run after X for cleanliness, but technically works independently). Say which kind it is.
125
135
 
@@ -141,7 +151,7 @@ If there are no notes, omit the section entirely. Do not emit an empty `## NOTES
141
151
 
142
152
  ## Emphasis for scanning: bold and italics
143
153
 
144
- Bold and italicize the "save points" - the phrases that carry meaning - not whole sentences. A reader who skims *only* the bold and italic fragments should get the story; full prose is for when they want detail.
154
+ Bold and italicize the "save points" - the phrases that carry meaning - not whole sentences. A reader who skims _only_ the bold and italic fragments should get the story; full prose is for when they want detail.
145
155
 
146
156
  **What to bold:** phrases that name the **work itself** - the component, the failure mode, the mechanism, the behavior the ticket asks for. These are the nouns and verbs that would appear in a diff of the design, not a diff of the code. "**circular wait** in the **KeyManager**" names the failure mode and the component. "**load key material outside the mutex**" names the mechanism.
147
157
 
@@ -177,10 +187,11 @@ These are hard rules, not suggestions.
177
187
  5. **No authoring-sequence narration.** Never describe the order you discovered things in, which draft had what, or what a later revision will add. Describe the ticket as it stands.
178
188
  6. **Italics for orientation asides.** Use `_italics_` for a one-phrase aside that orients the reader: _This is where the deadlock lived_. Not for emphasis.
179
189
  7. **Plain ASCII only.** No smart quotes, smart apostrophes, em dashes, en dashes, ellipsis glyphs, or arrow glyphs. Use plain hyphens (sparingly) for asides; semicolons are often better.
180
- 8. **No buzzwordy abstractions.** If a phrase sounds like it is trying to sound smart, cut or replace it. Name the code and behavior directly. "identity contract" -> "the struct field that identifies the owner". "canonical hash" -> "the SHA-256 we compute on ingestion".
181
- 9. **Prescriptive voice.** The ticket proposes work that hasn't happened yet. Use "the fix should...", "the implementation must...", "the worker should..." not "this PR moves..." or "the code now...". The PR description uses descriptive voice; the ticket uses prescriptive.
182
- 10. **Default to a numbered outline for steps.** A flat list, with an occasional inline branch ("if the path is not in the registry, return a 404; otherwise continue to step 6"), covers almost every workflow. The bar for a diagram or Mermaid chart is high: reach for one only when the flow genuinely needs two dimensions to read - a graph network with many nodes and edges, or a workflow that recurses, forks, and rejoins in ways a linear outline cannot follow without constant back-references. If the flow is one or two levels deep and does not recurse or redirect, an outline is clearer and cheaper to maintain than a diagram.
183
- 11. **Avoid loaded language.** Use neutral, current terminology unless the repo's established name is different. Prefer allowlist/blocklist over whitelist/blacklist, primary/replica over master/slave, and precise role names over moralized labels like "bad" or "evil".
190
+ 8. **No buzzwordy abstractions.** If a phrase sounds like it is trying to sound smart, cut or replace it. Name the code and behavior directly. "identity contract" -> "the struct field that identifies the owner". "canonical hash" -> "the SHA-256 we compute on ingestion". "leverage" -> "use". "utilize" -> "use". "facilitate" -> "help". If you cannot say what a phrase means in plain English, it does not belong. Buzzwords are the number-one signal that an AI wrote the ticket; do not send that signal.
191
+ 9. **Prefer specific terms over ambiguous ones.** If a word can mean more than one thing in this ticket, qualify it or replace it with the specific behavior. Do not rely on the reader guessing the local meaning. Ordinary words can be ambiguous when the code gives them a special role: claim, owner, active, current, generation, repair, coalesce, terminal, source, scope, sync, publish, resolve. "Publish the value" is vague. "Persist the value in the database so the UI can display it" is specific.
192
+ 10. **Prescriptive voice.** The ticket proposes work that hasn't happened yet. Use "the fix should...", "the implementation must...", "the worker should..." not "this PR moves..." or "the code now...". The PR description uses descriptive voice; the ticket uses prescriptive.
193
+ 11. **Default to a numbered outline for steps.** A flat list, with an occasional inline branch ("if the path is not in the registry, return a 404; otherwise continue to step 6"), covers almost every workflow. The bar for a diagram or Mermaid chart is high: reach for one only when the flow genuinely needs two dimensions to read - a graph network with many nodes and edges, or a workflow that recurses, forks, and rejoins in ways a linear outline cannot follow without constant back-references. If the flow is one or two levels deep and does not recurse or redirect, an outline is clearer and cheaper to maintain than a diagram.
194
+ 12. **Avoid loaded language.** Use neutral, current terminology unless the repo's established name is different. Prefer allowlist/blocklist over whitelist/blacklist, primary/replica over master/slave, and precise role names over moralized labels like "bad" or "evil".
184
195
 
185
196
  ## Length and style
186
197
 
@@ -207,6 +218,23 @@ Comparison process:
207
218
 
208
219
  When the codebase contradicts the ticket, flag the discrepancy to the user before drafting. Do not silently paper over the gap.
209
220
 
221
+ ## Project context for planned work
222
+
223
+ Some tickets are slices of a larger project. The code alone may not explain the project terms, ordering constraints, or prior decisions the implementer needs. Before drafting, read enough context to make the ticket startable for an engineer new to this area.
224
+
225
+ Read project context when the request, existing ticket, code comments, branch name, prior PRs, docs, or discussion mentions:
226
+ - a parent ticket, related PR, follow-up, or multi-ticket project;
227
+ - a deferred part of the design;
228
+ - an upstream dependency;
229
+ - a project-specific term whose local meaning is not obvious from the code touched by this ticket;
230
+ - a roadmap label, subsystem nickname, architecture slogan, or branch-local name.
231
+
232
+ Use available source material: linked tickets, linked PRs, nearby docs, code comments, commit messages, and project memory. Build a private term map: term -> plain behavior -> source. Do not dump the map into the ticket. Use it to write the shortest useful BACKGROUND.
233
+
234
+ If a term or dependency controls the work and you cannot resolve it from available context, stop and ask the user. Do not guess. Do not write around the missing definition with vaguer words.
235
+
236
+ Put project context in BACKGROUND only when it helps the implementer start work or helps a lead schedule it correctly. Omit generic backstory.
237
+
210
238
  ## Search before create
211
239
 
212
240
  Before filing a new ticket, search for likely duplicates in the tracker. Use the proposed title, problem keywords, affected subsystem, and any incident/customer/project references. If a plausible duplicate exists, surface it to the user before drafting or filing.
@@ -361,20 +389,22 @@ That reading alone conveys the shape, scope, and gates of all three tickets.
361
389
  1. **Gather**: read the code the ticket references. Check `git log` for recent changes to the same files. Identify the problem, the prior work, and the proposed direction.
362
390
  2. **Search before create**: search Linear/Jira for likely duplicate tickets. If one exists, surface it before drafting or filing.
363
391
  3. **Codebase comparison**: verify the problem still exists in the current code. If it was already fixed, tell the user. If it was partially mitigated, note the mitigation.
364
- 4. **Draft PROBLEM first**, in one breath, without looking at code. If you cannot state the harm in three sentences, you do not understand the problem yet. Go back and read.
365
- 5. **Write BACKGROUND** (if needed): what prior work led here, what was done, what was left behind.
366
- 6. **Write PROPOSED APPROACH**: the compass heading, not the map. Prescriptive voice.
367
- 7. **Write ACCEPTANCE CRITERIA**: observable, testable bullets. Name the test shape where relevant.
368
- 8. **Write RELEASE PLAN** (if needed): flags, ordering, rollback.
369
- 9. **Write VALIDATION** (if needed): monitoring, signals, smoke tests.
370
- 10. **Write DEPENDENCIES** (if needed): what blocks this, what this blocks, and why.
371
- 11. **Write SYNOPSIS last** - it is a compression of PROBLEM + the core approach.
372
- 12. **Bold and italicize the save points** in the allowed locations. Bold phrases that name the work (components, mechanisms, behaviors). Italicize phrases that orient to significance (conclusions, payoffs), at most one per paragraph. Apply the scan check.
373
- 13. **Add NOTES** for non-goals, declined alternatives, and scope limits. Use `## NOTES` header. Omit if empty.
374
- 14. **Suggest Linear labels** when the ticket is being filed in Linear. Use obvious stable labels only; do not guess initiative labels.
375
- 15. **Verify links**: check repo file links, external docs, tickets, PRs, and design artifacts where tooling allows. Do not claim an unverified link was verified.
376
- 16. **Verify prose style**: check each rule in Prose style. Cut design-narration, authoring-sequence, and buzzwordy abstractions. Verify plain ASCII. Verify prescriptive voice (not descriptive). Verify first-use definitions for subsystem jargon in BACKGROUND or PROBLEM. Verify plain English nouns (no code-domain nouns in prose). Verify conclusion-first in PROBLEM. Verify NOTES bullets are either short pointers or self-contained.
377
- 17. **Verify length**: if the body exceeds what the work's conceptual size warrants, cut until each line earns its place. If PROPOSED APPROACH dominates, consider splitting into a design doc plus ticket.
392
+ 4. **Read project context for planned work**: if the ticket is part of a larger project, depends on prior work, uses unexplained project terms, or has scheduling dependencies, read the linked tickets, PRs, docs, comments, and memory before drafting. Build a private term map. If a term or dependency controls the work and you cannot resolve it, ask the user.
393
+ 5. **Draft PROBLEM first**, in one breath, without looking at code. If you cannot state the harm in three sentences, you do not understand the problem yet. Go back and read.
394
+ 6. **Write BACKGROUND** (if needed): what prior work led here, what was done, what was left behind, and what project context an engineer new to this area needs to start.
395
+ 7. **Write PROPOSED APPROACH**: the compass heading, not the map. Prescriptive voice.
396
+ 8. **Write ACCEPTANCE CRITERIA**: observable, testable bullets. Name the test shape where relevant.
397
+ 9. **Write RELEASE PLAN** (if needed): flags, ordering, rollback.
398
+ 10. **Write VALIDATION** (if needed): monitoring, signals, smoke tests.
399
+ 11. **Write DEPENDENCIES** (if needed): what blocks this, what this blocks, and why.
400
+ 12. **Write SYNOPSIS last** - it is a compression of PROBLEM + the core approach.
401
+ 13. **Bold and italicize the save points** in the allowed locations. Bold phrases that name the work (components, mechanisms, behaviors). Italicize phrases that orient to significance (conclusions, payoffs), at most one per paragraph. Apply the scan check.
402
+ 14. **Add NOTES** for non-goals, declined alternatives, and scope limits. Use `## NOTES` header. Omit if empty.
403
+ 15. **Suggest Linear labels** when the ticket is being filed in Linear. Use obvious stable labels only; do not guess initiative labels.
404
+ 16. **Verify links**: check repo file links, external docs, tickets, PRs, and design artifacts where tooling allows. Do not claim an unverified link was verified.
405
+ 17. **Verify prose style and core principle**: check each rule in Prose style. Cut design-narration, authoring-sequence, and buzzwordy abstractions. Verify plain ASCII. Verify prescriptive voice (not descriptive). Verify first-use definitions for subsystem jargon in BACKGROUND or PROBLEM. Verify plain English nouns (no code-domain nouns in prose). Verify conclusion-first in PROBLEM. Verify NOTES bullets are either short pointers or self-contained.
406
+ 18. **Clarity pass**: read the draft as a cold lead skimming a backlog, then as an implementer picking up the work cold. Rewrite before returning it; do not tell the user you performed this pass. Check: does every project-specific term get plain-English meaning before or with the label? Are ambiguous terms qualified or replaced with specific behavior? Does every process word name object/action/effect? Does every contrast name current and proposed behavior? Does every causal sentence show the middle step? Did you preserve connective tissue instead of compressing meaning into noun stacks? If the draft got longer, cut a lower-value claim instead of compressing a high-value one.
407
+ 19. **Verify length**: if the body exceeds what the work's conceptual size warrants, cut until each line earns its place. If PROPOSED APPROACH dominates, consider splitting into a design doc plus ticket.
378
408
 
379
409
  ## Anti-patterns
380
410
 
@@ -36,21 +36,21 @@ 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-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
39
- | `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Cross-references findings against prior review comments when a follow-up round register is provided; produces a Previously identified appendix. |
39
+ | `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Starts the final report with a workflow-change preface, then cross-references findings against prior review comments when a follow-up round register is provided. |
40
40
  | `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
41
41
  | `thatch-workflow-research` | Research code workflows/features affected by a change or planned change. Reads code flows, comments, git history, memories, docs. Produces a guide to the code for reviewers or planners. |
42
42
  | `thatch-change-walkthrough` | Explain a change to the user as a teaching walkthrough: resolve the delta, research each affected workflow at the merge-base, teach current behavior, then overlay the modifications with file:line citations and analogies. |
43
43
  | `thatch-code-walkthrough` | Explain a feature, module, or workflow to the user as a teaching walkthrough: identify the code area (optionally from a branch or PR), research how it works, teach it with file:line citations and analogies, list the key files. |
44
44
  | `thatch-session-reflection` | End-of-session memory recording (project, user, tools, self). |
45
- | `pr-description` | Draft PR descriptions with instructional-design scaffolding (SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES) and bold+italic emphasis for scanning. |
46
- | `ticket-description` | Draft ticket/issue descriptions with instructional-design scaffolding (SYNOPSIS / PROBLEM / BACKGROUND / PROPOSED APPROACH / ACCEPTANCE CRITERIA / RELEASE PLAN / VALIDATION / DEPENDENCIES / NOTES). |
45
+ | `pr-description` | Draft PR descriptions with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, project-context research, clarity checks, and bold+italic emphasis for scanning. |
46
+ | `ticket-description` | Draft ticket/issue descriptions with clear sections, project-context research, clarity checks, and bold+italic emphasis for scanning. |
47
47
  | `split-overlarge-pr` | Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main. |
48
48
 
49
49
  **opencode-only (1)** — the coordinator needs sub-agent support:
50
50
 
51
51
  | Skill | Role |
52
52
  |-------|------|
53
- | `thatch-code-review` | Resolve review target (incl. VCS detection and connected PR/MR lookup for follow-up round detection), gather project context, research affected workflows, estimate complexity, partition, dispatch the 6 specialists in parallel, synthesize (incl. cross-referencing findings against prior review comments). |
53
+ | `thatch-code-review` | Resolve review target (incl. VCS detection and connected PR/MR lookup for follow-up round detection), gather project context, research affected workflows, estimate complexity, partition, dispatch the 6 specialists in parallel, synthesize with a workflow-change preface and prior-comment cross-reference. |
54
54
 
55
55
  ## REVIEW_COMMON
56
56
 
@@ -115,7 +115,7 @@ and `--cursor` pass only the shared set.
115
115
  ## Memory review skills in practice
116
116
 
117
117
  - **Quick single lens**: load any specialist directly and point it at a branch.
118
- - **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all 6 specialists in parallel (with both the context brief and workflow guide injected into each briefing), then synthesizes.
118
+ - **Full review on opencode**: load `thatch-code-review` — it gathers project context, researches affected workflows, dispatches all 6 specialists in parallel (with both the context brief and workflow guide injected into each briefing), then synthesizes a report that starts with the workflow changes before findings.
119
119
  - **Full review on Claude Code/Cursor**: run each specialist in sequence, then
120
120
  run `thatch-review-synthesizer` to verify and aggregate.
121
121
 
@@ -174,7 +174,7 @@ Six specialist review lenses, each a self-contained static-analysis pass:
174
174
  | `thatch-review-no-slop` | AI writing anti-patterns: change narration, fourth wall breaks, em dashes, hedging, filler. |
175
175
  | `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
176
176
  | `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
177
- | `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a single deduplicated, severity-grouped report. |
177
+ | `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a report that starts with workflow changes, then deduplicated severity-grouped findings. |
178
178
  | `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, memory) before a review. Prevents false positives about intentionally deferred work. |
179
179
  | `thatch-workflow-research` | Researches code workflows and features affected by a change or planned change. Reads code flows, comments, git history, and produces a guide for reviewers or planners. |
180
180
  | `thatch-change-walkthrough` | Explains a change to the user as a teaching walkthrough: researches each affected workflow at the merge-base, teaches current behavior, then overlays the modifications with file:line citations. |
@@ -184,15 +184,15 @@ Six specialist review lenses, each a self-contained static-analysis pass:
184
184
 
185
185
  | Skill | Purpose |
186
186
  |-------|---------|
187
- | `pr-description` | Drafts PR descriptions using instructional-design scaffolding (SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES) with bold and italic emphasis for scanning. |
188
- | `ticket-description` | Drafts ticket or issue descriptions (Linear or Jira) using instructional-design scaffolding with bold and italic emphasis for scanning. |
187
+ | `pr-description` | Drafts PR descriptions with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, project-context research, clarity checks, and bold/italic emphasis for scanning. |
188
+ | `ticket-description` | Drafts ticket or issue descriptions (Linear or Jira) with clear sections, project-context research, clarity checks, and bold/italic emphasis for scanning. |
189
189
  | `split-overlarge-pr` | Splits already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main. |
190
190
 
191
191
  ### opencode-only skills
192
192
 
193
193
  | Skill | Purpose |
194
194
  |-------|---------|
195
- | `thatch-code-review` | Multi-agent review coordinator. Dispatches parallel sub-agents for triage, decomposition, specialist fan-out, and synthesis. Not available in Claude Code (requires sub-agent support). |
195
+ | `thatch-code-review` | Multi-agent review coordinator. Dispatches parallel sub-agents for triage, decomposition, specialist fan-out, and synthesis with a workflow-change preface. Not available in Claude Code (requires sub-agent support). |
196
196
 
197
197
  ### Host availability
198
198
 
@@ -222,7 +222,8 @@ Load thatch-code-review and review branch feature-x.
222
222
  ```
223
223
 
224
224
  The coordinator will triage the change, dispatch parallel sub-agents (one per
225
- specialist lens), and synthesize a final report.
225
+ specialist lens), and synthesize a final report. The report starts with the
226
+ workflow-level changes so the findings have context.
226
227
 
227
228
  For a **full review on Claude Code** (or without the coordinator), run each
228
229
  specialist in sequence, then synthesize:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffober/thatch",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
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/prompts.ts CHANGED
@@ -46,8 +46,8 @@ workflows. The host auto-discovers them, but reach for them proactively:
46
46
  - \`thatch-session-reflection\` — record what you learned at end of session.
47
47
  - \`thatch-fact-extractor\` — extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
48
48
  - \`thatch-dedup-classifier\` — resolve duplicate memory pairs from \`thatch_find_duplicates\`.
49
- - \`pr-description\` — draft a PR description using instructional-design scaffolding with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story.
50
- - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) using instructional-design scaffolding with bold and italic emphasis for scanning.
49
+ - \`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.
50
+ - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
51
51
  - \`split-overlarge-pr\` — split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
52
52
 
53
53
  ## When to Write
@@ -85,6 +85,14 @@ about their preferences:
85
85
  2. Use thatch_prediction_update to create, reinforce, or weaken a prediction
86
86
  3. Use thatch_prediction_delete to remove a prediction created in error
87
87
 
88
+ Code review discussions are high-signal prediction material. When working
89
+ through potential review comments with the user, watch for preferences about
90
+ review threshold, severity, tone, evidence, scope, false positives, or what is
91
+ worth posting. This applies whether the user invoked a review skill, is
92
+ reviewing your changes, or asked you to review their changes or another LLM's
93
+ changes. Before creating a new prediction, query for an existing one and
94
+ reinforce or adjust it when possible.
95
+
88
96
  ## What to Store
89
97
 
90
98
  - **Global store**: user observations, agent personality, system environment
@@ -212,8 +220,8 @@ workflows. The host auto-discovers them, but reach for them proactively:
212
220
  - \`thatch-session-reflection\` — record what you learned at end of session.
213
221
  - \`thatch-fact-extractor\` — extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
214
222
  - \`thatch-dedup-classifier\` — resolve duplicate memory pairs from \`find_duplicates\`.
215
- - \`pr-description\` — draft a PR description using instructional-design scaffolding with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story.
216
- - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) using instructional-design scaffolding with bold and italic emphasis for scanning.
223
+ - \`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.
224
+ - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
217
225
  - \`split-overlarge-pr\` — split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
218
226
 
219
227
  ## When to Write
@@ -251,6 +259,14 @@ about their preferences:
251
259
  2. Use prediction_update to create, reinforce, or weaken a prediction
252
260
  3. Use prediction_delete to remove a prediction created in error
253
261
 
262
+ Code review discussions are high-signal prediction material. When working
263
+ through potential review comments with the user, watch for preferences about
264
+ review threshold, severity, tone, evidence, scope, false positives, or what is
265
+ worth posting. This applies whether the user invoked a review skill, is
266
+ reviewing your changes, or asked you to review their changes or another LLM's
267
+ changes. Before creating a new prediction, query for an existing one and
268
+ reinforce or adjust it when possible.
269
+
254
270
  ## What to Store
255
271
 
256
272
  - **Global store**: user observations, agent personality, system environment
@@ -440,8 +456,8 @@ workflows. The host auto-discovers them, but reach for them proactively:
440
456
  - \`thatch-session-reflection\` — record what you learned at end of session.
441
457
  - \`thatch-fact-extractor\` — extract durable facts from recent tool interactions (auto-triggered by the extraction pipeline).
442
458
  - \`thatch-dedup-classifier\` — resolve duplicate memory pairs from \`find_duplicates\`.
443
- - \`pr-description\` — draft a PR description using instructional-design scaffolding with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story.
444
- - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) using instructional-design scaffolding with bold and italic emphasis for scanning.
459
+ - \`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.
460
+ - \`ticket-description\` — draft a ticket, issue, or work item (Linear or Jira) with clear sections and bold/italic emphasis for scanning.
445
461
  - \`split-overlarge-pr\` — split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main.
446
462
 
447
463
  ## When to Write
@@ -479,6 +495,14 @@ about their preferences:
479
495
  2. Use prediction_update to create, reinforce, or weaken a prediction
480
496
  3. Use prediction_delete to remove a prediction created in error
481
497
 
498
+ Code review discussions are high-signal prediction material. When working
499
+ through potential review comments with the user, watch for preferences about
500
+ review threshold, severity, tone, evidence, scope, false positives, or what is
501
+ worth posting. This applies whether the user invoked a review skill, is
502
+ reviewing your changes, or asked you to review their changes or another LLM's
503
+ changes. Before creating a new prediction, query for an existing one and
504
+ reinforce or adjust it when possible.
505
+
482
506
  ## What to Store
483
507
 
484
508
  - **Global store**: user observations, agent personality, system environment