@mootup/moot-templates 0.2.1 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mootup/moot-templates",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Canonical project templates (skills, teams, devcontainer, Claude hooks) for @mootup/moot-cli, synced from the mootup Python CLI source.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,6 +1,20 @@
1
1
  {
2
2
  "permissions": {
3
- "defaultMode": "bypassPermissions"
3
+ "defaultMode": "bypassPermissions",
4
+ "allow": [
5
+ "Edit(.claude/**)",
6
+ "Write(.claude/**)",
7
+ "Edit(.worktrees/**/.claude/**)",
8
+ "Write(.worktrees/**/.claude/**)",
9
+ "Edit(CLAUDE.md)",
10
+ "Write(CLAUDE.md)",
11
+ "Edit(.worktrees/**/CLAUDE.md)",
12
+ "Write(.worktrees/**/CLAUDE.md)",
13
+ "Edit(docs/**/CLAUDE.md)",
14
+ "Write(docs/**/CLAUDE.md)",
15
+ "Edit(.worktrees/**/docs/**/CLAUDE.md)",
16
+ "Write(.worktrees/**/docs/**/CLAUDE.md)"
17
+ ]
4
18
  },
5
19
  "hooks": {
6
20
  "SessionStart": [
@@ -14,16 +14,32 @@ done
14
14
 
15
15
  # Read per-role actor identity from .moot/actors.json. See run-moot-mcp.sh
16
16
  # for the full rationale — same rule applies to the channel adapter.
17
+ #
18
+ # SEC-2-C: env-driven Python via single-quoted heredoc — no shell-eval RCE.
17
19
  if [ -f "$PROJECT_ROOT/$ACTORS_FILE" ]; then
18
- eval $(python3 -c "
19
- import json, shlex
20
- with open('$PROJECT_ROOT/$ACTORS_FILE') as f:
21
- data = json.load(f)
22
- entry = data.get('actors', {}).get('$ROLE', {})
23
- print('KEY=' + shlex.quote(entry.get('api_key', '')))
24
- print('AID=' + shlex.quote(entry.get('actor_id', '')))
25
- print('ANAME=' + shlex.quote(entry.get('display_name', '$ROLE')))
26
- " 2>/dev/null)
20
+ OUT="$(
21
+ export _PR="$PROJECT_ROOT" _AF="$ACTORS_FILE" _ROLE="$ROLE"
22
+ python3 <<'PYEOF'
23
+ import json, os, sys
24
+ pr = os.environ['_PR']
25
+ af = os.environ['_AF']
26
+ role = os.environ['_ROLE']
27
+ try:
28
+ with open(os.path.join(pr, af)) as f:
29
+ data = json.load(f)
30
+ entry = data.get('actors', {}).get(role, {})
31
+ print(entry.get('api_key', ''))
32
+ print(entry.get('actor_id', ''))
33
+ print(entry.get('display_name', role))
34
+ except Exception:
35
+ print('', file=sys.stderr)
36
+ print('', file=sys.stderr)
37
+ print('', file=sys.stderr)
38
+ PYEOF
39
+ )"
40
+ KEY="$(printf '%s\n' "$OUT" | sed -n '1p')"
41
+ AID="$(printf '%s\n' "$OUT" | sed -n '2p')"
42
+ ANAME="$(printf '%s\n' "$OUT" | sed -n '3p')"
27
43
  if [ -n "$KEY" ]; then
28
44
  export CONVO_API_KEY="$KEY"
29
45
  else
@@ -35,12 +51,15 @@ fi
35
51
 
36
52
  # Read API URL from moot.toml
37
53
  if [ -z "$CONVO_API_URL" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
38
- URL=$(python3 -c "
39
- import tomllib
40
- with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
54
+ URL="$(
55
+ export _PR="$PROJECT_ROOT"
56
+ python3 <<'PYEOF'
57
+ import os, tomllib
58
+ with open(os.path.join(os.environ['_PR'], 'moot.toml'), 'rb') as f:
41
59
  data = tomllib.load(f)
42
60
  print(data.get('convo', {}).get('api_url', ''))
43
- " 2>/dev/null)
61
+ PYEOF
62
+ )"
44
63
  if [ -n "$URL" ]; then
45
64
  export CONVO_API_URL="$URL"
46
65
  fi
@@ -48,12 +67,15 @@ fi
48
67
 
49
68
  # Read space ID from moot.toml
50
69
  if [ -z "$CONVO_SPACE_ID" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
51
- SID=$(python3 -c "
52
- import tomllib
53
- with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
70
+ SID="$(
71
+ export _PR="$PROJECT_ROOT"
72
+ python3 <<'PYEOF'
73
+ import os, tomllib
74
+ with open(os.path.join(os.environ['_PR'], 'moot.toml'), 'rb') as f:
54
75
  data = tomllib.load(f)
55
76
  print(data.get('convo', {}).get('space_id', ''))
56
- " 2>/dev/null)
77
+ PYEOF
78
+ )"
57
79
  if [ -n "$SID" ]; then
58
80
  export CONVO_SPACE_ID="$SID"
59
81
  fi
@@ -18,16 +18,33 @@ done
18
18
  # "unknown-agent", and the backend rejects any post whose agent_id in the
19
19
  # body doesn't match the authenticated actor (HTTP 400, which the adapter
20
20
  # surfaces as an empty event_id).
21
+ #
22
+ # SEC-2-C: env-driven Python via single-quoted heredoc — no shell-eval RCE.
23
+ # CONVO_ROLE / paths reach Python via os.environ, never via shell interpolation.
21
24
  if [ -f "$PROJECT_ROOT/$ACTORS_FILE" ]; then
22
- eval $(python3 -c "
23
- import json, shlex
24
- with open('$PROJECT_ROOT/$ACTORS_FILE') as f:
25
- data = json.load(f)
26
- entry = data.get('actors', {}).get('$ROLE', {})
27
- print('KEY=' + shlex.quote(entry.get('api_key', '')))
28
- print('AID=' + shlex.quote(entry.get('actor_id', '')))
29
- print('ANAME=' + shlex.quote(entry.get('display_name', '$ROLE')))
30
- " 2>/dev/null)
25
+ OUT="$(
26
+ export _PR="$PROJECT_ROOT" _AF="$ACTORS_FILE" _ROLE="$ROLE"
27
+ python3 <<'PYEOF'
28
+ import json, os, sys
29
+ pr = os.environ['_PR']
30
+ af = os.environ['_AF']
31
+ role = os.environ['_ROLE']
32
+ try:
33
+ with open(os.path.join(pr, af)) as f:
34
+ data = json.load(f)
35
+ entry = data.get('actors', {}).get(role, {})
36
+ print(entry.get('api_key', ''))
37
+ print(entry.get('actor_id', ''))
38
+ print(entry.get('display_name', role))
39
+ except Exception:
40
+ print('', file=sys.stderr)
41
+ print('', file=sys.stderr)
42
+ print('', file=sys.stderr)
43
+ PYEOF
44
+ )"
45
+ KEY="$(printf '%s\n' "$OUT" | sed -n '1p')"
46
+ AID="$(printf '%s\n' "$OUT" | sed -n '2p')"
47
+ ANAME="$(printf '%s\n' "$OUT" | sed -n '3p')"
31
48
  if [ -n "$KEY" ]; then
32
49
  export CONVO_API_KEY="$KEY"
33
50
  else
@@ -39,12 +56,15 @@ fi
39
56
 
40
57
  # Read API URL from moot.toml
41
58
  if [ -z "$CONVO_API_URL" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
42
- URL=$(python3 -c "
43
- import tomllib
44
- with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
59
+ URL="$(
60
+ export _PR="$PROJECT_ROOT"
61
+ python3 <<'PYEOF'
62
+ import os, tomllib
63
+ with open(os.path.join(os.environ['_PR'], 'moot.toml'), 'rb') as f:
45
64
  data = tomllib.load(f)
46
65
  print(data.get('convo', {}).get('api_url', ''))
47
- " 2>/dev/null)
66
+ PYEOF
67
+ )"
48
68
  if [ -n "$URL" ]; then
49
69
  export CONVO_API_URL="$URL"
50
70
  fi
@@ -52,12 +72,15 @@ fi
52
72
 
53
73
  # Read space ID from moot.toml
54
74
  if [ -z "$CONVO_SPACE_ID" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
55
- SID=$(python3 -c "
56
- import tomllib
57
- with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
75
+ SID="$(
76
+ export _PR="$PROJECT_ROOT"
77
+ python3 <<'PYEOF'
78
+ import os, tomllib
79
+ with open(os.path.join(os.environ['_PR'], 'moot.toml'), 'rb') as f:
58
80
  data = tomllib.load(f)
59
81
  print(data.get('convo', {}).get('space_id', ''))
60
- " 2>/dev/null)
82
+ PYEOF
83
+ )"
61
84
  if [ -n "$SID" ]; then
62
85
  export CONVO_SPACE_ID="$SID"
63
86
  fi
@@ -5,7 +5,32 @@ description: Curate repository documentation for agent use. Use when restructuri
5
5
 
6
6
  # Doc Curation
7
7
 
8
- Curate docs for fast agent retrieval and reliable human orientation.
8
+ ## Purpose
9
+
10
+ Keep repository documentation optimized for fast agent retrieval and reliable human orientation. The failure class this skill addresses is **retrieval drift** — documentation accumulates organically, the same concept gets re-explained across many docs, canonical entry points fade, and agents burn tokens stitching together answers from fragmented sources. Left unaudited, doc trees decay into navigation mazes that cost more to read than they save.
11
+
12
+ **Why it exists as a named skill:** curation is a judgment-heavy activity (when to split, when to merge, what's "canonical") that benefits from a shared stance rather than each author making ad-hoc calls. The skill captures the stance, the decision heuristics, and the common friction smells so curators at different times make consistent calls.
13
+
14
+ ## Preconditions
15
+
16
+ - **Role:** any role that edits docs. Most commonly Librarian (who owns `docs/design/`, `docs/arch/`, READMEs) or Product (who owns `docs/product/`).
17
+ - **Trigger:** restructuring docs, adding index pages, reducing repeated explanations, splitting or merging documents, or responding to a specific drift flag. Also fires preemptively during post-ship as-built passes when the curator notices duplication or weak entry points.
18
+ - **Entry-point awareness:** the curator knows which existing docs currently serve as canonical entry points (`VISION.md`, `docs/architecture.md`, `docs/product/README.md`, `docs/specs/README.md`, etc.) so they can preserve or improve them rather than accidentally orphan.
19
+
20
+ ## Invariants
21
+
22
+ - **Canonical entry points MUST be preserved.** Overview docs, spec indexes, and runbooks are load-bearing; curation improves or augments them, never demotes or replaces silently.
23
+ - **One coherent subject per document.** A doc that answers two unrelated questions is a bad split target — re-partition rather than leaving it mixed.
24
+ - **Don't orphan references.** When moving content out of doc A into doc B, update doc A to point at B (or remove A entirely with an index update). Dangling references are process-debt.
25
+ - **No duplicate canonical content.** If two docs define the same concept, one MUST be canonical and the other MUST reference it. Both-canonical is the drift state this skill fights.
26
+
27
+ ## Postconditions
28
+
29
+ - An agent asking a common question about the curated area can answer it from ≤2 reads.
30
+ - Canonical entry points are intact or improved.
31
+ - Duplicate prose is removed or reduced; cross-references point to canonical sources.
32
+ - Where a second read is likely, the "read this next" pointer is explicit in the first doc.
33
+ - Any doc moves or renames update the directory index (typically `README.md` in that directory).
9
34
 
10
35
  ## Default stance
11
36
 
@@ -15,66 +40,61 @@ Curate docs for fast agent retrieval and reliable human orientation.
15
40
  - Use inter-document references to guide the next read when one document is not enough.
16
41
  - Optimize for fewer read round-trips and lower reconstruction effort.
17
42
 
18
- ## When to use this skill
19
-
20
- Use this skill when you are:
43
+ ## Procedure
21
44
 
22
- - reorganizing docs or specs
23
- - adding or updating README index pages
24
- - reducing repeated explanations across docs
25
- - deciding whether to split or merge documents
26
- - making docs easier for agents to scan in a large context window
45
+ 1. **Identify current entry points** — main overview, setup, spec index, runbook docs. Preserve or improve those before introducing new structure.
27
46
 
28
- ## Workflow
29
-
30
- 1. Identify the current entry points.
31
- - Find the main overview, setup, spec index, and runbook docs.
32
- - Preserve or improve those before introducing new structure.
33
-
34
- 2. Map the document types.
47
+ 2. **Map document types:**
35
48
  - Overview: "what is this system?"
36
49
  - Subject docs: "how does this area work?"
37
50
  - Specs/runbooks: "what should we build?" / "how do we operate it?"
38
51
  - Reference: canonical facts, API shapes, protocol copies
39
52
 
40
- 3. Check for agent-friction smells.
41
- - The same concept is re-explained in many docs.
42
- - A doc is so broad that agents must scan the whole file to answer a narrow question.
43
- - A concept is fragmented across too many docs, forcing multiple reads to reconstruct one answer.
44
- - There is no clear "read this first" path.
45
- - References exist, but they do not tell the reader what to open next or why.
53
+ 3. **Check for agent-friction smells:**
54
+ - Same concept re-explained in many docs.
55
+ - A doc so broad that agents must scan the whole file to answer a narrow question.
56
+ - A concept fragmented across too many docs, forcing multiple reads to reconstruct one answer.
57
+ - No clear "read this first" path.
58
+ - References exist but don't tell the reader what to open next or why.
46
59
 
47
- 4. Choose the retrieval unit.
48
- - Default to a subject-oriented doc with a short summary and scoped headings.
49
- - Split only when sections are weakly related or maintained by different workflows.
50
- - Prefer one document that answers a common question in one read over multiple documents that must be stitched together.
60
+ 4. **Choose the retrieval unit.** Default: a subject-oriented doc with a short summary and scoped headings. Split only when sections are weakly related or maintained by different workflows. Prefer one document that answers a common question in one read over multiple that must be stitched.
51
61
 
52
- 5. Edit for retrieval.
62
+ 5. **Edit for retrieval:**
53
63
  - Put a 1-3 sentence summary near the top.
54
64
  - Use descriptive headings that match likely queries.
55
- - Move repeated background into one canonical subject doc and reference it from related docs.
56
- - Add explicit inter-document references such as "For auth boundaries, read `docs/specs/auth-hardening.md`" when a second read is likely.
57
- - Keep "See also" or "Related subjects" sections short and action-oriented.
65
+ - Move repeated background into one canonical subject doc and reference it.
66
+ - Add explicit inter-document references ("For auth boundaries, read `docs/specs/auth-hardening.md`") when a second read is likely.
67
+ - Keep "See also" / "Related subjects" sections short and action-oriented.
58
68
 
59
- 6. Verify the result.
69
+ 6. **Verify the result:**
60
70
  - Can an agent answer the common question from one read?
61
71
  - If a second read is needed, is the next doc obvious?
62
72
  - Did token cost go down by reducing duplicate prose or pointless hops?
63
73
 
64
- ## Heuristics
74
+ ## Practice
75
+
76
+ **Good primary-doc size** is usually a few hundred to low-thousand tokens. Substantially smaller → probably too granular (merge candidate). Substantially larger → probably too broad (split candidate).
77
+
78
+ **Good split:** "auth model" and "invite flow" are different subjects with different maintenance cadences.
65
79
 
66
- - Good primary doc size: usually a few hundred to low-thousand tokens.
67
- - Good split: "auth model" and "invite flow" are different subjects.
68
- - Bad split: one coherent subject scattered across several weakly differentiated docs.
69
- - Prefer one strong README/MOC per doc area over many weak index notes.
70
- - For cross-cutting topics, use one canonical subject doc and reference it from specs and overviews.
80
+ **Bad split:** one coherent subject scattered across several weakly differentiated docs. Symptom: every answer requires reading 3+ files.
81
+
82
+ **One strong README/MOC per doc area > many weak index notes.** Prefer a single well-maintained entry point. Multiple competing indexes are drift.
83
+
84
+ **For cross-cutting topics, one canonical subject doc + references from specs and overviews.** The canonical doc is the single source of truth; other docs reference it rather than re-defining.
71
85
 
72
86
  ## Output expectations
73
87
 
74
- When proposing or making changes, explain:
88
+ When proposing or making changes, explain in the commit / PR body:
89
+ - Which entry points were preserved or added
90
+ - Which docs became canonical for repeated concepts
91
+ - Which duplicates were removed or reduced
92
+ - Which inter-document references were added or clarified
93
+ - Whether the change reduces round-trips for agents
94
+
95
+ ## Defined terms
96
+
97
+ - **Canonical entry point** — a load-bearing doc (overview, index, runbook) that agents and humans find first. Curation preserves these.
98
+ - **Retrieval unit** — the granularity at which a doc is expected to be read. Good retrieval units answer a common question in one read.
99
+ - **Agent-friction smell** — a doc-structure pattern that forces unnecessary reads, duplication, or reconstruction effort.
75
100
 
76
- - the entry points you preserved or added
77
- - which docs became canonical for repeated concepts
78
- - which duplicates were removed or reduced
79
- - which inter-document references were added or clarified
80
- - whether the change reduces round-trips for agents
@@ -4,28 +4,67 @@ description: Post a structured handoff message to the next agent in the pipeline
4
4
  argument-hint: [summary of what was done]
5
5
  ---
6
6
 
7
- Post a structured handoff message to the next agent in the Moot channel.
7
+ # Handoff
8
8
 
9
- ## Pipeline Order
9
+ ## Purpose
10
10
 
11
- - **Product** hands off to **Spec**
12
- - **Spec** hands off to **Implementation**
13
- - **Implementation** hands off to **QA**
14
- - **QA** hands off to **Product** (verification complete)
11
+ Transfer control of in-flight pipeline work from one agent to the next. The failure class this skill prevents is the **silent handoff** agent A finishes work, updates status, and goes idle without notifying agent B, stalling the ring. Also prevents **misdirected handoff** (mentioning the wrong next agent for the current pipeline stage) and **unstructured handoff** (free-form text that omits the branch, the files changed, or the next-agent action items).
15
12
 
16
- ## Steps
13
+ **Why it exists as a named skill:** the pipeline order is fixed but the specific next-agent depends on *which stage you just completed*; each handoff format varies by stage (Spec → Impl, Impl → QA, QA → Leader, Leader → Product); and there are exceptions (Spec doc-only, QA verification-only) that the current agent must recognize. Capturing this once keeps handoff structure consistent across the pipeline.
17
14
 
18
- 1. Determine which agent is next based on your role (check `whoami` if unsure).
19
- 2. Commit all work to your branch (e.g., `spec/<slug>`, `impl/<slug>`).
20
- 3. Get the current branch name and list of files changed:
21
- ```
15
+ ## Preconditions
16
+
17
+ - **Role:** caller is a pipeline agent (Spec / Implementation / QA / Leader / Product). Librarian is an observer role and does NOT hand off in the feature thread — if Librarian reaches this skill, it's a misfire.
18
+ - **Branch committed:** all work is committed to the caller's branch (`<role>/<slug>`). Handing off uncommitted work is a protocol violation; Leader cannot merge what isn't on a branch.
19
+ - **Feature thread known:** caller knows the current feature thread's `thread_id` (or an `event_id` within the thread that can be `reply_to`'d). Handoffs posted top-level fork the thread spine.
20
+ - **Next-agent identified:** caller has determined the correct next agent based on the pipeline stage just completed. `whoami` + pipeline-order table in this skill, if unsure.
21
+
22
+ ## Invariants
23
+
24
+ - **Thread discipline.** Handoff messages MUST be replies in the feature thread, not top-level posts. The feature thread is the spine; top-level posts fragment it.
25
+ - **Mention-the-next-agent-only.** Per CLAUDE.md mention discipline, `mentions=` includes the next agent and NO ONE else. No broadcast mentions.
26
+ - **Display names in text, IDs in `mentions`.** Message text uses "Implementation: pull the branch..."; the `mentions` parameter carries the `agt_*` ID. Mixing raw IDs into text is a readability violation.
27
+ - **No acknowledgment after handing off.** Per CLAUDE.md, the caller MUST NOT wait for the next agent to ack. Post handoff, update status, stop.
28
+ - **Librarian is never in handoff mentions.** Observer role. Even if Librarian contributed content, handoff mentions are pipeline-only.
29
+
30
+ ## Postconditions
31
+
32
+ - A handoff reply exists in the feature thread, with `mentions=[<next-agent-id>]`.
33
+ - For pipeline stages requiring a branch merge (Spec, Impl, QA with commits), a `message_type="git_request"` reply addressed to Leader has been posted in the feature thread.
34
+ - Caller's `update_status` reflects the idle/awaiting state post-handoff.
35
+ - Caller is idle — not polling, not re-checking, not acknowledging anything in reply.
36
+
37
+ ## Pipeline Order (reference, not a contract)
38
+
39
+ ```
40
+ Pat → Product → Leader → Spec → Implementation → QA → Leader → Product
41
+ ```
42
+
43
+ - **Product** composes the feature kickoff (`message_type="feature"`) mentioning **Leader**; Leader replies in-thread with the operational kickoff mentioning Spec/Impl/QA.
44
+ - **Spec** hands off to **Implementation** via SPEC-READY reply in the feature thread (and a `message_type="git_request"` to Leader to merge `spec/<slug>` → `feat/<slug>`).
45
+ - **Implementation** hands off to **QA** via a `message_type="git_request"` reply to Leader to merge `impl/<slug>` → `feat/<slug>`. QA picks up after Leader's merge ack.
46
+ - **QA** hands off to **Leader** via a verification report that MUST mention Leader via the `mentions` parameter. Leader squash-merges `feat/<slug>` → `main` and posts the ship message.
47
+ - **Leader** hands off to **Product** by posting the retros-in ping after all three retros land, mentioning Product. Product reads retros, synthesizes, requests merge of `product/run-<label>-synthesis`.
48
+
49
+ ## Procedure
50
+
51
+ 1. **Determine the next agent** from the pipeline order above (use `whoami` if unsure of current role).
52
+ 2. **Commit all work to the role branch** (`spec/<slug>`, `impl/<slug>`, `qa/<slug>`).
53
+ 3. **Capture branch state:**
54
+ ```bash
22
55
  git branch --show-current
23
56
  git diff --name-only feat/<slug>...HEAD
24
57
  ```
25
- 4. Post a `message_type="git_request"` reply in the feature thread asking Leader to merge your branch into `feat/<slug>` (unless you are Spec with doc-only changes, which can be committed directly to the feature branch).
26
- 5. Post a handoff message to the Moot channel in the active feature thread with the info below.
58
+ 4. **Post a `message_type="git_request"` reply in the feature thread asking Leader to merge.** Exceptions (no git-request needed):
59
+ - Spec doc-only changes MAY be committed directly to `feat/<slug>` per CLAUDE.md.
60
+ - QA MAY commit small unambiguous repairs directly to `feat/<slug>`.
61
+ - QA verification reports with no repairs need no git-request at all — the verification report itself is the handoff.
62
+ 5. **Post the handoff message as a reply in the feature thread.** Use `mentions=[<next-agent-id>]`; use display names in the text. For QA, the next agent is **Leader** (ship), not Product.
63
+ 6. **Update status and stop.** `update_status` ("idle, awaiting next feature" or equivalent). Do not poll, do not ack.
64
+
65
+ ## Practice
27
66
 
28
- ## Message Format
67
+ **Message format** (default; adjust for stage):
29
68
 
30
69
  ```
31
70
  Handing off to @NextAgent.
@@ -44,3 +83,12 @@ Handing off to @NextAgent.
44
83
 
45
84
  **Pointers:** [links to specs, docs, or specific line numbers]
46
85
  ```
86
+
87
+ **QA verification-complete handoff** uses the gate-results table format from prior QA reports rather than the generic template — a concise gate table communicates pass/fail more clearly than free-form summary.
88
+
89
+ ## Defined terms
90
+
91
+ - **Feature thread** — the thread rooted at Product's feature kickoff message. All pipeline handoffs for this feature run live as replies within it.
92
+ - **Role branch** — per-feature branch owned by the current role: `spec/<slug>`, `impl/<slug>`, `qa/<slug>`, etc.
93
+ - **Feature branch** — `feat/<slug>`, the integration branch Leader creates at kickoff and merges role branches into.
94
+