@jeffober/thatch 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +4 -2
  2. package/artifacts/skills/thatch-fact-extractor.md +1 -1
  3. package/artifacts/skills/thatch-memory-verify.md +2 -2
  4. package/artifacts/skills/thatch-plan-refinement.md +3 -2
  5. package/artifacts/skills/thatch-refine-infra.md +66 -0
  6. package/artifacts/skills/thatch-refine-oss-contribution.md +68 -0
  7. package/artifacts/skills/thatch-refine-personal.md +61 -0
  8. package/artifacts/skills/thatch-refine-shared-lib.md +69 -0
  9. package/artifacts/skills/thatch-refine-spike.md +53 -0
  10. package/artifacts/skills/thatch-refine-team-app.md +69 -0
  11. package/artifacts/skills/thatch-refine.md +84 -0
  12. package/docs/dev/README.md +11 -7
  13. package/docs/dev/features/cross-session-chat.md +8 -1
  14. package/docs/dev/features/memory-store.md +1 -1
  15. package/docs/dev/features/nudge-pipeline.md +12 -0
  16. package/docs/dev/features/opencode-plugin.md +1 -1
  17. package/docs/dev/features/session-lifecycle.md +1 -1
  18. package/docs/dev/gotchas.md +71 -1
  19. package/docs/dev/mcp-parity.md +1 -1
  20. package/docs/dev/setup-and-hooks.md +1 -1
  21. package/docs/dev/skills.md +8 -1
  22. package/docs/user/README.md +8 -1
  23. package/docs/user/commands.md +8 -0
  24. package/docs/user/memory.md +1 -1
  25. package/docs/user/skills.md +12 -0
  26. package/package.json +1 -1
  27. package/src/chat.ts +17 -0
  28. package/src/commands.ts +23 -3
  29. package/src/db.ts +77 -12
  30. package/src/extraction.ts +89 -3
  31. package/src/index.ts +45 -0
  32. package/src/opencode/v2.ts +48 -4
  33. package/src/prompts.ts +118 -30
  34. package/src/runtime.ts +271 -72
  35. package/src/skills.ts +7 -0
  36. package/src/tool-defs.ts +156 -28
  37. package/src/watchers.ts +14 -0
package/README.md CHANGED
@@ -194,8 +194,10 @@ Thatch gives your agent:
194
194
  auto-joining with `chat.autoRegister: false`).
195
195
  - **Slash commands** -- `/thatch/defrag` (consolidate duplicate memories),
196
196
  `/thatch/extract` (drain the extraction queue now), `/thatch/hygiene`
197
- (tend stale and orphaned memories), and `/thatch/reflect` (persist what
198
- the session learned) run on demand the same behaviors the nudges run on
197
+ (tend stale and orphaned memories), `/thatch/reflect` (persist what
198
+ the session learned), and `/thatch/refine` (refine a plan under the
199
+ project type's requirements, classifying the project first) run on
200
+ demand. The first four mirror the same behaviors the nudges run on
199
201
  their own schedule. Plus the opencode-only wrap-ups: `/thatch/compact` and
200
202
  `/thatch/exit` run a pre-flight checklist before a compaction or an exit:
201
203
  the agent flushes pending fact extraction, finishes promised memory
@@ -18,7 +18,7 @@ The extraction nudge or dispatch prompt will give you a session ID. Call `get_ex
18
18
  4. Apply the durability test before saving: will this still be true and useful in a future session that knows nothing about this branch, commit, or session? If not, skip it. Do not store point-in-time values (migration indices, line numbers, file counts), commit hashes or branch history narratives (git is the source of truth), or anything re-derivable from the codebase faster than recalling it.
19
19
  5. Write for a future session with zero current context. No "we", "our session", "just now".
20
20
  6. Call `extraction_done` (with `session_id` set to the parent session's ID from the nudge) to mark the run complete. Do this even when nothing was worth saving: the parent session holds the buffered interactions until a completion signal arrives, and a memory write is not one on a no-save run.
21
- 7. Your final message must be exactly: "Extraction complete." — do not list or summarize what you saved. The memories are in the store; the parent session does not need a report.
21
+ 7. Your final message must be exactly: "Extraction complete. This is the extractor's final report - a background-task completion, not an extraction nudge; the buffer is drained. Never re-dispatch an extractor because a completion arrived - a new extraction nudge is the only dispatch signal." - do not list or summarize what you saved. The memories are in the store; the parent session does not need a report. The frame rides with the completion on purpose: a bare "Extraction complete." was indistinguishable from nudge traffic mid-loop, and the parent model misread it as new work (the September 2026 re-dispatch loop).
22
22
 
23
23
  ## What to extract
24
24
 
@@ -20,7 +20,7 @@ This skill is the catch.
20
20
 
21
21
  Call `thatch_memory_show` with the label (or accept the memory content directly if dispatched by a coordinator that already read it).
22
22
 
23
- Note the `created_at` and `updated_at` dates. A memory that was last updated recently is less likely to be stale than one that has not been touched in months.
23
+ Note the age line ("This memory was last updated N ago"). A memory that was last updated recently is less likely to be stale than one that has not been touched in months.
24
24
 
25
25
  ## Step 2: Classify Claims
26
26
 
@@ -111,6 +111,6 @@ If no corrections were needed, report "all claims verified, no updates needed."
111
111
 
112
112
  # Proactive Use
113
113
 
114
- When `thatch_memory_show` or `thatch_memory_recall` returns a memory with an old `updated_at` date (more than a few weeks), consider loading this skill to fact-check it before relying on its code-related claims. The `updated_at` date is included in the memory output for this purpose.
114
+ When `thatch_memory_show` or `thatch_memory_recall` returns a memory whose age line shows it has not been updated in a while (more than a few weeks), consider loading this skill to fact-check it before relying on its code-related claims. The age prose ("This memory was last updated N ago") is included in the memory output for this purpose.
115
115
 
116
116
  This is not mandatory for every old memory. Use judgment: a memory about a stable architectural decision may be fine for months, while a memory about file locations or function names is more likely to drift.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: thatch-plan-refinement
3
- description: Refine a plan for a code change by dispatching a fresh-context reviewer subagent to hunt for gaps, unverified premises, and unexpected side effects, then revising and re-reviewing until consensus. Use when a plan is about to be implemented, when the user asks to refine, stress-test, or double-check a plan, or after a plan revision that incorporated prior findings. Quick mode is one fresh reviewer per round; deep mode adds a specialist lens fan-out (reuse, alternatives, hidden problems, safe-to-modify, archaeology).
3
+ description: Refine a plan for a code change by dispatching a fresh-context reviewer subagent to hunt for gaps, unverified premises, and unexpected side effects, then revising and re-reviewing until consensus. Use when a plan is about to be implemented, when the user asks to refine, stress-test, or double-check a plan, or after a plan revision that incorporated prior findings. This is the generic core loop; when the project type should shape the refinement bar, load thatch-refine instead and it will apply a type delta on top of this loop. Quick mode is one fresh reviewer per round; deep mode adds a specialist lens fan-out (reuse, alternatives, hidden problems, safe-to-modify, archaeology).
4
4
  ---
5
5
 
6
6
  You are refining a plan before code exists. A plan written by the same context that researched the problem inherits that context's blind spots. A reviewer with no stake in the plan and no memory of writing it finds what the author cannot. Refinement is the loop: draft, review, revise, repeat until consensus. Each pass tightens the plan; a round with no findings means the plan is done, not that the loop failed.
@@ -75,7 +75,8 @@ One reviewer per round in quick mode; one lens fan-out total in deep mode, then
75
75
 
76
76
  ## Relationship to other skills
77
77
 
78
- - **`thatch-code-archaeology`** — the research skill for understanding the code; its output is often the plan's input. The archaeology lens is a targeted, plan-scoped re-run of its git-history step, not a replacement for it.
78
+ - **`thatch-refine`** - the type-aware entry point. Different project types need different refinement bars: a team codebase owes coordination and breadcrumbs, a personal project allows cleverness, a shared library owes API hygiene. When the user runs `/thatch/refine` or the project's type should shape the bar, load `thatch-refine` first; it classifies and hands back a thatch-refine-* delta to apply on top of this loop. This skill stays the generic core.
79
+ - **`thatch-code-archaeology`** - the research skill for understanding the code; its output is often the plan's input. The archaeology lens is a targeted, plan-scoped re-run of its git-history step, not a replacement for it.
79
80
  - **`thatch-coding-workflow`** — the procedure skill for executing the refined plan. Refinement ends where coding-workflow begins.
80
81
  - **`thatch-ticket-description` / `thatch-pr-description`** — if the refined plan feeds a ticket or PR description (or the session iterated on one using this skill), RE-LOAD the appropriate writing skill and draft within its contract. A plan is a working artifact for the session that wrote it; a ticket or PR description is a reader-facing document with its own sections, verbosity budget, and prose rules. Refinement output — findings, accepted risks, review rounds — is SOURCE MATERIAL for those skills, never a substitute for them. This holds the right level of detail for the medium and keeps the writing clear.
81
82
  - **`thatch-clear-writing`** — for any other human-facing text produced along the way (reports, comments, docs).
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: thatch-refine-infra
3
+ description: Type-specific requirements for refining a plan that touches infrastructure (CI pipelines, Terraform, Kubernetes manifests, build and deploy configuration). Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. Use when a wrong premise can break deploys or pipelines for everyone downstream.
4
+ ---
5
+
6
+ You are refining a plan for an **infra** change: CI pipelines, Terraform,
7
+ Kubernetes manifests, build and deploy configuration. The governing value
8
+ is blast radius: a wrong premise here does not break one feature, it
9
+ breaks every pipeline, environment, or developer downstream of it, often
10
+ silently and often for everyone at once. Load `thatch-plan-refinement`
11
+ for the core loop and apply the deltas below; where they disagree, these
12
+ win.
13
+
14
+ ## What this type owes
15
+
16
+ - **Near-absolute pattern-following.** Configuration is the worst place
17
+ for novelty. Copy the established pattern from a sibling pipeline,
18
+ module, or manifest even when a better one exists; propose the better
19
+ one as its own change, after this one lands.
20
+ - **Rollback as a first-class deliverable.** Every change names how it
21
+ backs out, concretely (which command, which revert, which state to
22
+ re-apply), not "revert the commit if problems arise."
23
+ - **Staged verification.** The plan verifies against a non-production
24
+ target first (staging environment, a canary job, a dry-run or plan
25
+ output) and names what a successful verification looks like before
26
+ production applies it.
27
+
28
+ ## How this changes the loop
29
+
30
+ - **Deep mode is the default.** Infra changes almost always touch shared
31
+ persistent state that other consumers read, which is the core skill's
32
+ first deep-mode trigger.
33
+ - **Premises verify against live state, not memory.** The most dangerous
34
+ infra premise is "the current setup is X" recalled from memory. Check
35
+ the actual manifests, the actual pipeline config, the actual running
36
+ versions, and cite where you checked. Terraform drift and manual
37
+ console changes make memory especially unreliable here.
38
+ - **Consensus is unchanged**, but the reviewer prompt should emphasize
39
+ checking the rollback and verification sections explicitly.
40
+
41
+ ## Lens weights
42
+
43
+ - **Hidden problems (pre-mortem) dominates.** The question is "who reads
44
+ this state that the plan does not know about?" - dependent pipelines,
45
+ environments sharing the module, developers relying on cache behavior,
46
+ jobs relying on timing. Enumerate the dependents by reading what
47
+ actually references the resource, not by recollection.
48
+ - **Safe-to-modify is second.** An infra change landing in untested
49
+ configuration without a verification step is a finding.
50
+ - **Alternatives and pattern/reuse mostly skip.** The pattern question
51
+ was answered above: follow it.
52
+
53
+ ## Extra plan sections
54
+
55
+ - **Rollback plan.** Concrete and executable, as above.
56
+ - **Verification step.** What runs in staging or dry-run first, and what
57
+ result counts as safe to proceed.
58
+ - **Sequencing.** Infra changes often must land in an order (create
59
+ before reference, drain before delete). The plan states the order and
60
+ what breaks if it is violated.
61
+
62
+ ## Docs bar
63
+
64
+ A one-paragraph change note for the team (what changed, why, how to
65
+ roll back) is the deliverable. Config comments explain constraints the
66
+ next person must not violate.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: thatch-refine-oss-contribution
3
+ description: Type-specific requirements for refining a plan for a contribution to an open source repository the user does not maintain. Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. The maintainer's design authority and house style govern, and the diff stays minimal.
4
+ ---
5
+
6
+ You are refining a plan for an **oss-contribution**: a change to a
7
+ repository the user does not maintain. The governing value is the
8
+ maintainer's design authority. It is their codebase; the contribution
9
+ that gets merged is the one that fits their intent, not the one that
10
+ would be best by your lights. Load `thatch-plan-refinement` for the core
11
+ loop and apply the deltas below; where they disagree, these win.
12
+
13
+ ## What this type owes
14
+
15
+ - **Conform to house style, even when it is worse.** A foreign codebase's
16
+ conventions are not up for improvement in this change. Do not import
17
+ patterns from other projects; do not refactor what the maintainer
18
+ wrote.
19
+ - **Minimal diff.** No drive-by refactors, no reformatting of untouched
20
+ lines, no new dependencies, no new abstractions beyond what the change
21
+ strictly needs.
22
+ - **The discussion comes first.** Significant design work waits until the
23
+ approach has a maintainer's nod: check CONTRIBUTING.md, search open
24
+ and closed issues and PRs for the same idea, and file or comment on
25
+ the proposal before investing in the implementation. A plan that
26
+ assumes acceptance is building on an unverified premise.
27
+
28
+ ## How this changes the loop
29
+
30
+ - **Add a premise class: upstream status.** Every plan premise about the
31
+ maintainer's intent (is this wanted, is the approach acceptable, is
32
+ the issue still open) needs evidence: an issue thread, a maintainer
33
+ comment, a CONTRIBUTING instruction. No evidence means "unknown -
34
+ ask upstream," and the plan gates on that question, not on a guess.
35
+ - **Consensus adds one test.** Alongside the core skill's consensus
36
+ criteria, the reviewer answers: "would a maintainer accept this
37
+ scope?" Scope findings are blockers. A contribution that solves the
38
+ issue plus three adjacent problems will sit unmerged.
39
+ - **Round cap unchanged.** But a plan blocked on upstream discussion
40
+ pauses for the user to have that conversation; it does not loop.
41
+
42
+ ## Lens weights
43
+
44
+ - **Pattern and reuse inverts.** In team code, existing patterns are a
45
+ strong default; here they are the requirement. A "better" pattern than
46
+ the house style is a finding against the plan, not for it.
47
+ - **Hidden problems shrinks.** Consumers of internal state are the
48
+ maintainer's concern. Focus on the change's own footprint and its
49
+ interaction with in-flight upstream work (search open PRs for overlap).
50
+ - **Alternatives mostly skips.** The maintainer chose the architecture.
51
+ The plan's job is fitting into it, and where the plan needs a
52
+ maintainer decision, that is an upstream question, not an alternatives
53
+ survey.
54
+
55
+ ## Extra plan sections
56
+
57
+ - **Upstream discussion.** The issue or thread this change responds to,
58
+ and the maintainer signals (or absence of them) the plan relies on.
59
+ - **House-style conformance.** The specific conventions the change will
60
+ follow, read from the project's own CONTRIBUTING and recent merged
61
+ PRs, not assumed.
62
+
63
+ ## Docs bar
64
+
65
+ Match the project's own documentation conventions for any user-facing
66
+ text (changelog entries, docs pages) and the house code-comment style.
67
+ The writing skills still govern clarity, but the structure and tone
68
+ follow the project's.
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: thatch-refine-personal
3
+ description: Type-specific requirements for refining a plan in a solo personal project with no downstream consumers. Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. Relaxes coordination requirements and allows cleverness and experimentation, while keeping premise verification honest.
4
+ ---
5
+
6
+ You are refining a plan for a **personal** project: solo code with no
7
+ downstream consumers. The coordination constraints that govern team code
8
+ are relaxed. This is the place to show off cleverness and experiment with
9
+ interesting techniques that would be inconsiderate in a shared codebase.
10
+ Load `thatch-plan-refinement` for the core loop and apply the deltas
11
+ below; where they disagree, these win.
12
+
13
+ ## What this type owes
14
+
15
+ - **Almost nothing to anyone else.** No consistency obligation to
16
+ teammates, no reviewer to orient, no downstream API to protect.
17
+ - **Still honest about facts.** Relaxed style does not mean relaxed
18
+ reality: every factual premise still carries a verified `file:line`
19
+ citation, and "unverified" is still marked. A plan built on a wrong
20
+ premise wastes your time in any project.
21
+
22
+ ## How this changes the loop
23
+
24
+ - **The skip threshold drops.** Most personal-project plans can be tried
25
+ faster than they can be refined. Skip refinement whenever the change is
26
+ cheap to build and cheaper to rewrite; run the loop only when the plan
27
+ touches something expensive to get wrong (persistent state, a
28
+ hard-to-reverse migration, hours of build effort).
29
+ - **Fewer rounds.** One quiet review round is enough consensus. The cap
30
+ drops from three rounds to two; a personal plan that has not converged
31
+ by then should just be built or abandoned.
32
+ - **Degraded review is fine.** If the host cannot dispatch sub-agents, a
33
+ same-context self-review pass is usually enough. Saying so out loud, as
34
+ the core skill requires, is still worthwhile but the stakes are lower.
35
+
36
+ ## Lens weights
37
+
38
+ - **Premise verification is the only load-bearing lens.** The fresh
39
+ reviewer's core job is checking the plan's factual model of the code.
40
+ - **Pattern and reuse mostly skips.** There is no team to stay consistent
41
+ with. Flag reuse only when reinventing an existing wheel will genuinely
42
+ bite future-you.
43
+ - **Alternatives turns exploratory.** The question shifts from "what is
44
+ safest?" to "what would I learn?" - one alternative worth trying for
45
+ the technique is a valid result even when the plan's choice is fine.
46
+ - **Hidden problems shrinks to future-self.** The only consumer to
47
+ enumerate is you, six months from now, with no memory of this code.
48
+
49
+ ## Extra plan sections
50
+
51
+ None required. Blast radius, migration plans, and reviewer orientation
52
+ sections are skipped unless the change is in the expensive-to-get-wrong
53
+ category that triggered refinement at all.
54
+
55
+ ## Docs bar
56
+
57
+ - Future-self breadcrumbs only: comment the surprising spots, not the
58
+ obvious ones.
59
+ - When a plan deliberately uses an experimental technique, record that in
60
+ one line (in the plan or a comment) so a future session knows the
61
+ oddity was chosen, not accidental.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: thatch-refine-shared-lib
3
+ description: Type-specific requirements for refining a plan that touches a library's API surface, in any repo, including personal ones. Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. Use whenever exported API, published packages, or downstream consumers are involved; API hygiene governs even solo projects.
4
+ ---
5
+
6
+ You are refining a plan for a **shared-lib** change: work that touches an
7
+ API other code consumes and keeps working against. This applies to any
8
+ library with external callers, including a personal one. The governing
9
+ value is API hygiene: you are writing for consumers you cannot see and
10
+ cannot call back. Load `thatch-plan-refinement` for the core loop and
11
+ apply the deltas below; where they disagree, these win.
12
+
13
+ ## What this type owes
14
+
15
+ - **Flexible on input, strict on output.** Accept broad input types and
16
+ normalize them; return precise, well-defined types and never leak
17
+ internal representations. Callers write code against your output
18
+ shapes; widen what you accept, pin down what you emit.
19
+ - **Keep special cases out of the API.** No caller-specific knobs, no
20
+ one-off escape hatches, no parameters that exist for exactly one
21
+ consumer. A special case is a design smell: handle it inside the
22
+ implementation or reject it at the boundary.
23
+ - **Do not foreclose caller options.** Prefer returning data over making
24
+ decisions callers might want to make differently. Every shortcut the
25
+ library takes on the caller's behalf is a wall they hit later.
26
+ - **Keep the surface small.** Every export is a permanent maintenance
27
+ promise. The best API change is often the one that exports nothing new.
28
+
29
+ ## How this changes the loop
30
+
31
+ - **Deep mode is the default** for anything that adds, changes, or
32
+ removes an export. The abstraction gets locked in at ship time; after
33
+ release, changing it costs every consumer. This is the last cheap
34
+ moment to get the shape right.
35
+ - **Alternatives works harder here.** "No better alternative found" must
36
+ be argued harder than the core skill's paragraph: enumerate the
37
+ plausible alternative shapes and say why the plan's shape wins for
38
+ callers, not just for the implementation.
39
+ - **Backward compatibility findings are blockers by default.** A breaking
40
+ change without a deprecation path is a blocker, not a should-fix.
41
+
42
+ ## Lens weights
43
+
44
+ - **Hidden problems reframes entirely.** Every consumer is a stranger;
45
+ you cannot grep your callers. Enumerate the contract the plan changes
46
+ and reason about the population of consumers you cannot see, including
47
+ the ones using the API in ways you never intended.
48
+ - **Pattern and reuse applies to your own API first.** Consistency with
49
+ the library's existing API conventions is its own requirement: a
50
+ second method that disagrees with the first in naming or shape is a
51
+ finding even when both are internally fine.
52
+
53
+ ## Extra plan sections
54
+
55
+ - **API surface diff.** Exactly what is exported, added, changed, or
56
+ removed, in a list a reviewer can check one line at a time.
57
+ - **Semver impact and deprecation path.** The version bump this deserves,
58
+ what is deprecated, and how callers migrate.
59
+ - **External documentation.** The docs and examples this change requires,
60
+ written for the reader: what the behavior is, when to use it, what it
61
+ does not do. "I'll document it later" is a finding.
62
+ - **Caller migration notes.** For breaking or behavior-changing exports,
63
+ the note that goes in the changelog.
64
+
65
+ ## Docs bar
66
+
67
+ Reader-facing documentation is a plan deliverable, not a follow-up. Draft
68
+ it under the writing skills' contracts: define terms on first use,
69
+ behavior stated precisely enough that a caller needs no source dive.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: thatch-refine-spike
3
+ description: Type-specific requirements for refining a plan for a throwaway prototype or time-boxed spike. Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. Skips almost all of the loop, verifying only the premises the experiment's conclusion depends on.
4
+ ---
5
+
6
+ You are refining a plan for a **spike**: throwaway code whose purpose is
7
+ answering a question, not producing a maintained artifact. Almost all of
8
+ the refinement loop is waste here. Load `thatch-plan-refinement` for the
9
+ core loop, then apply the deltas below; where they disagree, these win.
10
+
11
+ ## What this type owes
12
+
13
+ - **A stated question.** The plan opens with the question the spike
14
+ exists to answer, stated concretely enough that "done" is checkable
15
+ ("can Postgres full-text search handle our query volume?" not "explore
16
+ search options").
17
+ - **A promotion test.** The plan states what would make this code worth
18
+ promoting into the real codebase versus rewriting it properly. Most
19
+ spikes end in a rewrite, and that is a success, not a failure.
20
+ - **A time box.** The plan names its budget: hours or days, not open-
21
+ ended effort.
22
+
23
+ ## How this changes the loop
24
+
25
+ - **Skip the loop by default.** No reviewer dispatch, no rounds, no
26
+ consensus machinery. One focused self-review pass is the whole
27
+ refinement: check the plan's few load-bearing premises, then build.
28
+ - **Verify only conclusion-bearing premises.** The spike's conclusion is
29
+ only as good as the premises it depends on. If the experiment claims
30
+ "this approach is too slow," the benchmark setup and the
31
+ representativeness of the test data are the premises that matter, and
32
+ they get the verified-citation treatment. Everything else is
33
+ throwaway.
34
+ - **Degraded review needs no apology.** The core skill's honest-degradation
35
+ notice is unnecessary; there is no real review to degrade.
36
+
37
+ ## Lens weights
38
+
39
+ All specialist lenses skip except one consideration: **is the spike
40
+ actually throwaway?** If the plan quietly assumes the prototype code will
41
+ survive into production, stop and surface that. A spike that is really a
42
+ production change wearing a costume should be refined under the type it
43
+ actually is.
44
+
45
+ ## Extra plan sections
46
+
47
+ - The question, the promotion test, and the time box above. Nothing else.
48
+
49
+ ## Docs bar
50
+
51
+ No breadcrumb obligation. One comment or note recording the question and
52
+ the answer is enough. The spike's real output is the answer, and it
53
+ should be written down where the user will find it.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: thatch-refine-team-app
3
+ description: Type-specific requirements for refining a plan in a multi-developer team codebase (production app or service shared by a team). Loaded by thatch-refine after classification; assumes the core loop in thatch-plan-refinement. Use when coordination cost, consistency, and reviewer comprehension are the governing constraints.
4
+ ---
5
+
6
+ You are refining a plan for a **team-app** project: production code in a
7
+ repository where multiple developers ship, review, and maintain each
8
+ other's work. The governing value is org velocity through coordination and
9
+ consistency. Code is read far more often than it is written, and most of
10
+ its readers did not write it. Load `thatch-plan-refinement` for the core
11
+ loop and apply the deltas below; where they disagree, these win.
12
+
13
+ ## What this type owes
14
+
15
+ - **Consistency outranks local optimality.** Following the codebase's
16
+ existing pattern beats a "better" one that splits the codebase in two.
17
+ A novel approach must justify the divergence it imposes on every future
18
+ reader, not just prove it is cleverer.
19
+ - **Implement for the junior reviewer.** The bar is that a developer with
20
+ no history in this area can review the change and debug it at 2am.
21
+ Cleverness is allowed only with a justification comment at the point of
22
+ cleverness, and only when the payoff is real.
23
+ - **Intent is a deliverable.** Docstrings and comments are the breadcrumb
24
+ trail for the next maintainer. The plan says which comments and
25
+ docstrings it will write, and *why* is documented, not just *what*.
26
+
27
+ ## How this changes the loop
28
+
29
+ - **Mode triage stays strict.** The skip threshold does not relax for
30
+ team code: anything another developer must review earns at least quick
31
+ mode. Established-pattern changes with no design decisions can still
32
+ skip, as the core skill already provides.
33
+ - **Deep mode triggers broaden.** Beyond the core skill's triggers, deep
34
+ mode is warranted when the change alters a contract other teams build
35
+ on, or lands in an area with a history of review churn.
36
+ - **Consensus is unchanged.** Same rounds, same cap, same escalation to
37
+ the user.
38
+
39
+ ## Lens weights
40
+
41
+ - **Hidden problems (pre-mortem) carries the most signal.** In team code
42
+ the plan's biggest risk is an unenumerated consumer or an implicit
43
+ contract another team relies on.
44
+ - **Safe-to-modify is second.** A plan that lands in an untested,
45
+ tangled section without a refactor-first dependency is a finding.
46
+ - **Pattern and reuse tightens.** "Reuse the existing pattern" is the
47
+ default verdict, not one option among several. A plan that introduces a
48
+ parallel way to do something the codebase already does needs a strong,
49
+ evidenced reason.
50
+ - **Alternatives stays a filter.** Two alternatives, one paragraph each,
51
+ as the core skill says; the judgment criterion is team cost, not
52
+ personal preference.
53
+
54
+ ## Extra plan sections
55
+
56
+ - **Blast radius and consumers.** Who reads the state, tables, config, and
57
+ symbols this change touches, including other teams and services.
58
+ - **Migration and rollback.** How the change ships safely and how it
59
+ backs out.
60
+ - **Intent breadcrumbs.** The docstrings and comments the implementation
61
+ will write, and what future-reader question each answers.
62
+ - **Reviewer orientation.** One paragraph a reviewer can read first: what
63
+ changed, why, and where to look.
64
+
65
+ ## Docs bar
66
+
67
+ Comments and docstrings are part of the definition of done, and any
68
+ reader-facing text produced along the way (PR description, ticket,
69
+ changelog entry) is drafted under the writing skills' contracts.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: thatch-refine
3
+ description: Classify the current project (audience, lifecycle, surface) and refine a plan under that type's requirements. Entry point for the thatch-refine-* family. Use when the user asks to refine a plan, runs /thatch/refine, or when a plan is about to be implemented and the project type should shape the refinement bar. For a bare "refine this plan" request, load this skill rather than thatch-plan-refinement directly - the router picks the type and applies its delta on top of the core loop.
4
+ ---
5
+
6
+ You are the entry point for project-type-aware plan refinement. The core
7
+ refinement loop (draft, fresh-context reviewer, revise, consensus) is the
8
+ same everywhere; it lives in `thatch-plan-refinement`. What changes by
9
+ project type is the bar: which lenses matter, what the plan must contain,
10
+ how much documentation is owed, and when skipping refinement is honest.
11
+
12
+ ## The types
13
+
14
+ | Type | Governing value | Skill |
15
+ |------|-----------------|-------|
16
+ | `team-app` | Coordination and consistency promote org velocity | `thatch-refine-team-app` |
17
+ | `personal` | Freedom to experiment; low coordination cost | `thatch-refine-personal` |
18
+ | `shared-lib` | API hygiene; never foreclose caller options | `thatch-refine-shared-lib` |
19
+ | `spike` | Answering a question cheaply, not producing code | `thatch-refine-spike` |
20
+ | `infra` | Blast radius across pipelines and environments | `thatch-refine-infra` |
21
+ | `oss-contribution` | The maintainer's design authority | `thatch-refine-oss-contribution` |
22
+
23
+ ## Classification
24
+
25
+ Classify on three axes, then pick the type whose requirements this plan
26
+ must satisfy. Classify **the change**, not just the repo: a personal repo
27
+ gaining a published API is a `shared-lib` plan for that change, even if the
28
+ repo is `personal` overall.
29
+
30
+ **Audience** - who reads and maintains this code.
31
+
32
+ - Solo: one contributor in git history, no CODEOWNERS, no required reviews.
33
+ - Team: CODEOWNERS, CONTRIBUTING.md, required PR review, multiple regular
34
+ authors.
35
+ - Public: published package (npm/PyPI/etc. metadata, `publishConfig`), or
36
+ consumers outside the repo you cannot enumerate.
37
+
38
+ **Lifecycle** - what this code owes anyone.
39
+
40
+ - Production: protected main, CI gates, deploy configuration, semver
41
+ discipline.
42
+ - Experimental: active WIP, churny main, thin or absent tests.
43
+ - Throwaway: a question wearing a repository.
44
+
45
+ **Surface** - what the change lives in.
46
+
47
+ - Application: end-user or service code with no downstream importers.
48
+ - Library: exported API that other code imports and keeps working against.
49
+ - Infrastructure: CI, Terraform, k8s manifests, build and deploy config.
50
+
51
+ Signals to gather (all cheap and read-only): `git log --format="%an" |
52
+ sort -u | head`, presence of CODEOWNERS / CONTRIBUTING.md / required
53
+ review config, package.json `private` and `publishConfig` fields, the
54
+ publishing config of the relevant ecosystem, presence of `.github/workflows`,
55
+ `terraform/` or k8s manifests, and what the package exports. Do not
56
+ over-invest here; the classification should cost a minute, not a research
57
+ pass.
58
+
59
+ ## Procedure
60
+
61
+ 1. If the user named a type explicitly (for example `/thatch/refine
62
+ shared-lib`), skip classification and use it.
63
+ 2. Otherwise gather the signals above and pick the type.
64
+ 3. State the classification in one line and why, and let the user override.
65
+ A wrong classification silently changes the requirements, so the user
66
+ sees the pick before it takes effect. When the signals conflict or are
67
+ too thin to pick, ask instead of guessing.
68
+ 4. Load `thatch-plan-refinement` (the core loop) and the type's skill.
69
+ 5. Run the core loop with the type skill's deltas applied. Where a delta
70
+ and the core skill disagree, the delta wins; that is its whole job.
71
+
72
+ If no type fits (the repo serves a niche the table misses), run plain
73
+ `thatch-plan-refinement` and say that the requirements are the generic
74
+ ones.
75
+
76
+ ## Relationship to other skills
77
+
78
+ - **`thatch-plan-refinement`** - the core loop. Always loaded; the type
79
+ skills only modify it.
80
+ - **`thatch-coding-workflow`** - the procedure skill for executing the
81
+ refined plan. Refinement ends where it begins.
82
+ - **`thatch-clear-writing`** and the writing skills - several type skills
83
+ make reader-facing documentation a plan deliverable. Draft that text
84
+ under the writing skills' contracts, not this one's.
@@ -127,7 +127,7 @@ methods. The v1 hook shapes:
127
127
  | `command.execute.before` | Arms the wrap-up greenlight check: `/thatch/compact` and `/thatch/exit` mark their session in `pendingWrapUp`. The next `session.status` idle resolves it by inspecting the final assistant message for the greenlight token and, when present, triggering the TUI action (`session_compact` via `executeCommand`, `app.exit` via `publish`; the exit path unregisters the session from the chat directory first). See [features/session-lifecycle.md](features/session-lifecycle.md). |
128
128
  | `experimental.compaction.autocontinue` | Clears the compacting flag so `chat.message` nudges resume. Without this, nudges that instruct tool calls would fire during summary generation where tools are blocked. The `chat.message` hook also clears the flag if it fires for a session still in the compacting set but the incoming message has no compaction-type part — this handles compaction failure, where the session would otherwise be stuck with nudges off forever. |
129
129
  | `tool.execute.after` | Buffers every non-`thatch_*`, non-`skill`, non-`task` tool call into the session's extraction buffer. (Skill/task are excluded — buffering them creates a feedback loop where the nudge triggers a skill load, which gets buffered, which triggers another nudge.) Memory writes (`thatch_memory_remember`) and `thatch_extraction_done` drain the buffer and reset the missed-nudge counter. For child sessions (`childToParent.has(sessionID)`), also tracks metrics: `remember` with `overwrite:false` → new++, `overwrite:true` → updated++, `forget` → deleted++. For `thatch_chat_*` tool calls, builds the transcript echo (`chatEchoText`) and posts it as a visible non-synthetic `noReply` part. This is a plugin hook, NOT a bus event — do not move it into the `event` handler; the event bus has no such event and it will silently never fire. |
130
- | `chat.message` | Two priority tiers: (a) if extraction buffer has interactions and the session is NOT in the `extracting` set (direct extraction in progress), **peeks** the buffer (does NOT drain it) and injects a synthetic text part carrying the extraction nudge with the session ID and fetch tool name (not the full payload) — the sub-agent calls `thatch_get_extraction_payload` to retrieve the interactions as a tool response, keeping the full payload out of the main session's context window. The buffer persists until the agent writes a memory or calls `thatch_extraction_done`, so ignored nudges repeat and escalate (polite → insistent → ALL-CAPS) via the `missedNudges` counter; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). The same embedding also feeds the prediction auto-fire (`db.scorePredictionNudge`, injects `[thatch] User decision model`) and the behavior auto-fire (`db.scoreBehaviorNudge`, injects `[thatch] Situational behaviors`). All three nudges (recall, prediction, behavior) fire independently in separate try/catch blocks with separate synthetic parts. Chat transcript echoes (non-synthetic `noReply` parts whose text is entirely `[chat]`-prefixed bubbles) are skipped before any tier — no model turn reads them, so nudging them wastes an embedding. Skipped entirely while the session is compacting (tool calls are blocked during summary generation). |
130
+ | `chat.message` | Two priority tiers: (a) if extraction buffer has interactions and the session is NOT in the `extracting` set (direct extraction in progress), **peeks** the buffer (does NOT drain it) and injects a synthetic text part carrying the extraction nudge with the session ID and fetch tool name (not the full payload) — the sub-agent calls `thatch_get_extraction_payload` to retrieve the interactions as a tool response, keeping the full payload out of the main session's context window. The buffer persists until the agent writes a memory or calls `thatch_extraction_done`, so ignored nudges repeat and escalate (polite → insistent → ALL-CAPS) via the `missedNudges` counter; (b) otherwise, embeds the user's prompt text with the in-process warm model, searches `db.search()` across repo + global, and pushes a recall nudge if matches exceed the threshold (default 0.55). The same embedding also feeds the prediction auto-fire (`db.scorePredictionNudge`, injects `[thatch] User decision model`) and the behavior auto-fire (`db.scoreBehaviorNudge`, injects `[thatch] Situational behaviors`). All three nudges (recall, prediction, behavior) fire independently in separate try/catch blocks with separate synthetic parts. Chat transcript echoes (non-synthetic `noReply` parts whose text is entirely `[chat]`-prefixed bubbles) are skipped before any tier — no model turn reads them, so nudging them wastes an embedding. Skipped entirely while the session is compacting (tool calls are blocked during summary generation), and for task-dispatched sub-agent sessions (`childToParent` without `extractionChildren`) - their tool lists may exclude the thatch tools and their work is driven by the dispatch prompt. |
131
131
  | `event` | Subscribes to all session bus events. `session.created`: records `childToParent` + `parentSnapshots` (shallow copy of the parent's buffer for snapshot-aware drain), then sends the session-start reminder via `client.session.prompt` carrying the hygiene heartbeat (pending dedup pairs, stale count, orphaned branch memories) when any signal is non-zero. `session.status`: records the session's live status for the watcher and chat delivery gates; on idle, if the session is a child, drains its snapshot, fires a toast with `childMetrics`, and deletes the child session; if the session is a parent with pending tool interactions and not already extracting, calls `triggerExtraction` to create a direct-extraction child, then flushes pending watcher events and pending chat mail (the session just became deliverable). `session.error`: requeues the parent's buffer (child died without draining). `session.deleted`: cleans up `childToParent`, `parentSnapshots`, `childMetrics`, and `extracting`, cancels the session's watchers, and unregisters it from the chat directory (the crash path — a dead process fires no event — is covered by heartbeat staleness). `session.compacted`: clears the compacting flag so `chat.message` nudges resume. |
132
132
  | `dispose` | Stops the version checker, the watcher poller, and the chat poller, closes the DB. |
133
133
 
@@ -179,11 +179,15 @@ Two of these hooks were dead for weeks because failures were invisible.
179
179
  10. **Background completion narration is suppressed, not prevented.** When a
180
180
  background sub-agent completes, opencode injects a `<task_result>` block
181
181
  into the parent session and triggers a full model generation. Thatch
182
- cannot cancel this turn (no pre-response hook). Two mitigations: the
183
- fact-extractor skill's return value is constrained to the literal
184
- "Extraction complete." so the injected block has no narratable content,
185
- and the system prompt's "Background Task Completions" section instructs
186
- the model not to narrate completions or treat them as approval to act.
182
+ cannot cancel this turn (no pre-response hook). The mitigations: the
183
+ fact-extractor skill's return value is a fixed string so the injected
184
+ block has nothing to narrate AND the string self-identifies as a
185
+ completion, not an extraction nudge (a bare "Extraction complete." was
186
+ misread mid-loop as new nudge traffic and re-dispatched - the September
187
+ 2026 re-dispatch loop); the system prompt's "Background Task
188
+ Completions" section instructs the model not to narrate completions or
189
+ treat them as approval to act, and that a completion is never a
190
+ re-dispatch signal.
187
191
  11. **Prediction engine is a statistical model, not an LLM call.** The query
188
192
  (embed prompt, cosine-match against matchers, score linked predictions)
189
193
  is mechanical — same shape as `thatch_memory_recall` but against different
@@ -209,7 +213,7 @@ Two of these hooks were dead for weeks because failures were invisible.
209
213
  ## Data flow
210
214
 
211
215
  ```text
212
- thatch_memory_remember(label, content)
216
+ thatch_memory_remember(label?, content)
213
217
  → model.passageEmbed("# label\n\ncontent") → Float32Array
214
218
  → db.findSimilar(store, embedding) — write-time collision check (no telemetry)
215
219
  → db.remember(store, label, content, embedding, model.name, opts)
@@ -191,7 +191,14 @@ rather than one so a single late poll cycle does not flap the roster.
191
191
  Heartbeat age is the ONLY liveness signal, by design. A host process id
192
192
  cannot serve: the same session is re-hosted by a new process on every
193
193
  `-s` resume, so a pid stamped on the row lies as soon as a different
194
- harness beats it (it says dead while the heartbeat proves alive). `isStale`
194
+ harness beats it (it says dead while the heartbeat proves alive). RESTART
195
+ grace: a new daemon re-hosts the dead one's hosted set under a bounded
196
+ window (`CHAT_REHOST_GRACE_MS`, 24h, `THATCH_CHAT_REHOST_GRACE_MINUTES`
197
+ to override) - open TUI tabs reconnect but emit no events until typed
198
+ into, so without the grace they would read stale while alive-idle and
199
+ mail to them would not wake the tab. Sessions that emit activity
200
+ graduate to permanent hosting; still-silent ones (closed tabs) age out
201
+ at the grace and go stale. `isStale`
195
202
  (src/chat.ts) is the single rule; `chatLiveness`, the `chat_send` note,
196
203
  and the broadcast skip all call it, so they cannot disagree. `chat_list`
197
204
  groups the result into Active and Stale sections - the stale section's
@@ -58,7 +58,7 @@ The "global" store always exists — it is inserted at schema init (`INSERT OR I
58
58
  ### Write path (memory_remember)
59
59
 
60
60
  ```text
61
- agent calls memory_remember(label, content, opts)
61
+ agent calls memory_remember(label?, content, opts) - label is derived from the content's first heading or line when omitted
62
62
  → model.passageEmbed("# label\n\ncontent") → Float32Array
63
63
  → db.findSimilar(store, embedding, { excludeSlug }) → write-time collision check
64
64
  → db.remember(store, label, content, embedding, model.name, opts)
@@ -49,6 +49,18 @@ not a compaction summary, compaction has already failed (the auto-continue
49
49
  never fired). Thatch clears the stale `compacting` flag and proceeds normally.
50
50
  See [compaction-recovery.md](compaction-recovery.md).
51
51
 
52
+ #### Task sub-agent guard
53
+
54
+ If the session is a child in `childToParent` but not in `extractionChildren`
55
+ (a task-dispatched sub-agent), all nudge tiers are skipped and the hook
56
+ returns before tier 1. Dispatched sub-agents may have restricted tool lists
57
+ that exclude the thatch tools, and even where the tools exist the child is
58
+ driven by its dispatch prompt, so a nudge only produces "No tool named"
59
+ error rounds or noise. `extraction.requeueStaleAccepted()` still runs before
60
+ the guard - it is session-independent maintenance. See
61
+ [session-lifecycle.md](session-lifecycle.md) for the `extractionChildren`
62
+ distinction.
63
+
52
64
  #### Tier 1---Extraction nudge (fallback path)
53
65
 
54
66
  Fires only when direct extraction was never triggered or threw (the session is