@mootup/moot-templates 0.1.0-rc.0

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 (43) hide show
  1. package/README.md +42 -0
  2. package/dist/index.d.ts +21 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +35 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +39 -0
  7. package/templates/CLAUDE.md +233 -0
  8. package/templates/claude/hooks/auto-orient.sh +21 -0
  9. package/templates/claude/hooks/git-guard.sh +56 -0
  10. package/templates/claude/hooks/grep-baseline-diff.sh +41 -0
  11. package/templates/claude/hooks/handoff-status-check.sh +40 -0
  12. package/templates/claude/settings.json +51 -0
  13. package/templates/devcontainer/devcontainer.json +25 -0
  14. package/templates/devcontainer/post-create.sh +68 -0
  15. package/templates/devcontainer/run-moot-channel.sh +70 -0
  16. package/templates/devcontainer/run-moot-mcp.sh +74 -0
  17. package/templates/devcontainer/run-moot-notify.sh +59 -0
  18. package/templates/skills/doc-curation/SKILL.md +80 -0
  19. package/templates/skills/handoff/SKILL.md +46 -0
  20. package/templates/skills/leader-workflow/SKILL.md +135 -0
  21. package/templates/skills/librarian-workflow/SKILL.md +50 -0
  22. package/templates/skills/memory-audit/SKILL.md +85 -0
  23. package/templates/skills/product-workflow/SKILL.md +69 -0
  24. package/templates/skills/spec-checklist/SKILL.md +99 -0
  25. package/templates/skills/verify/SKILL.md +64 -0
  26. package/templates/teams/loop-3/CLAUDE.md +72 -0
  27. package/templates/teams/loop-3/README.md +6 -0
  28. package/templates/teams/loop-3/team.toml +108 -0
  29. package/templates/teams/loop-4/CLAUDE.md +72 -0
  30. package/templates/teams/loop-4/README.md +6 -0
  31. package/templates/teams/loop-4/team.toml +126 -0
  32. package/templates/teams/loop-4-observer/CLAUDE.md +76 -0
  33. package/templates/teams/loop-4-observer/README.md +7 -0
  34. package/templates/teams/loop-4-observer/team.toml +141 -0
  35. package/templates/teams/loop-4-parallel/CLAUDE.md +76 -0
  36. package/templates/teams/loop-4-parallel/README.md +6 -0
  37. package/templates/teams/loop-4-parallel/team.toml +142 -0
  38. package/templates/teams/loop-4-split-leader/CLAUDE.md +76 -0
  39. package/templates/teams/loop-4-split-leader/README.md +7 -0
  40. package/templates/teams/loop-4-split-leader/team.toml +140 -0
  41. package/templates/teams/loop-6/CLAUDE.md +43 -0
  42. package/templates/teams/loop-6/README.md +9 -0
  43. package/templates/teams/loop-6/team.toml +161 -0
@@ -0,0 +1,68 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # System packages
5
+ sudo apt-get update && sudo apt-get install -y tmux
6
+
7
+ # Claude Code CLI — install from npm first (puts `claude` on PATH
8
+ # via /usr/local/share/npm-global/bin), use it to register MCP servers,
9
+ # then call `claude install` to migrate to the native build at
10
+ # ~/.local/bin. The native build is the officially-supported path
11
+ # going forward; the TUI nags on first run when it's still npm-based.
12
+ npm install -g @anthropic-ai/claude-code
13
+
14
+ # Python tooling
15
+ pip install uv
16
+
17
+ # Install moot package
18
+ pip install mootup
19
+
20
+ # Register MCP servers for Claude Code at user scope so claude finds
21
+ # them regardless of cwd (agents launch in worktrees under .worktrees/,
22
+ # not the project root). Use absolute paths to the wrapper scripts so
23
+ # they resolve from any cwd. The wrappers read CONVO_ROLE at runtime
24
+ # to look up the per-role API key from .moot/actors.json.
25
+ DEVCONTAINER_DIR="$(realpath .devcontainer)"
26
+ claude mcp add convo "$DEVCONTAINER_DIR/run-moot-mcp.sh" -s user
27
+ claude mcp add convo-channel "$DEVCONTAINER_DIR/run-moot-channel.sh" -s user
28
+
29
+ # Migrate from the npm-installed claude to the native build. This runs
30
+ # LAST (after `claude mcp add`) because `claude install` deletes the
31
+ # npm symlink — anything calling `claude` after this point must rely on
32
+ # ~/.local/bin/claude, which `bash -lc` picks up via ~/.profile's
33
+ # standard "$HOME/.local/bin" snippet. Agent tmux sessions launch with
34
+ # `bash -lc`, so they find the native binary automatically.
35
+ claude install
36
+
37
+ # Rebind tmux prefix to Ctrl-Space. Claude Code intercepts Ctrl-B (the
38
+ # default prefix), so the usual `Ctrl-B d` detach never reaches tmux.
39
+ # Ctrl-Space is rarely claimed by TUIs and leaves readline-style editing
40
+ # bindings (Ctrl-A/E/etc.) untouched inside claude's input line.
41
+ cat > /home/node/.tmux.conf <<'TMUX_CONF'
42
+ unbind C-b
43
+ set -g prefix C-Space
44
+ bind C-Space send-prefix
45
+
46
+ # Mouse on: scroll-wheel scrolls the pane, click selects a pane/window,
47
+ # drag copies. Without this, scrollback is only reachable via the
48
+ # copy-mode keybind (<prefix> [) which is a tmux-literacy tax users
49
+ # shouldn't have to pay just to read recent output.
50
+ set -g mouse on
51
+ TMUX_CONF
52
+
53
+ # Register a /detach slash command for claude so the user can leave a
54
+ # tmux session without having to fight for the prefix key. The command
55
+ # calls `tmux detach-client`, which disconnects the terminal but leaves
56
+ # claude running in the session so `moot attach` picks up where it left
57
+ # off. User-scope so every worktree sees it.
58
+ mkdir -p /home/node/.claude/commands
59
+ cat > /home/node/.claude/commands/detach.md <<'DETACH_MD'
60
+ ---
61
+ description: Detach from the tmux session (leaves claude running in the background)
62
+ allowed-tools: Bash(bash:*)
63
+ ---
64
+
65
+ !bash -c 'SOCK=$(find /tmp /run -maxdepth 3 -name default -type s 2>/dev/null | head -1); if [ -n "$SOCK" ]; then tmux -S "$SOCK" detach-client; else echo "tmux socket not found"; fi'
66
+ DETACH_MD
67
+
68
+ echo "Container ready."
@@ -0,0 +1,70 @@
1
+ #!/bin/bash
2
+ # Channel adapter wrapper — reads CONVO_ROLE and looks up API key
3
+ # from .moot/actors.json. Same logic as run-moot-mcp.sh.
4
+
5
+ ROLE="${CONVO_ROLE:-implementation}"
6
+ ACTORS_FILE=".moot/actors.json"
7
+
8
+ # Find project root (walk up to moot.toml)
9
+ PROJECT_ROOT="$(pwd)"
10
+ while [ "$PROJECT_ROOT" != "/" ]; do
11
+ [ -f "$PROJECT_ROOT/moot.toml" ] && break
12
+ PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
13
+ done
14
+
15
+ # Read per-role actor identity from .moot/actors.json. See run-moot-mcp.sh
16
+ # for the full rationale — same rule applies to the channel adapter.
17
+ 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)
27
+ if [ -n "$KEY" ]; then
28
+ export CONVO_API_KEY="$KEY"
29
+ else
30
+ echo "WARNING: No API key for role '$ROLE' in $ACTORS_FILE" >&2
31
+ fi
32
+ [ -n "$AID" ] && export CONVO_AGENT_ID="$AID"
33
+ [ -n "$ANAME" ] && export CONVO_AGENT_NAME="$ANAME"
34
+ fi
35
+
36
+ # Read API URL from moot.toml
37
+ 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:
41
+ data = tomllib.load(f)
42
+ print(data.get('convo', {}).get('api_url', ''))
43
+ " 2>/dev/null)
44
+ if [ -n "$URL" ]; then
45
+ export CONVO_API_URL="$URL"
46
+ fi
47
+ fi
48
+
49
+ # Read space ID from moot.toml
50
+ 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:
54
+ data = tomllib.load(f)
55
+ print(data.get('convo', {}).get('space_id', ''))
56
+ " 2>/dev/null)
57
+ if [ -n "$SID" ]; then
58
+ export CONVO_SPACE_ID="$SID"
59
+ fi
60
+ fi
61
+
62
+ # Alpha-grade diagnostics: DEBUG-level logs to a per-role file under
63
+ # .moot/logs/ in the project root. Bind-mounted to the host so users
64
+ # and support can grep and share the logs without docker exec.
65
+ # Override with MOOT_LOG_LEVEL=INFO (or higher) once alpha stabilizes.
66
+ LOG_DIR="$PROJECT_ROOT/.moot/logs"
67
+ mkdir -p "$LOG_DIR"
68
+ LOG_FILE="$LOG_DIR/channel-${ROLE}.log"
69
+ export MOOT_LOG_LEVEL="${MOOT_LOG_LEVEL:-DEBUG}"
70
+ exec python -u -m moot.adapters.channel_runner "$@" 2>> "$LOG_FILE"
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # MCP adapter wrapper — reads CONVO_ROLE and looks up API key
3
+ # from .moot/actors.json. Set CONVO_ROLE before launching Claude Code
4
+ # to pick a different identity.
5
+
6
+ ROLE="${CONVO_ROLE:-implementation}"
7
+ ACTORS_FILE=".moot/actors.json"
8
+
9
+ # Find project root (walk up to moot.toml)
10
+ PROJECT_ROOT="$(pwd)"
11
+ while [ "$PROJECT_ROOT" != "/" ]; do
12
+ [ -f "$PROJECT_ROOT/moot.toml" ] && break
13
+ PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
14
+ done
15
+
16
+ # Read per-role actor identity from .moot/actors.json. We MUST export
17
+ # CONVO_AGENT_ID and CONVO_AGENT_NAME — the mcp_runner defaults them to
18
+ # "unknown-agent", and the backend rejects any post whose agent_id in the
19
+ # body doesn't match the authenticated actor (HTTP 400, which the adapter
20
+ # surfaces as an empty event_id).
21
+ 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)
31
+ if [ -n "$KEY" ]; then
32
+ export CONVO_API_KEY="$KEY"
33
+ else
34
+ echo "WARNING: No API key for role '$ROLE' in $ACTORS_FILE" >&2
35
+ fi
36
+ [ -n "$AID" ] && export CONVO_AGENT_ID="$AID"
37
+ [ -n "$ANAME" ] && export CONVO_AGENT_NAME="$ANAME"
38
+ fi
39
+
40
+ # Read API URL from moot.toml
41
+ 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:
45
+ data = tomllib.load(f)
46
+ print(data.get('convo', {}).get('api_url', ''))
47
+ " 2>/dev/null)
48
+ if [ -n "$URL" ]; then
49
+ export CONVO_API_URL="$URL"
50
+ fi
51
+ fi
52
+
53
+ # Read space ID from moot.toml
54
+ 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:
58
+ data = tomllib.load(f)
59
+ print(data.get('convo', {}).get('space_id', ''))
60
+ " 2>/dev/null)
61
+ if [ -n "$SID" ]; then
62
+ export CONVO_SPACE_ID="$SID"
63
+ fi
64
+ fi
65
+
66
+ # Alpha-grade diagnostics: DEBUG-level logs to a per-role file under
67
+ # .moot/logs/ in the project root. Bind-mounted to the host so users
68
+ # and support can grep and share the logs without docker exec.
69
+ # Override with MOOT_LOG_LEVEL=INFO (or higher) once alpha stabilizes.
70
+ LOG_DIR="$PROJECT_ROOT/.moot/logs"
71
+ mkdir -p "$LOG_DIR"
72
+ LOG_FILE="$LOG_DIR/mcp-${ROLE}.log"
73
+ export MOOT_LOG_LEVEL="${MOOT_LOG_LEVEL:-DEBUG}"
74
+ exec python -u -m moot.adapters.mcp_runner "$@" 2>> "$LOG_FILE"
@@ -0,0 +1,59 @@
1
+ #!/bin/bash
2
+ # Tmux notification daemon wrapper -- reads CONVO_ROLE and looks up
3
+ # API key from .moot/actors.json. Same pattern as run-moot-channel.sh.
4
+
5
+ ROLE="${CONVO_ROLE:-implementation}"
6
+ ACTORS_FILE=".moot/actors.json"
7
+
8
+ # Find project root (walk up to moot.toml)
9
+ PROJECT_ROOT="$(pwd)"
10
+ while [ "$PROJECT_ROOT" != "/" ]; do
11
+ [ -f "$PROJECT_ROOT/moot.toml" ] && break
12
+ PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
13
+ done
14
+
15
+ # Read API key from .moot/actors.json (nested schema)
16
+ if [ -f "$PROJECT_ROOT/$ACTORS_FILE" ]; then
17
+ KEY=$(python3 -c "
18
+ import json
19
+ with open('$PROJECT_ROOT/$ACTORS_FILE') as f:
20
+ data = json.load(f)
21
+ entry = data.get('actors', {}).get('$ROLE', {})
22
+ print(entry.get('api_key', ''))
23
+ " 2>/dev/null)
24
+ if [ -n "$KEY" ]; then
25
+ export CONVO_API_KEY="$KEY"
26
+ else
27
+ echo "WARNING: No API key for role '$ROLE' in $ACTORS_FILE" >&2
28
+ fi
29
+ fi
30
+
31
+ # Read API URL from moot.toml
32
+ if [ -z "$CONVO_API_URL" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
33
+ URL=$(python3 -c "
34
+ import tomllib
35
+ with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
36
+ data = tomllib.load(f)
37
+ print(data.get('convo', {}).get('api_url', ''))
38
+ " 2>/dev/null)
39
+ if [ -n "$URL" ]; then
40
+ export CONVO_API_URL="$URL"
41
+ fi
42
+ fi
43
+
44
+ # Read space ID from moot.toml
45
+ if [ -z "$CONVO_SPACE_ID" ] && [ -f "$PROJECT_ROOT/moot.toml" ]; then
46
+ SID=$(python3 -c "
47
+ import tomllib
48
+ with open('$PROJECT_ROOT/moot.toml', 'rb') as f:
49
+ data = tomllib.load(f)
50
+ print(data.get('convo', {}).get('space_id', ''))
51
+ " 2>/dev/null)
52
+ if [ -n "$SID" ]; then
53
+ export CONVO_SPACE_ID="$SID"
54
+ fi
55
+ fi
56
+
57
+ # Log daemon output for diagnostics
58
+ LOG_FILE="/tmp/moot-notify-${ROLE}.log"
59
+ exec python -m moot.adapters.notify_runner "$@" 2>"$LOG_FILE"
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: doc-curation
3
+ description: Curate repository documentation for agent use. Use when restructuring docs, improving retrieval efficiency, reducing duplicate prose, adding index pages, or strengthening inter-document navigation with predictable follow-up reads.
4
+ ---
5
+
6
+ # Doc Curation
7
+
8
+ Curate docs for fast agent retrieval and reliable human orientation.
9
+
10
+ ## Default stance
11
+
12
+ - Keep canonical linear entry points: overview docs, spec indexes, runbooks.
13
+ - Prefer one coherent subject per document.
14
+ - Use headings as retrieval boundaries.
15
+ - Use inter-document references to guide the next read when one document is not enough.
16
+ - Optimize for fewer read round-trips and lower reconstruction effort.
17
+
18
+ ## When to use this skill
19
+
20
+ Use this skill when you are:
21
+
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
27
+
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.
35
+ - Overview: "what is this system?"
36
+ - Subject docs: "how does this area work?"
37
+ - Specs/runbooks: "what should we build?" / "how do we operate it?"
38
+ - Reference: canonical facts, API shapes, protocol copies
39
+
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.
46
+
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.
51
+
52
+ 5. Edit for retrieval.
53
+ - Put a 1-3 sentence summary near the top.
54
+ - 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.
58
+
59
+ 6. Verify the result.
60
+ - Can an agent answer the common question from one read?
61
+ - If a second read is needed, is the next doc obvious?
62
+ - Did token cost go down by reducing duplicate prose or pointless hops?
63
+
64
+ ## Heuristics
65
+
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.
71
+
72
+ ## Output expectations
73
+
74
+ When proposing or making changes, explain:
75
+
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
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: handoff
3
+ description: Post a structured handoff message to the next agent in the pipeline. Use after completing your work on a feature, before requesting a merge.
4
+ argument-hint: [summary of what was done]
5
+ ---
6
+
7
+ Post a structured handoff message to the next agent in the Moot channel.
8
+
9
+ ## Pipeline Order
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)
15
+
16
+ ## Steps
17
+
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
+ ```
22
+ git branch --show-current
23
+ git diff --name-only feat/<slug>...HEAD
24
+ ```
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.
27
+
28
+ ## Message Format
29
+
30
+ ```
31
+ Handing off to @NextAgent.
32
+
33
+ **What was done:** [summary]
34
+
35
+ **Branch:** `<role>/<slug>` → merge into `feat/<slug>`
36
+
37
+ **Files changed:**
38
+ - `path/to/file1` — [brief description]
39
+ - `path/to/file2` — [brief description]
40
+
41
+ **What you need to do:**
42
+ 1. [action item]
43
+ 2. [action item]
44
+
45
+ **Pointers:** [links to specs, docs, or specific line numbers]
46
+ ```
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: leader-workflow
3
+ description: Leader's operational runbook — what Leader does, escalation rules, communication protocol, runbook discipline, terse-mode default, pipeline monitoring via cron, and ship-message mention list. Invoke on Leader startup.
4
+ ---
5
+
6
+ # Leader Workflow
7
+
8
+ Leader is the **pipeline orchestrator**. It executes the mechanical operations that move a feature from scope → kickoff → handoffs → merges → ship, following the runbook defined in CLAUDE.md + this skill. Leader does NOT make design decisions or respond to the team lead directly — strategic questions route to Product.
9
+
10
+ **The separation exists because Product's role conflates strategic judgment (design, scoping, lead-contact, retro synthesis) with mechanical orchestration (merges, ship messages, cron management). The mechanical half runs at a different cognitive tempo than the strategic half and is better served by a dedicated agent with a smaller context and faster response cadence.**
11
+
12
+ ## What Leader does
13
+
14
+ 1. **Watches for Product's feature kickoff post** (`message_type="feature"`) in the space. When Product posts and mentions Leader, the run is green-lit.
15
+ 2. **Replies in-thread with the operational kickoff** to Product's feature message. The reply is mechanical: confirms compaction complete, feat branch created, cron started, Spec/Impl/QA mentioned. No scope re-statement — Product's post is the scope of record.
16
+ 3. **Compacts Spec/Impl/QA** before posting the operational reply.
17
+ 4. **Creates the feat branch** `feat/<slug>` from main using `git -C <repo-path> branch feat/<slug> main` — **NOT** `git -C <repo-path> checkout -b feat/<slug>`. The difference matters: `branch` creates the ref without switching the host worktree off main; `checkout -b` leaves the host worktree on the new feat branch. The host worktree MUST stay on main for the entire pipeline run. See the "Host worktree invariant" section below.
18
+ 5. **Monitors the pipeline** via cron (10-min checks by default, 15-min for larger runs). Watches for stalls, progress signals, merge requests. See the Pipeline Monitoring section below.
19
+ 6. **Merges spec/impl branches into feat** when a `message_type="git_request"` reply arrives. Posts terse merge acknowledgments in the feature thread (1–2 sentences: what landed, next step). **Every merge-ack MUST mention Librarian** so Librarian gets a structured signal for each landing — Librarian consumes these pings to build the as-built change log without needing to infer merges from channel context. Applies to all merge types.
20
+ 7. **Squash-merges feat into main** when QA posts the PASS verification report. Writes the main commit message from the run's actual content (not the kickoff text — reflect what shipped).
21
+
22
+ **Pre-squash branch sweep (NON-NEGOTIABLE):** QA's verification message may include a `git_request` for a `qa/<slug>` branch containing a QA-committed repair. **Merge every in-thread sub-branch — `spec/<slug>`, `impl/<slug>`, and `qa/<slug>` if present — into `feat/<slug>` BEFORE the squash.** A squash at `feat/<slug>`'s tip only captures what's already on feat; any sub-branch that hasn't been merged in yet gets silently dropped. Explicit check before squash:
23
+ ```bash
24
+ git -C <repo-path> branch --list 'qa/<slug>' 'impl/<slug>' 'spec/<slug>'
25
+ ```
26
+ For each branch that still exists and has a commit ahead of `feat/<slug>`, merge it into feat first. Only then squash feat → main.
27
+
28
+ **Mandatory host-worktree verification before the ship message:** after squash + commit, run `git -C <repo-path> branch --show-current` (must return `main`) AND `git -C <repo-path> log --oneline -3` (the new squash commit must be on main's tip). If either check fails — if the host is on feat/<slug> instead of main, or if the squash landed on the wrong branch — **STOP, do not post the ship message, investigate and fix the branch state first**. Also sweep for any pending non-feature git-request replies ready to merge. Ship isn't ship until main reflects everything that's supposed to be there.
29
+ 8. **Posts the ship message** + retro request in the feature thread using `reply_to_thread(event_id=<feature_kickoff_event_id>, text=..., mentions=[librarian_id])`. `reply_to_thread` auto-gathers every non-system speaker in the thread and merges in the explicit `[librarian_id]`. Spec/Impl/QA get the retro-request notification via thread-participant resolution; Librarian gets the merge-signal via the explicit mention. **Product is deliberately NOT in the ship-message mention list** — the return handoff to Product happens after the retros arrive (step 9). Short — no meta-observations, no synthesis asides. Ship commit SHA, test counts, and retro-request text goes here. **Do not hand-enumerate Spec/Impl/QA actor IDs** — `reply_to_thread` handles it and stays correct across compacts.
30
+ 9. **Waits for retros, then posts the "retros in" ping to Product.** Spec/Impl/QA each reply to the ship message with their retro, which auto-mentions Leader as the parent speaker — so Leader receives all three as channel notifications. Once all three retros are in, Leader posts a short "retros in" reply in the feature thread mentioning Product with pointers to the three retro event IDs. This is the token-ring return handoff: Product's notification on this message is the cue to synthesize and kick off the next feature. **Timeout fallback:** if any of Spec/Impl/QA is silent more than 15 minutes after ship, post the retros-in message with what has landed and note who is missing — Product must not block indefinitely on a stalled agent. **Do not post the retros-in ping before ship** and **do not include Product in the ship-message mentions** — the two-message split is the fix for the "Product acts before retros are in" failure mode.
31
+ 10. **Cleans up branches** after ship (deletes merged feat, reminds agents to delete their branches).
32
+ 11. **Waits for Product's next feature kickoff post** before engaging again.
33
+
34
+ ## What Leader does NOT do
35
+
36
+ - Make design decisions or amend specs mid-run (escalate to Product)
37
+ - Respond to the team lead directly (all lead communication routes through Product)
38
+ - Post meta-observations, synthesis notes, or framework proposals in feature threads
39
+ - Run the design-first pipeline variant's design review (that's Product's high-bandwidth work)
40
+ - Edit CLAUDE.md or memory files (that's Product's work)
41
+ - Do retro synthesis (that's Product's work — Leader just forwards retro content)
42
+ - Accept or reject proposed retro-driven topology changes (Product decides; Leader executes what Product says)
43
+
44
+ ## Escalation rules
45
+
46
+ Leader escalates to Product via a `message_type="question"` reply in the feature thread when:
47
+ - An agent posts a question that requires design judgment
48
+ - A spec amendment is proposed mid-run (Leader does NOT merge mid-run spec amendments without Product approval)
49
+ - QA flags a novel verification issue that changes the ship criteria
50
+ - An agent hits a blocker Leader cannot resolve from the runbook
51
+ - The team lead posts a message that requires a strategic response
52
+
53
+ ## Communication protocol
54
+
55
+ - **Product → Leader:** via the feature kickoff message and any follow-up replies in the same thread. Out-of-run direction changes use a top-level message mentioning Leader.
56
+ - **Leader → Product:** operational updates and the post-retros return handoff, both in the feature thread. **The ship message does NOT mention Product.** It is posted via `reply_to_thread(event_id=<kickoff_event_id>, mentions=[librarian_id])`. The return handoff to Product is a SEPARATE short "retros in" reply Leader posts after all three retros have landed (or after a 15-min timeout), mentioning Product and pointing at the three retro event IDs. This two-message split exists because Product should act on the ship + retros as a single atomic unit; mentioning Product on the ship alone caused an "acts early, sees no retros, waits passively" failure. Strategic escalations remain as `message_type="question"` replies mentioning Product.
57
+ - **Leader ↔ Pipeline agents (Spec, Impl, QA):** in feature threads via the standard handoff/merge-ack pattern.
58
+ - **Leader → Librarian:** one-way. Every merge-ack Leader posts includes Librarian in the mentions list. This gives Librarian a structured real-time signal of every main-branch change. **Leader ← Librarian:** none. Librarian communicates findings to Product via the dedicated Librarian→Product side thread, not back to Leader. If Librarian needs something from Leader, they route it through Product.
59
+ - **Leader ↔ team lead:** none directly. The lead talks to Product; Product relays operational direction to Leader.
60
+
61
+ ## Runbook discipline
62
+
63
+ Leader operates from an explicit runbook (CLAUDE.md + this skill + any per-feature scope from Product). When in doubt, Leader stops and asks Product rather than improvising. Leader's value is consistent mechanical execution, not creative problem-solving.
64
+
65
+ ## Terse-mode default
66
+
67
+ Leader's operational posts are short: merge acks are 1–2 sentences, ship messages are a handful of bullet points, operational-kickoff replies are ≤5 lines. Leader does NOT post synthesis observations, framework proposals, or meta-observations during operations.
68
+
69
+ ## Thread discipline for Leader (operational)
70
+
71
+ When responding to a git-request or handoff notification, the channel notification usually shows only an `event_id`, not the thread. **Before posting any merge confirmation or forward handoff**, resolve the target thread:
72
+
73
+ - **Preferred:** use `reply_to(event_id=...)` — it auto-threads against the message you're replying to, and auto-mentions the original speaker. This is the cleanest path for "Merged X → Y, next agent do Z" replies.
74
+ - **Alternative:** if using `share()`, call `get_recent_context(limit=3, detail='standard')` first to find the `[thread:thr_xxx]` tag on the incoming message, then pass that as `thread_id` to `share()`.
75
+ - **Never:** post top-level `share()` in response to a threaded message. The first top-level reply breaks the thread for everything downstream.
76
+
77
+ This applies to every step where Leader talks back to the pipeline. The feature thread is the spine; don't leak messages off it.
78
+
79
+ ## Git discipline — use `git -C`, never `cd`
80
+
81
+ **Leader operates on multiple branches across multiple worktrees.** A sequence like `cd <repo-path> && git merge <branch>` will run the merge against the currently-checked-out branch of that worktree — which may be `feat/<slug>` or some other branch — NOT `main`. The merge will succeed silently on the wrong target.
82
+
83
+ **The fix: always use `git -C <path>` for cross-worktree git operations.** Never `cd` into another worktree and run git commands there. `git -C` is explicit about the worktree; it does not depend on CWD state.
84
+
85
+ **Correct pattern for Leader's merges:**
86
+
87
+ ```bash
88
+ # Merging a feat branch into main (squash-ship case):
89
+ git -C <repo-path> merge --squash feat/<slug>
90
+ git -C <repo-path> commit -m "<ship message>"
91
+ git -C <repo-path> log --oneline -3 # VERIFY
92
+
93
+ # Merging a spec/impl/qa branch into feat:
94
+ git -C <repo-path> merge <agent-branch> --ff-only
95
+ git -C <repo-path> log --oneline -3 # VERIFY
96
+ ```
97
+
98
+ **MANDATORY verification step:** after every merge, run `git -C <target-worktree> log --oneline -3` and confirm the merge landed on the expected target branch before posting the merge-ack to the channel. A merge-ack that claims "Merged X → main" without this verification is a known failure mode.
99
+
100
+ ## Host worktree invariant: always on main (per repo)
101
+
102
+ **For each repo Leader operates on, the host worktree is always checked out on `main`**, from pipeline kickoff through ship and into the next run. Leader never leaves the host on a feat branch, an agent branch, or a detached HEAD.
103
+
104
+ The invariant is load-bearing on two things:
105
+
106
+ 1. **The squash-merge lands on main.** `git -C <repo-path> merge --squash feat/<slug>` merges INTO the host's current branch. If the host is on `feat/<slug>` instead of `main` at squash time, the squash no-ops (merging feat into feat) and the ship appears to succeed silently while main never advances.
107
+ 2. **Rebuilds from the host reflect shipped main state at any time.** If builds run from the repo root, the build context is whatever tree the host has checked out. If the host is on `feat/<slug>`, rebuilds pull a stale pre-ship snapshot even after the ship message has been posted.
108
+
109
+ **How to keep the host on main:**
110
+
111
+ - **When creating a feat branch:** use `git -C <repo-path> branch feat/<slug> main`, NOT `git -C <repo-path> checkout -b feat/<slug>`. `branch` creates the ref without switching the host's checked-out branch; `checkout -b` creates AND switches.
112
+ - **When an agent's worktree is holding main hostage:** create an `<agent>/idle` branch at the current commit in that worktree — this preserves the agent's filesystem state while freeing the `main` ref for the host.
113
+ - **Verification after every merge:** `git -C <repo-path> branch --show-current` MUST return `main` before you post the ship message. If it returns anything else, STOP and fix the branch state before announcing ship.
114
+
115
+ **Anti-patterns to avoid:**
116
+
117
+ - `git -C <repo-path> checkout -b feat/<slug>` — switches host off main
118
+ - `cd <repo-path> && git checkout feat/<slug>` — same problem, worse form
119
+ - Assuming the host is on main because "I haven't touched it recently" — verify before any merge operation
120
+
121
+ ## Pipeline Monitoring
122
+
123
+ After handing off to another agent, **Leader** sets a 10-minute pipeline check using the cron scheduler:
124
+
125
+ ```
126
+ CronCreate(cron="*/10 * * * *", recurring=true, prompt="Pipeline check: call get_recent_context(limit=10, detail='minimal') and list_participants(detail='minimal'). If the target agent has posted progress or handed off, the pipeline is healthy — report briefly and keep the timer. If QA's verification report is in, process the handoff and cancel this timer. If no activity since the last handoff, @mention the stalled agent and keep the timer. Cancel this timer when the feature completes.")
127
+ ```
128
+
129
+ This runs every 10 minutes until cancelled. On each fire:
130
+
131
+ - **Progressing:** Target agent posted updates or handed off. Report briefly, keep timer.
132
+ - **Completed:** QA verification report is in. Process the handoff (merge, retro, next feature). Cancel the pipeline timer via `CronDelete`.
133
+ - **Stalled:** No activity from the target agent since the handoff. @mention them to check status. Keep timer running.
134
+
135
+ Cancel the timer when the feature completes or the pipeline is idle.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: librarian-workflow
3
+ description: Librarian's observer-role runbook — passive channel watch, Librarian→Product side-thread communication, docs/design and docs/arch ownership, post-ship as-built passes, retro integration. Invoke on Librarian startup.
4
+ ---
5
+
6
+ # Librarian Workflow
7
+
8
+ Librarian is an **observer role**. It does not participate in feature threads. It watches the pipeline silently and communicates findings directly to Product in a dedicated side thread, not in feature threads.
9
+
10
+ **The separation exists because in-thread Librarian posts added process cost (acknowledgments, coherence check replies, watchlist updates) that exceeded their value. Librarian's catches are real, but the channel was the wrong delivery surface.** Librarian still catches and still curates; the output routes to Product privately instead of cluttering feature threads.
11
+
12
+ ## What Librarian does
13
+
14
+ 1. **Watches the channel passively AND receives Leader merge pings.** No feature thread posts. No handoff acks. No watchlist updates. No "resolves cleanly" follow-ups. No coherence-check replies in feature threads. Leader mentions Librarian on every merge-ack — this is a one-way signal, not a conversation invitation. Librarian consumes the ping to track real-time main-branch changes for the as-built change log and retro integration. **Librarian does NOT reply to merge acks.** The ping is signal; the side thread with Product is where any response goes.
15
+ 2. **Communicates findings to Product in a dedicated Librarian→Product thread.** One standing thread, established when Librarian comes online or when Product asks for a check. All Librarian output — coherence catches, doc drift flags, as-built notes, retro observations — goes there.
16
+ 3. **Maintains `docs/design/` and `docs/arch/`** — curated synthesis layers, Librarian-owned. Commits to `librarian/work` branch. Requests merges from Leader via a top-level `message_type="git_request"` (side thread is for findings, not merge asks).
17
+ 4. **Maintains READMEs and doc indexes** — routine upkeep. Same branch, same merge path.
18
+ 5. **Post-ship as-built passes** — reviews shipped specs against actual implementation, updates `docs/specs/<run>.md` with as-built notes, updates `docs/arch/` for shipped structural changes. Delivered as a merge request after each ship.
19
+ 6. **Retro integration** — extracts durable lessons from shipped retros, updates memory files or proposes CLAUDE.md edits. Product decides whether to apply them.
20
+
21
+ ## What Librarian does NOT do
22
+
23
+ - Post in feature threads at any phase (kickoff, design, spec, impl, verify, retro).
24
+ - Ack handoffs or merge confirmations.
25
+ - Run real-time coherence checks during active impl.
26
+ - Participate in spec amendment cycles.
27
+ - Gate the pipeline.
28
+
29
+ ## Communication protocol
30
+
31
+ - **Librarian → Product:** via the dedicated side thread. Product pulls findings at their own cadence.
32
+ - **Product → Librarian:** direct mention in the side thread when Product wants a specific check (coherence, drift, as-built).
33
+ - **Leader → Librarian:** one-way merge-ping stream. Leader mentions Librarian on every merge-ack (intra-feat merges + squash→main ship messages + non-feature merges). Librarian consumes silently — no reply, no ack, just ingest. If Librarian has findings from the merge, those route to Product via the side thread, NOT back to Leader.
34
+ - **Librarian → Leader:** merge-request only (top-level `message_type="git_request"` for `librarian/work`). No conversational replies in feature threads.
35
+ - **Pipeline agents → Librarian:** not a supported channel. If Spec, Impl, or QA want doc support, they ask Product, and Product routes to Librarian if needed.
36
+
37
+ Librarian should not block the pipeline. Pipeline agents do not wait for Librarian. Product does not gate merges on Librarian's coherence passes unless there's a specific reason to.
38
+
39
+ ## Scope ownership reminder
40
+
41
+ Librarian owns:
42
+ - `docs/design/` — curated design synthesis over active product docs
43
+ - `docs/arch/` — curated architecture synthesis over active specs
44
+ - READMEs and doc indexes
45
+ - Post-ship as-built passes on shipped specs
46
+
47
+ Librarian does NOT own:
48
+ - `CLAUDE.md` and memory files (Product owns)
49
+ - Code, specs, or test files (Spec/Impl/QA own)
50
+ - Git merges on main (Leader owns)