cohorte 1.0.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/CHANGELOG.md +264 -0
- package/LICENSE +661 -0
- package/README.md +269 -0
- package/bin/cli.js +339 -0
- package/core/agents/implementer.template.md +74 -0
- package/core/agents/release.md +51 -0
- package/core/agents/review.md +85 -0
- package/core/commands/align-ds.md +32 -0
- package/core/commands/audit.md +31 -0
- package/core/commands/brainstorm.md +48 -0
- package/core/commands/build.md +91 -0
- package/core/commands/doctor.md +50 -0
- package/core/commands/fix.md +62 -0
- package/core/commands/init-pipeline.md +32 -0
- package/core/commands/refactor.md +38 -0
- package/core/commands/review.md +68 -0
- package/core/commands/ship.md +68 -0
- package/core/commands/smoke.md +55 -0
- package/core/commands/spec.md +67 -0
- package/core/commands/update-pipeline.md +96 -0
- package/core/hooks/__pycache__/gate.cpython-312.pyc +0 -0
- package/core/hooks/gate.py +129 -0
- package/core/templates/agent-handoff.md +34 -0
- package/core/templates/brainstorm-return.md +36 -0
- package/core/templates/design-brief.md +35 -0
- package/core/templates/pr-body.md +29 -0
- package/core/templates/review-feedback.md +36 -0
- package/core/templates/spec.template.md +84 -0
- package/core/templates/steps/init-pipeline/01-detect-stack.md +40 -0
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +41 -0
- package/core/templates/steps/init-pipeline/03-draft-profile.md +10 -0
- package/core/templates/steps/init-pipeline/04-write-render.md +88 -0
- package/core/templates/steps/init-pipeline/05-report.md +12 -0
- package/dashboard/README.md +54 -0
- package/dashboard/dist/apple-touch-icon-180.png +0 -0
- package/dashboard/dist/assets/index-CoBuEdy-.js +42 -0
- package/dashboard/dist/assets/index-DN5OGW9g.css +1 -0
- package/dashboard/dist/favicon-16.png +0 -0
- package/dashboard/dist/favicon-32.png +0 -0
- package/dashboard/dist/favicon-48.png +0 -0
- package/dashboard/dist/icon-192.png +0 -0
- package/dashboard/dist/icon-512.png +0 -0
- package/dashboard/dist/index.html +16 -0
- package/dashboard/server/doctor.js +266 -0
- package/dashboard/server/fleet.js +119 -0
- package/dashboard/server/index.js +306 -0
- package/dashboard/server/kanban.js +158 -0
- package/dashboard/server/versions.js +111 -0
- package/dashboard/server/yaml.js +126 -0
- package/install.ps1 +359 -0
- package/install.sh +301 -0
- package/package.json +40 -0
- package/profile/PIPELINE.template.md +208 -0
- package/profile/SCHEMA.md +303 -0
- package/profile/cohorte.config.template.yaml +43 -0
- package/scripts/new-feature.sh.template +89 -0
- package/scripts/remove-feature.sh.template +53 -0
package/install.sh
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# install.sh — install the portable multi-agent pipeline.
|
|
4
|
+
# POSIX sh (works with dash/bash/zsh).
|
|
5
|
+
#
|
|
6
|
+
# Per-project install (default — bundles the core into <target>/.claude, committable):
|
|
7
|
+
# sh install.sh [target_dir]
|
|
8
|
+
# curl -fsSL <raw-url>/install.sh | sh
|
|
9
|
+
#
|
|
10
|
+
# Global install (one core in ~/.claude, shared by every repo on this machine):
|
|
11
|
+
# sh install.sh --global
|
|
12
|
+
# curl -fsSL <raw-url>/install.sh | sh -s -- --global
|
|
13
|
+
#
|
|
14
|
+
# Update the generic core in place (keeps any generated PIPELINE.md + rendered agents):
|
|
15
|
+
# sh install.sh --update [target_dir]
|
|
16
|
+
# sh install.sh --update --global
|
|
17
|
+
#
|
|
18
|
+
# Per-project install copies the core into <target>/.claude; global install copies it once
|
|
19
|
+
# into ~/.claude and registers the gate hook there. Either way you then run `/init-pipeline`
|
|
20
|
+
# in each repo to generate PIPELINE.md + render the surface agents. Update refreshes ONLY the
|
|
21
|
+
# stack-agnostic files; generated profiles, rendered agents, gate-config.json and any project
|
|
22
|
+
# settings.json are left untouched.
|
|
23
|
+
|
|
24
|
+
set -eu
|
|
25
|
+
|
|
26
|
+
REPO_URL="${PIPELINE_REPO:-https://github.com/TheBidouilleAgency/cohorte}"
|
|
27
|
+
|
|
28
|
+
mode="install"
|
|
29
|
+
scope="project"
|
|
30
|
+
positional=""
|
|
31
|
+
while [ $# -gt 0 ]; do
|
|
32
|
+
case "$1" in
|
|
33
|
+
--update) mode="update"; shift ;;
|
|
34
|
+
--global) scope="global"; shift ;;
|
|
35
|
+
--) shift; break ;;
|
|
36
|
+
-*) echo "error: unknown flag: $1" >&2; exit 2 ;;
|
|
37
|
+
*) positional="$1"; shift ;;
|
|
38
|
+
esac
|
|
39
|
+
done
|
|
40
|
+
target="${positional:-$PWD}"
|
|
41
|
+
|
|
42
|
+
# --- locate the source (this checkout, or clone if piped via curl) ----------
|
|
43
|
+
src=""
|
|
44
|
+
self="${0:-}"
|
|
45
|
+
self_dir=""
|
|
46
|
+
case "$self" in
|
|
47
|
+
*/*) self_dir=$(CDPATH= cd -- "$(dirname -- "$self")" && pwd) ;;
|
|
48
|
+
esac
|
|
49
|
+
if [ -n "$self_dir" ] && [ -d "$self_dir/core" ]; then
|
|
50
|
+
src="$self_dir"
|
|
51
|
+
else
|
|
52
|
+
echo "→ fetching pipeline from $REPO_URL"
|
|
53
|
+
tmp=$(mktemp -d)
|
|
54
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
55
|
+
git clone --depth 1 "$REPO_URL" "$tmp/pipeline" >/dev/null 2>&1
|
|
56
|
+
src="$tmp/pipeline"
|
|
57
|
+
fi
|
|
58
|
+
[ -d "$src/core" ] || { echo "error: pipeline source not found (no core/ in $src)" >&2; exit 1; }
|
|
59
|
+
|
|
60
|
+
# --- resolve the destination .claude dir ------------------------------------
|
|
61
|
+
if [ "$scope" = "global" ]; then
|
|
62
|
+
dest="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
63
|
+
else
|
|
64
|
+
dest="$target/.claude"
|
|
65
|
+
fi
|
|
66
|
+
mkdir -p "$dest"
|
|
67
|
+
|
|
68
|
+
# version stamp so a per-repo pointer can record which core it expects:
|
|
69
|
+
# the package.json semver, with the git sha for traceability on from-main installs
|
|
70
|
+
semver=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$src/package.json" 2>/dev/null | head -n 1)
|
|
71
|
+
sha=$(git -C "$src" rev-parse --short HEAD 2>/dev/null || true)
|
|
72
|
+
if [ -n "$semver" ] && [ -n "$sha" ]; then ver="$semver ($sha)"
|
|
73
|
+
elif [ -n "$semver" ]; then ver="$semver"
|
|
74
|
+
else ver="${sha:-unknown}"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
copy_core() {
|
|
78
|
+
cp -R "$src/core/commands" "$dest/"
|
|
79
|
+
cp -R "$src/core/hooks" "$dest/"
|
|
80
|
+
cp -R "$src/core/templates" "$dest/"
|
|
81
|
+
# 0.1.19 renamed questionnaire-domain-brief.md → research-brief.md; drop the stale copy.
|
|
82
|
+
rm -f "$dest/templates/questionnaire-domain-brief.md"
|
|
83
|
+
mkdir -p "$dest/pipeline/scripts"
|
|
84
|
+
cp "$src/profile/PIPELINE.template.md" "$dest/pipeline/"
|
|
85
|
+
cp "$src/profile/SCHEMA.md" "$dest/pipeline/"
|
|
86
|
+
cp "$src/profile/cohorte.config.template.yaml" "$dest/pipeline/"
|
|
87
|
+
cp "$src"/scripts/*.template "$dest/pipeline/scripts/"
|
|
88
|
+
cp "$src/core/agents/implementer.template.md" "$dest/pipeline/"
|
|
89
|
+
[ -f "$src/CHANGELOG.md" ] && cp "$src/CHANGELOG.md" "$dest/pipeline/"
|
|
90
|
+
printf '%s\n' "$ver" > "$dest/pipeline/VERSION"
|
|
91
|
+
chmod +x "$dest/hooks/gate.py" 2>/dev/null || true
|
|
92
|
+
scrub_tdd_gate
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# The TDD gate was removed in 0.1.6. Older installs have hooks/tdd_gate.py on disk and
|
|
96
|
+
# registered in settings.json — copy-over never deletes, and a registered hook whose file
|
|
97
|
+
# is gone errors on every Write/Edit, so scrub both.
|
|
98
|
+
scrub_tdd_gate() {
|
|
99
|
+
rm -f "$dest/hooks/tdd_gate.py"
|
|
100
|
+
[ -f "$dest/settings.json" ] || return 0
|
|
101
|
+
command -v python3 >/dev/null 2>&1 || return 0
|
|
102
|
+
python3 - "$dest/settings.json" <<'PY'
|
|
103
|
+
import json, sys
|
|
104
|
+
settings = sys.argv[1]
|
|
105
|
+
try:
|
|
106
|
+
with open(settings) as fh:
|
|
107
|
+
data = json.load(fh)
|
|
108
|
+
except Exception:
|
|
109
|
+
sys.exit(0)
|
|
110
|
+
pre = data.get("hooks", {}).get("PreToolUse")
|
|
111
|
+
if not isinstance(pre, list):
|
|
112
|
+
sys.exit(0)
|
|
113
|
+
kept = [e for e in pre if not any(
|
|
114
|
+
h.get("command", "").strip().endswith("tdd_gate.py") for h in e.get("hooks", []))]
|
|
115
|
+
if len(kept) != len(pre):
|
|
116
|
+
data["hooks"]["PreToolUse"] = kept
|
|
117
|
+
with open(settings, "w") as fh:
|
|
118
|
+
json.dump(data, fh, indent=2)
|
|
119
|
+
fh.write("\n")
|
|
120
|
+
print(" · removed the retired tdd_gate.py hook (file + settings registration)")
|
|
121
|
+
PY
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# the fixed (non-rendered) agents: the dev review/release pipeline agents
|
|
125
|
+
copy_fixed_agents() {
|
|
126
|
+
mkdir -p "$dest/agents"
|
|
127
|
+
cp "$src/core/agents/review.md" "$src/core/agents/release.md" \
|
|
128
|
+
"$dest/agents/"
|
|
129
|
+
# 0.1.19 split the bi-mode questionnaire-researcher into research-agent + questionnaire-architect;
|
|
130
|
+
# copy-over never deletes, so scrub the retired agent lest a dead subagent_type linger.
|
|
131
|
+
rm -f "$dest/agents/questionnaire-researcher.md"
|
|
132
|
+
scrub_research_questionnaire
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# The research + questionnaire capability was removed. Older installs have its agents, commands,
|
|
136
|
+
# templates and template-step dirs on disk; copy-over never deletes, so scrub every orphan.
|
|
137
|
+
scrub_research_questionnaire() {
|
|
138
|
+
rm -f "$dest/agents/research-agent.md" \
|
|
139
|
+
"$dest/agents/questionnaire-architect.md" \
|
|
140
|
+
"$dest/agents/questionnaire-writer.md" \
|
|
141
|
+
"$dest/agents/questionnaire-validator.md" \
|
|
142
|
+
"$dest/commands/research.md" \
|
|
143
|
+
"$dest/commands/questionnaire.md" \
|
|
144
|
+
"$dest/templates/research-brief.md" \
|
|
145
|
+
"$dest/templates/questionnaire-blueprint.md" \
|
|
146
|
+
"$dest/templates/questionnaire-declaration.md" \
|
|
147
|
+
"$dest/templates/questionnaire-verdict.md"
|
|
148
|
+
rm -rf "$dest/templates/steps/research" "$dest/templates/steps/questionnaire"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# pipeline capability config is USER-level (vault, Notion DB, kanban boards) — it lives in
|
|
152
|
+
# ~/.claude regardless of install scope. Seed it only if neither the consolidated nor the
|
|
153
|
+
# legacy copy exists. This piped installer is non-interactive: it seeds disabled defaults;
|
|
154
|
+
# /init-pipeline + /update-pipeline wire it (npx's installer offers a quick interview instead).
|
|
155
|
+
seed_config() {
|
|
156
|
+
base="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
157
|
+
cfg="$base/cohorte.config.yaml"
|
|
158
|
+
legacy=""
|
|
159
|
+
for n in thebidouille.config.yaml; do
|
|
160
|
+
[ -f "$base/$n" ] && { legacy="$base/$n"; break; }
|
|
161
|
+
done
|
|
162
|
+
if [ -f "$cfg" ]; then
|
|
163
|
+
echo " · kept your existing $cfg"
|
|
164
|
+
elif [ -n "$legacy" ]; then
|
|
165
|
+
echo " · found legacy $legacy — kept as-is (read as a fallback)."
|
|
166
|
+
echo " Run /update-pipeline to migrate it into cohorte.config.yaml + wire the kanban."
|
|
167
|
+
else
|
|
168
|
+
mkdir -p "$base"
|
|
169
|
+
cp "$src/profile/cohorte.config.template.yaml" "$cfg"
|
|
170
|
+
echo " · seeded $cfg (disabled defaults — enable via /init-pipeline or /update-pipeline)"
|
|
171
|
+
fi
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Register the profile-driven gate hook in the GLOBAL settings.json. Idempotent: the
|
|
175
|
+
# hook reads each repo's own .claude/gate-config.json (and no-ops where absent),
|
|
176
|
+
# so one registration serves every project.
|
|
177
|
+
register_global_hook() {
|
|
178
|
+
python3 - "$dest/settings.json" "$dest/hooks/gate.py" <<'PY'
|
|
179
|
+
import json, sys
|
|
180
|
+
settings, gate = sys.argv[1], sys.argv[2]
|
|
181
|
+
# (hook path, PreToolUse matcher)
|
|
182
|
+
hooks = [(gate, "Bash")]
|
|
183
|
+
try:
|
|
184
|
+
with open(settings) as fh:
|
|
185
|
+
data = json.load(fh)
|
|
186
|
+
if not isinstance(data, dict):
|
|
187
|
+
data = {}
|
|
188
|
+
except Exception:
|
|
189
|
+
data = {}
|
|
190
|
+
pre = data.setdefault("hooks", {}).setdefault("PreToolUse", [])
|
|
191
|
+
for path, matcher in hooks:
|
|
192
|
+
base = path.rsplit("/", 1)[-1]
|
|
193
|
+
already = any(
|
|
194
|
+
h.get("command", "").strip().endswith(base)
|
|
195
|
+
for entry in pre for h in entry.get("hooks", [])
|
|
196
|
+
)
|
|
197
|
+
if not already:
|
|
198
|
+
pre.append({"matcher": matcher,
|
|
199
|
+
"hooks": [{"type": "command", "command": "python3 " + path}]})
|
|
200
|
+
with open(settings, "w") as fh:
|
|
201
|
+
json.dump(data, fh, indent=2)
|
|
202
|
+
fh.write("\n")
|
|
203
|
+
print("ok")
|
|
204
|
+
PY
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Bump only the core_version in a repo's committed .claude/pipeline.json (bundled mode).
|
|
208
|
+
# Leaves every other field intact; no-ops if the pointer is absent or has no core_version.
|
|
209
|
+
bump_pointer_version() {
|
|
210
|
+
ptr="$1"; newver="$2"
|
|
211
|
+
[ -f "$ptr" ] || return 0
|
|
212
|
+
python3 - "$ptr" "$newver" <<'PY'
|
|
213
|
+
import json, sys
|
|
214
|
+
ptr, newver = sys.argv[1], sys.argv[2]
|
|
215
|
+
try:
|
|
216
|
+
with open(ptr) as fh:
|
|
217
|
+
data = json.load(fh)
|
|
218
|
+
except Exception:
|
|
219
|
+
sys.exit(0)
|
|
220
|
+
if isinstance(data, dict) and "core_version" in data:
|
|
221
|
+
data["core_version"] = newver
|
|
222
|
+
with open(ptr, "w") as fh:
|
|
223
|
+
json.dump(data, fh, indent=2, ensure_ascii=False)
|
|
224
|
+
fh.write("\n")
|
|
225
|
+
PY
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if [ "$scope" = "global" ]; then
|
|
229
|
+
if [ "$mode" = "install" ]; then
|
|
230
|
+
echo "→ installing pipeline core GLOBALLY into $dest"
|
|
231
|
+
else
|
|
232
|
+
echo "→ updating pipeline core GLOBALLY in $dest (keeping global settings.json)"
|
|
233
|
+
fi
|
|
234
|
+
copy_fixed_agents
|
|
235
|
+
copy_core
|
|
236
|
+
hook_state=$(register_global_hook || echo "skipped")
|
|
237
|
+
seed_config
|
|
238
|
+
cat <<EOF
|
|
239
|
+
|
|
240
|
+
✓ pipeline core installed globally into $dest (version $ver)
|
|
241
|
+
gate hook: $hook_state (reads each repo's .claude/gate-config.json; silent where absent)
|
|
242
|
+
|
|
243
|
+
The commands (/init-pipeline, /brainstorm, /build …) and the review/release agents are now
|
|
244
|
+
available in EVERY project on this machine — nothing is copied per repo.
|
|
245
|
+
|
|
246
|
+
Per repo:
|
|
247
|
+
1. Open the project in Claude Code.
|
|
248
|
+
2. Run /init-pipeline — it generates PIPELINE.md, renders the surface agents, writes
|
|
249
|
+
.claude/gate-config.json, and drops a committed .claude/pipeline.json pointer so
|
|
250
|
+
teammates know to install the global core ($REPO_URL).
|
|
251
|
+
3. Commit PIPELINE.md + .claude/, then /brainstorm to start a feature.
|
|
252
|
+
|
|
253
|
+
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
254
|
+
uv tool install -p 3.13 serena-agent # once per machine
|
|
255
|
+
Make sure ~/.local/bin is on PATH (uv tool update-shell) — otherwise the
|
|
256
|
+
registered MCP server silently fails to start.
|
|
257
|
+
|
|
258
|
+
Global kanban config, user-scoped — optional:
|
|
259
|
+
· One consolidated file: ~/.claude/cohorte.config.yaml (don't hand-edit it).
|
|
260
|
+
· /init-pipeline (new project) and /update-pipeline (existing) wire it for you: creating +
|
|
261
|
+
syncing an Obsidian kanban board of the pipeline in your shared vault.
|
|
262
|
+
EOF
|
|
263
|
+
exit 0
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
if [ "$mode" = "install" ]; then
|
|
267
|
+
echo "→ installing pipeline core into $dest"
|
|
268
|
+
copy_fixed_agents
|
|
269
|
+
copy_core
|
|
270
|
+
seed_config
|
|
271
|
+
mkdir -p "$target/specs"
|
|
272
|
+
[ -f "$target/specs/_template.md" ] || cp "$src/core/templates/spec.template.md" "$target/specs/_template.md"
|
|
273
|
+
cat <<EOF
|
|
274
|
+
|
|
275
|
+
✓ pipeline core installed into $dest (version $ver)
|
|
276
|
+
|
|
277
|
+
Next:
|
|
278
|
+
1. Open the project in Claude Code.
|
|
279
|
+
2. Run /init-pipeline — it detects your stack, asks the gaps, and generates
|
|
280
|
+
PIPELINE.md + renders one implementer agent per surface.
|
|
281
|
+
3. Commit PIPELINE.md, then /brainstorm to start a feature.
|
|
282
|
+
|
|
283
|
+
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
284
|
+
uv tool install -p 3.13 serena-agent # once per machine
|
|
285
|
+
Make sure ~/.local/bin is on PATH (uv tool update-shell) — otherwise the
|
|
286
|
+
registered MCP server silently fails to start.
|
|
287
|
+
|
|
288
|
+
Prefer one shared core across all your repos? Re-run with --global.
|
|
289
|
+
EOF
|
|
290
|
+
else
|
|
291
|
+
echo "→ updating pipeline core in $dest (keeping your PIPELINE.md + rendered agents)"
|
|
292
|
+
copy_core
|
|
293
|
+
copy_fixed_agents 2>/dev/null || true
|
|
294
|
+
seed_config
|
|
295
|
+
bump_pointer_version "$dest/pipeline.json" "$ver"
|
|
296
|
+
cat <<EOF
|
|
297
|
+
|
|
298
|
+
✓ core refreshed to $ver. Your PIPELINE.md, rendered surface agents, gate-config.json and
|
|
299
|
+
settings.json were left as-is. Re-run /init-pipeline if your stack changed.
|
|
300
|
+
EOF
|
|
301
|
+
fi
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cohorte",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Portable, stack-agnostic multi-agent development pipeline for Claude Code — install the core, run /init-pipeline, and it adapts to your project's stack.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"cohorte": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build:dashboard": "npm --prefix dashboard/app ci && npm --prefix dashboard/app run build"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin",
|
|
13
|
+
"core",
|
|
14
|
+
"profile",
|
|
15
|
+
"scripts",
|
|
16
|
+
"dashboard/server",
|
|
17
|
+
"dashboard/dist",
|
|
18
|
+
"dashboard/README.md",
|
|
19
|
+
"install.sh",
|
|
20
|
+
"install.ps1",
|
|
21
|
+
"CHANGELOG.md"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/TheBidouilleAgency/cohorte.git"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/TheBidouilleAgency/cohorte#readme",
|
|
31
|
+
"author": "Enzo Viry",
|
|
32
|
+
"license": "AGPL-3.0-only",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"claude",
|
|
35
|
+
"claude-code",
|
|
36
|
+
"agents",
|
|
37
|
+
"pipeline",
|
|
38
|
+
"multi-agent"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# PIPELINE.md — <PROJECT_NAME> profile
|
|
2
|
+
|
|
3
|
+
> **Generated by `/init-pipeline`.** This is the project profile: the single place the
|
|
4
|
+
> portable multi-agent pipeline reads for everything stack-specific. The pipeline core
|
|
5
|
+
> under `.claude/` is generic and references THIS file by section — keep project facts
|
|
6
|
+
> here, never hardcoded into agent prompts. Kept current by `/update-pipeline` (reconcile:
|
|
7
|
+
> new fields are topped up, your values never overwritten). Rendered agent files are
|
|
8
|
+
> regenerated from this profile on every reconcile — customize agents through §Conventions
|
|
9
|
+
> here, never by editing the agent files. Free-form notes belong in `CLAUDE.md`.
|
|
10
|
+
>
|
|
11
|
+
> **Machine block first, prose after.** The fenced `yaml pipeline-profile` block below is
|
|
12
|
+
> the deterministic contract (flags, surfaces, commands) — commands parse it and branch on
|
|
13
|
+
> it. The prose sections carry conventions agents read.
|
|
14
|
+
|
|
15
|
+
```yaml pipeline-profile
|
|
16
|
+
# ── identity ────────────────────────────────────────────────────────────────
|
|
17
|
+
name: <PROJECT_NAME>
|
|
18
|
+
one_liner: <one sentence: what this product is>
|
|
19
|
+
ui_language: <English | French | …> # language of ALL user-facing copy
|
|
20
|
+
package_manager: <pnpm | npm | yarn | bun | pip | cargo | go>
|
|
21
|
+
|
|
22
|
+
# ── vcs ─────────────────────────────────────────────────────────────────────
|
|
23
|
+
vcs:
|
|
24
|
+
host: <github | gitlab | none>
|
|
25
|
+
remote: <owner/repo> # e.g. acme/webapp
|
|
26
|
+
default_branch: <main>
|
|
27
|
+
feature_branch_prefix: feature/ # branch = <prefix><feature_id>
|
|
28
|
+
|
|
29
|
+
# ── repo shape ──────────────────────────────────────────────────────────────
|
|
30
|
+
repo:
|
|
31
|
+
layout: <monorepo | single>
|
|
32
|
+
workspace_tool: <turborepo | nx | none>
|
|
33
|
+
|
|
34
|
+
# ── code retrieval (semantic navigation — cuts agent read time) ─────────────
|
|
35
|
+
# Agents prefer symbol/graph MCP queries over grep-and-read when a provider is
|
|
36
|
+
# wired. serena = live LSP symbol navigation (default, no index to maintain);
|
|
37
|
+
# graphify = persistent tree-sitter knowledge graph over code + docs (needs an
|
|
38
|
+
# index step + rescans); none = agents fall back to Grep/Glob/Read.
|
|
39
|
+
# Registered by /init-pipeline as a project-scope MCP server (committed .mcp.json).
|
|
40
|
+
retrieval:
|
|
41
|
+
provider: serena # serena | graphify | none
|
|
42
|
+
|
|
43
|
+
# ── surfaces ────────────────────────────────────────────────────────────────
|
|
44
|
+
# One entry per independently-implemented code area. /build dispatches ONE
|
|
45
|
+
# implementer agent per surface, in parallel. Each surface is rendered by
|
|
46
|
+
# /init-pipeline into its own agent file (agent field) with the tools listed.
|
|
47
|
+
# This list GROWS automatically: /build §1.5 adds a surface (and renders its
|
|
48
|
+
# agent) when a spec touches a tree no surface owns, or splits a bottleneck
|
|
49
|
+
# surface into specialized sub-surfaces. Keep one owner per tree; shared code
|
|
50
|
+
# (routing/state/DS) is its own single-owner surface. See SCHEMA.md §Specialization.
|
|
51
|
+
surfaces:
|
|
52
|
+
- key: backend # short id, used as agent name + scope
|
|
53
|
+
path: apps/api # the ONLY tree this surface's agent may touch
|
|
54
|
+
label: backend (AdonisJS)
|
|
55
|
+
agent: backend # rendered agent file: .claude/agents/backend.md
|
|
56
|
+
tools: [Read, Write, Edit, Bash, Grep, Glob, mcp__serena] # mcp__<provider> mirrors retrieval.provider
|
|
57
|
+
model: sonnet # frontmatter model tier: sonnet | haiku | inherit
|
|
58
|
+
# sonnet = default (applies the frozen contract — cheap
|
|
59
|
+
# vs the Opus lead); haiku = purely mechanical scaffolding;
|
|
60
|
+
# inherit = only for surfaces with real design decisions
|
|
61
|
+
test_cmd: pnpm --filter api test
|
|
62
|
+
lint_cmd: pnpm --filter api lint
|
|
63
|
+
format_cmd: pnpm --filter api format
|
|
64
|
+
typecheck_cmd: pnpm --filter api exec tsc --noEmit
|
|
65
|
+
build_cmd: ""
|
|
66
|
+
uses_design: false
|
|
67
|
+
- key: frontend
|
|
68
|
+
path: apps/web
|
|
69
|
+
label: frontend (React/TanStack)
|
|
70
|
+
agent: frontend
|
|
71
|
+
tools: [Read, Write, Edit, Bash, Grep, Glob, DesignSync, mcp__serena]
|
|
72
|
+
model: inherit # this surface makes real design decisions ⇒ worth the lead's model
|
|
73
|
+
test_cmd: pnpm --filter web test
|
|
74
|
+
lint_cmd: pnpm --filter web lint
|
|
75
|
+
format_cmd: pnpm --filter web format
|
|
76
|
+
typecheck_cmd: pnpm check-types
|
|
77
|
+
build_cmd: pnpm --filter web build
|
|
78
|
+
uses_design: true
|
|
79
|
+
|
|
80
|
+
# ── contract (the only cross-surface sync channel) ──────────────────────────
|
|
81
|
+
contract:
|
|
82
|
+
enabled: <true | false> # false ⇒ no shared contract; skip §2 of /build
|
|
83
|
+
mechanism: <shared-types-zod | openapi | protobuf | json-schema | none>
|
|
84
|
+
path: packages/shared-types/src # where <feature_id>.<ext> is authored
|
|
85
|
+
ext: ts
|
|
86
|
+
index: packages/shared-types/src/index.ts # barrel to export from, or "" if none
|
|
87
|
+
authored_by: lead # NEVER the implementer agents
|
|
88
|
+
|
|
89
|
+
# ── repo-wide commands (root unless noted) ──────────────────────────────────
|
|
90
|
+
commands:
|
|
91
|
+
install: pnpm install
|
|
92
|
+
dev: pnpm dev
|
|
93
|
+
lint: pnpm lint
|
|
94
|
+
format: pnpm format
|
|
95
|
+
typecheck: pnpm check-types
|
|
96
|
+
test: pnpm test
|
|
97
|
+
# migration commands — omit / leave "" if the project has no DB migrations
|
|
98
|
+
migrate: "cd apps/api && node ace migration:run"
|
|
99
|
+
make_migration: "cd apps/api && node ace make:migration"
|
|
100
|
+
|
|
101
|
+
# ── rbac (optional) ─────────────────────────────────────────────────────────
|
|
102
|
+
rbac:
|
|
103
|
+
enabled: <true | false>
|
|
104
|
+
hierarchy: [super-admin, admin, editor, member] # highest → lowest, or []
|
|
105
|
+
note: "the platform must serve EVERY role, not just admins"
|
|
106
|
+
|
|
107
|
+
# ── design system (optional) ────────────────────────────────────────────────
|
|
108
|
+
design:
|
|
109
|
+
enabled: <true | false> # false ⇒ /align-ds + design gates are no-ops
|
|
110
|
+
provider: <claude-design | figma | none>
|
|
111
|
+
design_system_project: <uuid-or-id> # the UI-kit source of truth
|
|
112
|
+
design_project: none # legacy fallback for bare-filename design_files only; keep `none` — new specs use full links that carry their own project, so nothing here goes stale on a DS rebuild
|
|
113
|
+
snapshot_dir: apps/web/design-reference # committed DS snapshot for /align-ds diff
|
|
114
|
+
direction: design-to-code # NEVER push code→design for a curated DS
|
|
115
|
+
ui_kit_path: apps/web/src/components/ui
|
|
116
|
+
tokens_path: apps/web/src/index.css
|
|
117
|
+
|
|
118
|
+
# ── isolation / parallelism (optional) ──────────────────────────────────────
|
|
119
|
+
isolation:
|
|
120
|
+
enabled: <true | false> # false ⇒ features run in the main checkout
|
|
121
|
+
unit: git-worktree
|
|
122
|
+
db_per_worktree: <true | false>
|
|
123
|
+
db_name_pattern: "<name>_<id>" # e.g. myapp_<id>
|
|
124
|
+
port_base: { api: 3333, web: 5173 } # each worktree gets base+slot
|
|
125
|
+
compose_file: docker-compose.yml
|
|
126
|
+
registry: .worktrees/slots.tsv
|
|
127
|
+
|
|
128
|
+
# ── gate (drives .claude/hooks/gate.py + settings.json) ─────────────────────
|
|
129
|
+
# Confirm-first or hard-deny on dangerous Bash, inspecting the FULL command
|
|
130
|
+
# string (so chained `cd x && …` forms are caught).
|
|
131
|
+
gate:
|
|
132
|
+
# Three tiers. `deny` = always hard-blocked. `ask` = always confirm (branch-independent risk).
|
|
133
|
+
# `ask_on_default_branch` = confirm ONLY when the checked-out branch is `default_branch`; on
|
|
134
|
+
# feature branches these run freely. gate.py resolves the branch at run time (git rev-parse);
|
|
135
|
+
# unknown branch (no repo / detached) ⇒ gated, to stay safe. Keep git + docker here so agents
|
|
136
|
+
# move fast on feature branches but main stays protected.
|
|
137
|
+
default_branch: main # the protected branch (mirror vcs.default_branch)
|
|
138
|
+
deny: # never allowed, on any branch
|
|
139
|
+
- "node ace migration:fresh"
|
|
140
|
+
- "node ace migration:reset"
|
|
141
|
+
- "node ace migration:rollback"
|
|
142
|
+
- "node ace db:wipe"
|
|
143
|
+
ask: # always confirm, on any branch
|
|
144
|
+
- "node ace migration:run"
|
|
145
|
+
- "node ace db:"
|
|
146
|
+
- "psql"
|
|
147
|
+
ask_on_default_branch: # free on feature branches, confirm on default_branch
|
|
148
|
+
- "git commit"
|
|
149
|
+
- "git push"
|
|
150
|
+
- "git merge"
|
|
151
|
+
- "git rebase"
|
|
152
|
+
- "git reset"
|
|
153
|
+
- "docker compose"
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
> **Note.** The **kanban** board link is **user-scoped** — NOT configured here. Its facts live in the
|
|
158
|
+
> consolidated `~/.claude/cohorte.config.yaml`, read at runtime (the kanban board is keyed by this
|
|
159
|
+
> profile's `name`). This project profile only governs the dev pipeline (`/brainstorm…/ship`).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Conventions
|
|
164
|
+
|
|
165
|
+
> Read by the implementer + review agents. Keep these terse and rule-shaped; the machine
|
|
166
|
+
> block above holds the paths/commands they enforce against.
|
|
167
|
+
|
|
168
|
+
### Shared
|
|
169
|
+
|
|
170
|
+
- User-facing copy (API messages, UI text) in **<ui_language>**.
|
|
171
|
+
- <e.g. Zod v4 syntax `z.email()`/`z.uuid()`; ESM `.js` import extensions — project-specific>
|
|
172
|
+
|
|
173
|
+
### Surface: `backend` (`apps/api`)
|
|
174
|
+
|
|
175
|
+
- <one-action controllers · validator on every write · standardized response envelope · base model / UUID PK · `#`-alias imports · additive-only migrations · …>
|
|
176
|
+
|
|
177
|
+
### Surface: `frontend` (`apps/web`)
|
|
178
|
+
|
|
179
|
+
- <file-based routes with loaders/guards · domain `lib/api` modules over the shared client · design-system primitives, `cn()`+CVA · **mobile-first, fully responsive** · consume contract types, never redefine · …>
|
|
180
|
+
|
|
181
|
+
### Testing — strict TDD (red → green → refactor)
|
|
182
|
+
|
|
183
|
+
- <backend test runner + what a contract test must cover (status, validation, auth, payload) · DB isolation per test>
|
|
184
|
+
- <frontend test runner + what to cover (hooks, api modules, component behavior); note layout is not unit-testable>
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Design brief note (feeds `/spec` §8 and Claude Design)
|
|
189
|
+
|
|
190
|
+
- <design system name + primitives to use · mobile-first · copy language · brand/theming constraints>
|
|
191
|
+
- A feature lists its design pages in the spec front-matter `design_files` as **full links** of the form
|
|
192
|
+
`https://claude.ai/design/p/<projectId>?file=<file>` — each carries its own project (`/p/<projectId>`)
|
|
193
|
+
and page (`?file=`), so an agent extracts both and reads it via `DesignSync get_file(<projectId>,
|
|
194
|
+
<file>)`. Paste the link at `/build`'s design gate. No stored project id ⇒ a design-system rebuild
|
|
195
|
+
(new project) just means pasting the new links. (Bare file names are legacy, resolved in `design_project`.)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Personas for `/brainstorm` (optional — the panel)
|
|
200
|
+
|
|
201
|
+
<Panel members with a job AND a personality who challenge the idea from their angle and
|
|
202
|
+
disagree with each other. Include a role-coverage guard if `rbac.enabled`. Example:>
|
|
203
|
+
|
|
204
|
+
- **PM** (pragmatic, scope-cutting) — real value? what do we drop?
|
|
205
|
+
- **Skeptical senior engineer** (blunt) — feasibility, edge cases, tech debt.
|
|
206
|
+
- **UX/product designer** — mobile-first flows, accessibility, empty/error states.
|
|
207
|
+
- **Security & RBAC** (paranoid) — permission leaks, cross-tenant exposure, least privilege.
|
|
208
|
+
- <one persona per RBAC role so the feature serves every role, not just admins>
|