@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.
- package/README.md +42 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
- package/templates/CLAUDE.md +233 -0
- package/templates/claude/hooks/auto-orient.sh +21 -0
- package/templates/claude/hooks/git-guard.sh +56 -0
- package/templates/claude/hooks/grep-baseline-diff.sh +41 -0
- package/templates/claude/hooks/handoff-status-check.sh +40 -0
- package/templates/claude/settings.json +51 -0
- package/templates/devcontainer/devcontainer.json +25 -0
- package/templates/devcontainer/post-create.sh +68 -0
- package/templates/devcontainer/run-moot-channel.sh +70 -0
- package/templates/devcontainer/run-moot-mcp.sh +74 -0
- package/templates/devcontainer/run-moot-notify.sh +59 -0
- package/templates/skills/doc-curation/SKILL.md +80 -0
- package/templates/skills/handoff/SKILL.md +46 -0
- package/templates/skills/leader-workflow/SKILL.md +135 -0
- package/templates/skills/librarian-workflow/SKILL.md +50 -0
- package/templates/skills/memory-audit/SKILL.md +85 -0
- package/templates/skills/product-workflow/SKILL.md +69 -0
- package/templates/skills/spec-checklist/SKILL.md +99 -0
- package/templates/skills/verify/SKILL.md +64 -0
- package/templates/teams/loop-3/CLAUDE.md +72 -0
- package/templates/teams/loop-3/README.md +6 -0
- package/templates/teams/loop-3/team.toml +108 -0
- package/templates/teams/loop-4/CLAUDE.md +72 -0
- package/templates/teams/loop-4/README.md +6 -0
- package/templates/teams/loop-4/team.toml +126 -0
- package/templates/teams/loop-4-observer/CLAUDE.md +76 -0
- package/templates/teams/loop-4-observer/README.md +7 -0
- package/templates/teams/loop-4-observer/team.toml +141 -0
- package/templates/teams/loop-4-parallel/CLAUDE.md +76 -0
- package/templates/teams/loop-4-parallel/README.md +6 -0
- package/templates/teams/loop-4-parallel/team.toml +142 -0
- package/templates/teams/loop-4-split-leader/CLAUDE.md +76 -0
- package/templates/teams/loop-4-split-leader/README.md +7 -0
- package/templates/teams/loop-4-split-leader/team.toml +140 -0
- package/templates/teams/loop-6/CLAUDE.md +43 -0
- package/templates/teams/loop-6/README.md +9 -0
- 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.
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|