@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
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @mootup/moot-templates
2
+
3
+ Canonical project templates for [`@mootup/moot-cli`](https://www.npmjs.com/package/@mootup/moot-cli) — skills, team layouts, devcontainer scaffolding, and Claude Code hooks.
4
+
5
+ The templates are the single source of truth for `moot init` scaffolding on both the Python and JavaScript sides of the mootup toolchain. The canonical tree lives in [`mootup-io/moot`](https://github.com/mootup-io/moot) at `src/moot/templates/`; this package vendors a byte-identical copy for JS consumers.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @mootup/moot-templates
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```js
16
+ import { getTemplatesDir, BUNDLED_SKILLS } from '@mootup/moot-templates';
17
+
18
+ console.log(getTemplatesDir());
19
+ // /absolute/path/to/node_modules/@mootup/moot-templates/templates
20
+
21
+ console.log(BUNDLED_SKILLS);
22
+ // ['product-workflow', 'spec-checklist', ...]
23
+ ```
24
+
25
+ ## What's bundled
26
+
27
+ - `templates/CLAUDE.md` — default CLAUDE.md for new projects
28
+ - `templates/claude/` — Claude Code settings + hooks
29
+ - `templates/devcontainer/` — devcontainer.json + runner scripts
30
+ - `templates/skills/` — 8 bundled agent-workflow skills
31
+ - `templates/teams/` — 5 team topologies (loop-3, loop-4, loop-4-observer, loop-4-parallel, loop-4-split-leader)
32
+
33
+ ## Maintenance
34
+
35
+ Contributors: templates live canonically in `mootup-io/moot/src/moot/templates/`. Edits land there. To refresh this package's vendored copy:
36
+
37
+ ```bash
38
+ # From the mootup-io/moot-cli-js monorepo root:
39
+ npm run -w @mootup/moot-templates sync:templates
40
+ ```
41
+
42
+ The parity test (`test/parity.test.ts`) enforces byte-identical equality between the vendored copy and the canonical source on every CI run.
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Absolute path to the bundled templates root.
3
+ *
4
+ * After `npm install`, the package layout on consumers' disk is:
5
+ * node_modules/@mootup/moot-templates/
6
+ * dist/index.js <- this module after build
7
+ * templates/ <- vendored template tree
8
+ *
9
+ * `dirname(import.meta.url)` resolves to .../dist; `../templates` reaches
10
+ * the sibling directory. Works identically in the source layout during
11
+ * development (src/index.ts is under packages/moot-templates/src, and
12
+ * templates/ is the sibling — but production always runs from dist/).
13
+ */
14
+ export declare function getTemplatesDir(): string;
15
+ /**
16
+ * Mirror of Python's `moot.scaffold.BUNDLED_SKILLS`. Names must stay in
17
+ * lock-step; the parity test enforces that every name listed here has a
18
+ * corresponding directory under `templates/skills/`.
19
+ */
20
+ export declare const BUNDLED_SKILLS: readonly string[];
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EASlC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { dirname, join } from 'node:path';
3
+ /**
4
+ * Absolute path to the bundled templates root.
5
+ *
6
+ * After `npm install`, the package layout on consumers' disk is:
7
+ * node_modules/@mootup/moot-templates/
8
+ * dist/index.js <- this module after build
9
+ * templates/ <- vendored template tree
10
+ *
11
+ * `dirname(import.meta.url)` resolves to .../dist; `../templates` reaches
12
+ * the sibling directory. Works identically in the source layout during
13
+ * development (src/index.ts is under packages/moot-templates/src, and
14
+ * templates/ is the sibling — but production always runs from dist/).
15
+ */
16
+ export function getTemplatesDir() {
17
+ const here = dirname(fileURLToPath(import.meta.url));
18
+ return join(here, '..', 'templates');
19
+ }
20
+ /**
21
+ * Mirror of Python's `moot.scaffold.BUNDLED_SKILLS`. Names must stay in
22
+ * lock-step; the parity test enforces that every name listed here has a
23
+ * corresponding directory under `templates/skills/`.
24
+ */
25
+ export const BUNDLED_SKILLS = [
26
+ 'product-workflow',
27
+ 'spec-checklist',
28
+ 'leader-workflow',
29
+ 'librarian-workflow',
30
+ 'handoff',
31
+ 'verify',
32
+ 'doc-curation',
33
+ 'memory-audit',
34
+ ];
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C,kBAAkB;IAClB,gBAAgB;IAChB,iBAAiB;IACjB,oBAAoB;IACpB,SAAS;IACT,QAAQ;IACR,cAAc;IACd,cAAc;CACN,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@mootup/moot-templates",
3
+ "version": "0.1.0-rc.0",
4
+ "description": "Canonical project templates (skills, teams, devcontainer, Claude hooks) for @mootup/moot-cli, synced from the mootup Python CLI source.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "templates",
18
+ "README.md"
19
+ ],
20
+ "engines": {
21
+ "node": ">=20.0.0"
22
+ },
23
+ "scripts": {
24
+ "sync:templates": "node scripts/sync-templates.mjs",
25
+ "build": "tsc -p tsconfig.build.json",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "lint": "tsc --noEmit",
29
+ "prepublishOnly": "npm run build && npm test"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.14.0",
33
+ "typescript": "^5.5.0",
34
+ "vitest": "^2.1.0"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ }
39
+ }
@@ -0,0 +1,233 @@
1
+ # {project_name}
2
+
3
+ > This file is the entry point your AI coding agents read when they connect to your project. It describes how the team works, what each role does, and the disciplines that keep the work coherent. Edit the sections marked `TODO:` to describe your specific project. The Agent Workflow section below is generic across all projects using Moot — leave it as-is unless you want to customize the team topology.
4
+ >
5
+ > Generated by `moot init` from the bundled mootup template. Maintained at `https://mootup.io/docs`.
6
+
7
+ ## Status
8
+
9
+ TODO: A short paragraph about what this project is and what state it's in. One to three sentences.
10
+
11
+ ## Tech stack
12
+
13
+ TODO: Bullet list of the major dependencies and tooling. Example:
14
+
15
+ - **Python 3.11+**, async throughout, Pydantic models
16
+ - **Node 22**, TypeScript
17
+ - **PostgreSQL 17**
18
+ - **Docker Compose** for local dev
19
+
20
+ ## Running components
21
+
22
+ TODO: Describe how to start the project locally. The default `moot init` flow assumes you have a Docker-based dev stack and a Claude Code coding agent on your laptop, but adjust to your setup.
23
+
24
+ ```bash
25
+ # Example
26
+ docker compose up -d
27
+ ```
28
+
29
+ ## Code conventions
30
+
31
+ TODO: Defaults below — adjust to your project. The agents will follow whatever you put here.
32
+
33
+ - Type-checked end to end
34
+ - Async everywhere where the runtime supports it
35
+ - Tests live alongside the code they exercise
36
+ - Verbose logging in active development; structured logging in production
37
+
38
+ ## Agent Workflow
39
+
40
+ This project uses Moot to coordinate a team of AI coding agents working in parallel on the same codebase. The agents communicate via a shared Convo space (the channel), share a git repository via per-agent worktrees, and follow a fixed pipeline topology that has been refined across many projects.
41
+
42
+ ### Roles
43
+
44
+ - **Product** — Strategic direction, feature scoping, design decisions. Primary point of contact with the human team lead. Owns CLAUDE.md edits, memory file curation, and retro synthesis. Composes feature kickoffs (`message_type="feature"`) and hands off to Leader for operational execution. Does NOT run the pipeline cron, post operational merge acks, or handle mechanical merges day-to-day. Full runbook in the `product-workflow` skill.
45
+ - **Leader** — Pipeline orchestration. Replies to Product's kickoff with the operational setup (feat branch, compaction, cron), merges sub-branches into feat, squash-merges to main at ship time. Day-to-day owner of git operations on main and feat branches. Does NOT make design decisions, amend specs mid-run, or respond to the team lead directly — escalates to Product via `message_type="question"` in the feature thread. Full runbook in the `leader-workflow` skill.
46
+ - **Spec** — Design docs, specifications, test plans, architecture review. Each spec includes a "Security considerations" section: auth requirements, input validation boundaries, data isolation, secrets handling. Spec-drafting discipline in the `spec-checklist` skill.
47
+ - **Implementation** — Code implementation based on specs. Writes common-case behavioral tests before handoff.
48
+ - **QA** — Test strategy, test implementation, feature verification. Owns the local test stack. Extends test coverage beyond spec requirements based on own analysis. Includes security verification: auth bypass attempts, input validation on user-controlled fields, XSS surface, tenant isolation. May commit small repairs directly when the intended behavior is unambiguous.
49
+ - **Librarian** — Observer role. Owns documentation directories (`docs/design/`, `docs/arch/`, `docs/site/`, READMEs), post-ship as-built passes, and retro integration. Does NOT post in feature threads; communicates doc findings to Product via a dedicated Librarian→Product side thread. Full runbook in the `librarian-workflow` skill.
50
+
51
+ ### Resource Ownership
52
+
53
+ Shared resources have a single owner to avoid contention. Other agents must request operations via the Convo channel.
54
+
55
+ | Resource | Owner | Others request via |
56
+ |----------|-------|--------------------|
57
+ | Git: main branch, feature branches, merges | Leader | `message_type="git_request"` reply |
58
+ | Test stack (rebuild, restart) | QA | `message_type="stack_request"` reply |
59
+ | CLAUDE.md, memory files, retro synthesis | Product | Leader reports; Product edits |
60
+ | `docs/design/`, `docs/arch/`, as-built passes | Librarian | Product requests via side thread |
61
+
62
+ ### Git Workflow
63
+
64
+ Each agent works in a **git worktree** at `<repo>/.worktrees/<role>/` to avoid filesystem contention. The host worktree (the repo's root path) stays on `main` and is owned by the host.
65
+
66
+ **Branch naming:**
67
+ - `feat/<slug>` — integration branch, Leader creates from main at feature start
68
+ - `spec/<slug>` — Spec's work branch for a feature
69
+ - `impl/<slug>` — Implementation's work branch
70
+ - `qa/<slug>` — QA's work branch (tests, verification fixes)
71
+ - `librarian/work` — Librarian's persistent work branch (doc updates)
72
+ - `product/<slug>` — Product's branches for CLAUDE.md edits, memory files, retro synthesis docs
73
+
74
+ **Branch hygiene:** Create a fresh branch per feature. Do not reuse branches from previous features.
75
+
76
+ **What Spec / Impl / QA / Librarian do per feature:** create your branch from `feat/<slug>`, commit your work, request merge from Leader with `message_type="git_request"` as a reply in the feature thread. Pull `feat/<slug>` into your worktree before starting if another agent has committed ahead of you. Everything downstream (branch creation, cron monitoring, squash-merging to main, posting the ship message, retros-in handoff) is Leader's job and lives in the `leader-workflow` skill.
77
+
78
+ **Non-feature commits** (small bug fixes, doc updates, config changes) that aren't part of an active feature branch can be committed individually or grouped — no squash required. Use judgment: related fixes can share a commit, unrelated ones should be separate.
79
+
80
+ ### Startup
81
+
82
+ On connecting to the Convo space (including restarts and resumes), every agent must:
83
+ 1. Pull main into their worktree: `git rebase main` (avoids stash dances from stale branches)
84
+ 2. Join the Convo space and subscribe to the channel (space ID in `CONVO_SPACE_ID` from `.env.local` or equivalent)
85
+ 3. Run `whoami` to verify identity is correctly configured
86
+ 4. Catch up: call `get_context_with_summary` (for long spaces) or `get_activity(detail="minimal")` (for recent changes) to understand what happened while away
87
+ 5. Post a `status_update` confirming identity and readiness
88
+ 6. **Load your role workflow skill** if your role has one. Invoke via the Skill tool:
89
+ - **Product** → `product-workflow`
90
+ - **Leader** → `leader-workflow`
91
+ - **Librarian** → `librarian-workflow`
92
+ - Spec/Implementation/QA have role-specific guidance in this document plus memory files; no dedicated workflow skill yet.
93
+
94
+ ### MCP Response Profiles
95
+
96
+ Use the `detail` parameter on read-heavy MCP tools to reduce token consumption:
97
+
98
+ | Context | Detail level | Why |
99
+ |---------|-------------|-----|
100
+ | Polling / timer checks | `minimal` | Timestamps + speakers only — enough to detect activity |
101
+ | Catch-up after idle | `standard` (default) | Full text needed to understand what happened |
102
+ | Debugging / deep inspection | `full` | Metadata, mentions, refs for troubleshooting |
103
+
104
+ Tools that support `detail`: `get_recent_context`, `get_mentions`, `list_participants`, `get_activity`, `get_context_with_summary`, `get_space_status`.
105
+
106
+ **Rule of thumb:** If you're checking *whether* something happened, use `minimal`. If you need to understand *what* happened, use `standard`. If you need to know *everything*, use `full`.
107
+
108
+ ### Work Pipeline
109
+
110
+ Work flows through agents in sequence, one feature at a time:
111
+
112
+ ```
113
+ Lead ──direction──> Product ──scope──> Leader ──kickoff──> Spec ──design──> Implementation ──build──> QA ──verify──> Leader ──ship──> Product ──retro/memory──> next run
114
+ ```
115
+
116
+ **Two layers of coordination:**
117
+
118
+ - **Strategic layer (Product, lead-facing):** the team lead talks to Product about what to build. Product makes design decisions, writes feature scope, negotiates clarifying questions with Spec during design-first runs, synthesizes retros into CLAUDE.md / memory / skills. Composes and posts the feature kickoff message (`message_type="feature"`) once the direction is locked, mentioning Leader to hand off operational execution.
119
+ - **Operational layer (Leader, pipeline-facing):** Leader takes over from Product's feature kickoff by replying in-thread with the operational kickoff and runs the run through the Spec/Impl/QA pipeline. Manages the cron, merges branches, squash-merges to main, posts ship messages.
120
+
121
+ **Comms test:** Before beginning work on a feature, Leader (in the operational kickoff reply) mentions Spec/Impl/QA and waits for acknowledgment. Work does not begin until every agent has confirmed they are listening. Librarian is NOT in the mention list (observer role).
122
+
123
+ Each handoff uses the `mentions` parameter on `share()` or `reply_to()` to notify the next agent by participant_id. **Use display names in message text** (e.g., "Implementation: pull the branch..."), not raw IDs. The `mentions` parameter handles notification delivery; the message text is for human readability. Without an explicit mention, the next agent never receives a channel notification and the pipeline stalls (token-ring failure).
124
+
125
+ **Status updates on handoff:** Every agent must call `update_status` when receiving or completing a handoff. This keeps the participant list and web UI status indicators accurate.
126
+
127
+ **After handing off: stop.** Post the handoff message, update your status, and wait for the next channel notification. Do NOT poll for the next agent's response. Do NOT acknowledge the prior agent's handoff — only post a status update. Polling burns tokens and produces no value.
128
+
129
+ **Thread discipline:** During pipeline runs, all messages go in the feature thread. Do not post top-level messages for handoffs, acks, or status updates — reply in the thread. Leader-specific thread routing (how to resolve a thread from an `event_id`-only notification) lives in the `leader-workflow` skill.
130
+
131
+ **No handoff acknowledgments.** When you receive a handoff, do NOT reply to the prior agent saying "acknowledged." Instead, update your status and start working. The prior agent should already be idle.
132
+
133
+ ### Pipeline Variants
134
+
135
+ - **Standard pipeline:** Product compacts Leader → posts feature kickoff (`message_type="feature"`) → Leader replies with operational kickoff → Spec → Impl → QA → Leader ships → Product reads retros.
136
+ - **Design-first pipeline:** adds a Product↔Spec `message_type="question"` design review before the kickoff, for features with semantic decisions or multiple open questions. Triage: mechanical lifts use standard pipeline; semantic work uses design-first.
137
+ - **Kickoff ownership:** Product composes kickoff content (scope, baseline, ship criteria, retro carryover); Leader adds operational details in the in-thread reply (feat branch, compact confirmation, cron, agent mentions).
138
+
139
+ ### Message Types
140
+
141
+ Messages carry a structured `message_type` metadata field, set via the `message_type` parameter on `share()`, `reply_to()`, `reply_to_thread()`, and `post_response()`. The frontend renders it as a colored pill on the message card and (for thread roots) on the thread sidebar entry.
142
+
143
+ **Taxonomy** (10 values):
144
+
145
+ | Value | When to use |
146
+ |---|---|
147
+ | `feature` | Product's kickoff message that opens a feature pipeline run |
148
+ | `question` | An agent needs clarification from another agent |
149
+ | `git_request` | Asking Leader to merge a branch |
150
+ | `stack_request` | Asking QA to rebuild / restart the test stack |
151
+ | `review_request` | Asking another agent for a code / doc / design review |
152
+ | `code_share` | Sharing a code snippet or diff for reference |
153
+ | `status_update` | Programmatic status update (set automatically by `update_status`) |
154
+ | `decision_propagated` | Cross-space decision propagation |
155
+ | `retro` | Retrospective message after ship |
156
+ | `bug` | Bug report (usually to Product or the owning agent) |
157
+
158
+ **Usage:** pass `message_type=` on the message call. Do NOT include a `[TYPE]` bracket prefix in the text body — the first line of the message renders as the thread title and should be natural prose.
159
+
160
+ ```python
161
+ share(
162
+ text="merge `impl/xxx` → `feat/xxx`\n\n...",
163
+ message_type="git_request",
164
+ thread_id=feature_thread_id,
165
+ )
166
+ ```
167
+
168
+ ### Channel Threading Protocol
169
+
170
+ The space has three kinds of threads, identified by the root message's `message_type`:
171
+
172
+ 1. **Feature threads** (`message_type="feature"`) — Product creates when kicking off a feature. All handoffs, status updates, completion notices, retros, and clarification questions for that feature go in this thread. This is the spine of the work.
173
+ 2. **Question threads** (`message_type="question"`) — Any agent creates when they need clarification from another agent. Mention the target agent. Answer in-thread, then the asker resumes work.
174
+ 3. **Git-request / stack-request threads** (`message_type="git_request"` or `"stack_request"`) — Created when an agent needs a resource owner (Leader, QA) to act. Owner replies with the result in-thread. During a feature run, a `git_request` typically lives as a reply inside the feature thread rather than a new top-level thread.
175
+
176
+ ### Clarification Flow
177
+
178
+ When an agent is blocked and needs input:
179
+ - Spec asks Product for requirements clarification (high-bandwidth design questions go through Product directly)
180
+ - Implementation asks Spec for design clarification via `message_type="question"` in the feature thread
181
+ - QA asks Spec for acceptance criteria clarification via `message_type="question"` in the feature thread
182
+ - Librarian asks Product via the Librarian→Product side thread (not feature threads)
183
+ - Leader escalates judgment calls to Product via a `message_type="question"` reply in the feature thread
184
+
185
+ ### Tracking Decisions
186
+
187
+ Use `propose_decision` for choices that involve tradeoffs, creativity, judgment, or non-obvious analysis — decisions where a different reasonable person might choose differently. These are moments that prune or expand the space of possible futures.
188
+
189
+ **When to track:**
190
+ - Architectural choices during spec work
191
+ - Process changes from retros
192
+ - Moments during debugging where a pre-implementation assumption turned out to be fundamentally wrong
193
+ - Design tradeoffs with non-obvious consequences
194
+
195
+ **When NOT to track:** Mechanical or purely deductive decisions — things obvious from the facts at hand.
196
+
197
+ **Value:** Future agents can query `list_decisions` to understand *why* things are the way they are.
198
+
199
+ ### Retrospective
200
+
201
+ After QA verifies and Leader confirms a feature has shipped, Spec/Impl/QA each post one short retro message in the feature thread with `message_type="retro"`. Each retro is a `reply_to` against Leader's ship message, which auto-mentions Leader so the retros-in handoff is reliable. Keep retros short — bullets, not paragraphs.
202
+
203
+ **Topology invariance principle:** retros may change how individual agents perform their work but must NOT change the team interaction topology. The pipeline topology (Lead → Product → Leader → Spec → Impl → QA → Leader → Product) is invariant. Retros optimize the work at each node, not the connections between nodes.
204
+
205
+ ### Test Access
206
+
207
+ TODO: Document how each agent runs tests against their environment. Example:
208
+
209
+ ```bash
210
+ # Adjust to your test stack
211
+ docker exec project-backend-1 pytest -n auto
212
+ ```
213
+
214
+ ### Platform instability
215
+
216
+ Transient API/backend errors (502, 504, connection reset, timeout) are a normal failure mode of containerized services, not anomalies worth investigating. Default response:
217
+
218
+ 1. **Retry the call immediately** (one retry). Most blips clear within a second.
219
+ 2. **If the retry fails, call `wait_for_health`** if available, otherwise wait 30s. Do not poll.
220
+ 3. **If still failing**, post a single status update ("backend unreachable, pausing work") and stop. Do not descend into diagnostic commands unless the outage persists past 2–3 minutes AND it's blocking something time-sensitive.
221
+
222
+ **What NOT to do:**
223
+ - Run diagnostics on a single failed call. One 502 is not an incident.
224
+ - Poll in a loop waiting for the backend to come back. One check, then wait for notification.
225
+ - Assume "can't reach channel" means "pipeline has stalled." If you're mid-work, keep working locally; post accumulated results when the channel recovers.
226
+
227
+ ## Doc conventions
228
+
229
+ - TODO: Where does your project's design documentation live?
230
+ - TODO: Where do specs live?
231
+ - TODO: Where do operational runbooks live?
232
+ - Reference don't repeat: link to source files rather than copying content
233
+ - Local environment files are gitignored; use `.env.example` as a template
@@ -0,0 +1,21 @@
1
+ #!/bin/bash
2
+ # SessionStart hook — emits additionalContext instructing the agent to
3
+ # call orientation + list_participants as its first action. Covers
4
+ # fresh sessions, /resume, /compact continuations (source field varies
5
+ # but the instruction is the same).
6
+ set -euo pipefail
7
+
8
+ # Read stdin JSON (we don't branch on source — the instruction is
9
+ # source-agnostic — but we parse it so a future change is a 1-line
10
+ # edit).
11
+ INPUT=$(cat)
12
+ SOURCE=$(echo "$INPUT" | jq -r '.source // "startup"')
13
+
14
+ cat <<JSON
15
+ {
16
+ "hookSpecificOutput": {
17
+ "hookEventName": "SessionStart",
18
+ "additionalContext": "Before your first substantive action this session: call mcp__convo__orientation() to pick up your identity, focus space, and recent context, then call mcp__convo__list_participants(detail='full') to see who else is online. Post a status_update confirming you are ready. Skip this if you have already oriented in the current turn. (Injected by SessionStart hook, source=$SOURCE.)"
19
+ }
20
+ }
21
+ JSON
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ # PreToolUse hook — blocks mutating git commands when the current
3
+ # working directory does not match $CONVO_WORKTREE.
4
+ #
5
+ # Read-only subcommands fall through (exit 0 with no stdout = allow).
6
+ # Mutating subcommands emit a deny decision with the exact mismatch.
7
+ set -euo pipefail
8
+
9
+ INPUT=$(cat)
10
+ CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
11
+
12
+ # Not a Bash tool call, or no command — allow.
13
+ [ -z "$CMD" ] && exit 0
14
+
15
+ # Only care about git invocations. Match `git ` at word start (handles
16
+ # leading env overrides like `GIT_PAGER=cat git ...`). Grep is enough;
17
+ # we don't need a full parser.
18
+ if ! echo "$CMD" | grep -qE '(^|\s|;|&&|\|\|)git(\s|$)'; then
19
+ exit 0
20
+ fi
21
+
22
+ # Denylist of mutating subcommands. Fail-closed: unknown subcommands
23
+ # fall through (allow), but matched mutating ones are checked.
24
+ MUTATING='commit|merge|reset|rebase|cherry-pick|push|tag|clean\s+-[fd]|stash\s+drop|worktree\s+remove|branch\s+-[dD]|checkout\s+-[bB]'
25
+
26
+ if ! echo "$CMD" | grep -qE "\\bgit\\s+($MUTATING)\\b"; then
27
+ exit 0
28
+ fi
29
+
30
+ # Mutating command detected. Verify worktree match.
31
+ EXPECTED="${CONVO_WORKTREE:-}"
32
+ if [ -z "$EXPECTED" ]; then
33
+ # No worktree expectation set — allow (hook can't guard what it
34
+ # doesn't know). This is the case for host-clone sessions outside
35
+ # the agent launchers.
36
+ exit 0
37
+ fi
38
+
39
+ ACTUAL=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
40
+ EXPECTED_CANON=$(realpath "$EXPECTED" 2>/dev/null || echo "$EXPECTED")
41
+ ACTUAL_CANON=$(realpath "$ACTUAL" 2>/dev/null || echo "$ACTUAL")
42
+
43
+ if [ "$EXPECTED_CANON" = "$ACTUAL_CANON" ]; then
44
+ exit 0
45
+ fi
46
+
47
+ # Mismatch — block.
48
+ REASON="Cross-worktree git mutation blocked: CWD resolves to '$ACTUAL_CANON' but CONVO_WORKTREE is '$EXPECTED_CANON'. Change directory to the expected worktree before running mutating git commands, or unset CONVO_WORKTREE if this is a deliberate host-clone operation."
49
+
50
+ jq -n --arg reason "$REASON" '{
51
+ hookSpecificOutput: {
52
+ hookEventName: "PreToolUse",
53
+ permissionDecision: "deny",
54
+ permissionDecisionReason: $reason
55
+ }
56
+ }'
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook — caches Grep results keyed by (pattern, path) and
3
+ # warns when an identical grep returns a different count within the
4
+ # same session. Non-blocking.
5
+ set -euo pipefail
6
+
7
+ INPUT=$(cat)
8
+ SESSION=$(echo "$INPUT" | jq -r '.session_id // empty')
9
+ PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty')
10
+ SEARCH_PATH=$(echo "$INPUT" | jq -r '.tool_input.path // "."')
11
+ RESPONSE=$(echo "$INPUT" | jq -r '.tool_response // empty')
12
+
13
+ [ -z "$SESSION" ] || [ -z "$PATTERN" ] && exit 0
14
+
15
+ CACHE=/tmp/convo-grep-cache-"$SESSION".json
16
+ KEY=$(echo "${PATTERN}|${SEARCH_PATH}" | sha256sum | cut -d' ' -f1)
17
+
18
+ # Count matches in this response — the Grep tool's output format
19
+ # varies by output_mode; use line count as a cheap proxy.
20
+ COUNT=$(echo "$RESPONSE" | wc -l)
21
+
22
+ # Read prior count if cached.
23
+ PRIOR=""
24
+ if [ -f "$CACHE" ]; then
25
+ PRIOR=$(jq -r --arg k "$KEY" '.[$k] // empty' "$CACHE" 2>/dev/null || echo "")
26
+ fi
27
+
28
+ # Write current count back to cache.
29
+ mkdir -p "$(dirname "$CACHE")"
30
+ if [ -f "$CACHE" ]; then
31
+ jq --arg k "$KEY" --argjson v "$COUNT" '.[$k] = $v' "$CACHE" > "$CACHE.tmp" && mv "$CACHE.tmp" "$CACHE"
32
+ else
33
+ jq -n --arg k "$KEY" --argjson v "$COUNT" '{($k): $v}' > "$CACHE"
34
+ fi
35
+
36
+ # Warn if count drifted.
37
+ if [ -n "$PRIOR" ] && [ "$PRIOR" != "$COUNT" ]; then
38
+ echo "NOTICE: grep baseline drift — pattern='$PATTERN' path='$SEARCH_PATH' prior=$PRIOR current=$COUNT. A baseline measured earlier this session no longer matches; if you are mid-spec, re-ground before treating the current count as the new baseline." >&2
39
+ fi
40
+
41
+ exit 0
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # Stop hook — warns when the turn posts an mcp__convo__share (with
3
+ # mentions) but does not also call mcp__convo__update_status. Does
4
+ # NOT block; emits a system reminder for the next turn via stderr.
5
+ set -euo pipefail
6
+
7
+ INPUT=$(cat)
8
+ TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // empty')
9
+ [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ] && exit 0
10
+
11
+ # Find the last user-turn boundary: scan backward for the last line
12
+ # where type=user and the content is NOT a tool_result or system
13
+ # reminder. Everything after that is the current assistant turn.
14
+ LAST_USER_LINE=$(awk -v target='"type":"user"' '
15
+ $0 ~ target && $0 !~ /"tool_use_id"/ && $0 !~ /system-reminder/ { last=NR }
16
+ END { print last }
17
+ ' "$TRANSCRIPT")
18
+
19
+ [ -z "$LAST_USER_LINE" ] && exit 0
20
+
21
+ # Slice the turn's assistant entries.
22
+ TURN=$(awk -v start="$LAST_USER_LINE" 'NR > start' "$TRANSCRIPT")
23
+
24
+ # Detect handoff signal: mcp__convo__share or mcp__convo__reply_to
25
+ # with a non-empty mentions array.
26
+ HANDOFF=$(echo "$TURN" | grep -cE '"name":"mcp__convo__(share|reply_to|reply_to_thread)"' || true)
27
+ STATUS=$(echo "$TURN" | grep -cE '"name":"mcp__convo__update_status"' || true)
28
+
29
+ # Only fire when handoff present AND status_update absent AND the
30
+ # share/reply had mentions. Last check: grep the turn for a non-empty
31
+ # mentions array on any convo post.
32
+ MENTIONS=$(echo "$TURN" | grep -cE '"mentions":\["[^"]' || true)
33
+
34
+ if [ "$HANDOFF" -gt 0 ] && [ "$MENTIONS" -gt 0 ] && [ "$STATUS" -eq 0 ]; then
35
+ echo "WARNING: handoff message with mentions detected, but no mcp__convo__update_status call this turn. Pipeline handoffs must update status (CLAUDE.md § Status updates on handoff). Next turn should call update_status before returning to idle." >&2
36
+ # Exit 0 — non-blocking warning. stderr lands in the transcript
37
+ # for the operator and is injected as system context next turn.
38
+ fi
39
+
40
+ exit 0
@@ -0,0 +1,51 @@
1
+ {
2
+ "permissions": {
3
+ "defaultMode": "bypassPermissions"
4
+ },
5
+ "hooks": {
6
+ "SessionStart": [
7
+ {
8
+ "matcher": "",
9
+ "hooks": [
10
+ {
11
+ "type": "command",
12
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-orient.sh"
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "PreToolUse": [
18
+ {
19
+ "matcher": "Bash",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/git-guard.sh"
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "PostToolUse": [
29
+ {
30
+ "matcher": "Grep",
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/grep-baseline-diff.sh"
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ "Stop": [
40
+ {
41
+ "matcher": "",
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/handoff-status-check.sh"
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ }
51
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "moot-agent-team",
3
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:22",
4
+ "features": {
5
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
6
+ "moby": false
7
+ },
8
+ "ghcr.io/devcontainers/features/python:1": {
9
+ "version": "3.11"
10
+ }
11
+ },
12
+ "postCreateCommand": "bash .devcontainer/post-create.sh",
13
+ "runArgs": [
14
+ "--name", "moot-${localWorkspaceFolderBasename}"
15
+ ],
16
+ "customizations": {
17
+ "vscode": {
18
+ "extensions": [
19
+ "ms-python.python",
20
+ "ms-pyright.pyright"
21
+ ]
22
+ }
23
+ },
24
+ "remoteUser": "node"
25
+ }