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.
Files changed (57) hide show
  1. package/CHANGELOG.md +264 -0
  2. package/LICENSE +661 -0
  3. package/README.md +269 -0
  4. package/bin/cli.js +339 -0
  5. package/core/agents/implementer.template.md +74 -0
  6. package/core/agents/release.md +51 -0
  7. package/core/agents/review.md +85 -0
  8. package/core/commands/align-ds.md +32 -0
  9. package/core/commands/audit.md +31 -0
  10. package/core/commands/brainstorm.md +48 -0
  11. package/core/commands/build.md +91 -0
  12. package/core/commands/doctor.md +50 -0
  13. package/core/commands/fix.md +62 -0
  14. package/core/commands/init-pipeline.md +32 -0
  15. package/core/commands/refactor.md +38 -0
  16. package/core/commands/review.md +68 -0
  17. package/core/commands/ship.md +68 -0
  18. package/core/commands/smoke.md +55 -0
  19. package/core/commands/spec.md +67 -0
  20. package/core/commands/update-pipeline.md +96 -0
  21. package/core/hooks/__pycache__/gate.cpython-312.pyc +0 -0
  22. package/core/hooks/gate.py +129 -0
  23. package/core/templates/agent-handoff.md +34 -0
  24. package/core/templates/brainstorm-return.md +36 -0
  25. package/core/templates/design-brief.md +35 -0
  26. package/core/templates/pr-body.md +29 -0
  27. package/core/templates/review-feedback.md +36 -0
  28. package/core/templates/spec.template.md +84 -0
  29. package/core/templates/steps/init-pipeline/01-detect-stack.md +40 -0
  30. package/core/templates/steps/init-pipeline/02-interview-gaps.md +41 -0
  31. package/core/templates/steps/init-pipeline/03-draft-profile.md +10 -0
  32. package/core/templates/steps/init-pipeline/04-write-render.md +88 -0
  33. package/core/templates/steps/init-pipeline/05-report.md +12 -0
  34. package/dashboard/README.md +54 -0
  35. package/dashboard/dist/apple-touch-icon-180.png +0 -0
  36. package/dashboard/dist/assets/index-CoBuEdy-.js +42 -0
  37. package/dashboard/dist/assets/index-DN5OGW9g.css +1 -0
  38. package/dashboard/dist/favicon-16.png +0 -0
  39. package/dashboard/dist/favicon-32.png +0 -0
  40. package/dashboard/dist/favicon-48.png +0 -0
  41. package/dashboard/dist/icon-192.png +0 -0
  42. package/dashboard/dist/icon-512.png +0 -0
  43. package/dashboard/dist/index.html +16 -0
  44. package/dashboard/server/doctor.js +266 -0
  45. package/dashboard/server/fleet.js +119 -0
  46. package/dashboard/server/index.js +306 -0
  47. package/dashboard/server/kanban.js +158 -0
  48. package/dashboard/server/versions.js +111 -0
  49. package/dashboard/server/yaml.js +126 -0
  50. package/install.ps1 +359 -0
  51. package/install.sh +301 -0
  52. package/package.json +40 -0
  53. package/profile/PIPELINE.template.md +208 -0
  54. package/profile/SCHEMA.md +303 -0
  55. package/profile/cohorte.config.template.yaml +43 -0
  56. package/scripts/new-feature.sh.template +89 -0
  57. 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>