agentic-team 6.1.0 → 6.3.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 +8 -3
- package/bin/build-template.js +2 -2
- package/bin/index.js +234 -39
- package/bin/platforms.js +510 -0
- package/package.json +4 -4
- package/template/.claude-plugin/plugin.json +2 -2
- package/template/.orchestra/README.md +41 -51
- package/template/.orchestra/config.yml +16 -0
- package/template/.orchestra/roles/product-manager.md +3 -2
- package/template/.orchestra/scripts/compact-diff.awk +1 -1
- package/template/.orchestra/scripts/context.mjs +373 -0
- package/template/.orchestra/stacks/_repo/setup.sh +7 -3
- package/template/.orchestra/stacks/mobile-expo/setup.sh +1 -1
- package/template/CLAUDE.md +1 -1
- package/template/agents/lead.md +171 -116
- package/template/agents/milestone-reviewer.md +5 -3
- package/template/agents/product-manager.md +3 -2
- package/template/agents/re-reviewer.md +25 -0
- package/template/agents/reviewer.md +7 -5
- package/template/agents/scaffolder.md +26 -0
- package/template/commands/help.md +1 -0
- package/template/commands/hotfix.md +3 -1
- package/template/commands/rewind.md +10 -8
- package/template/commands/setup.md +2 -1
- package/template/commands/start.md +2 -2
- package/template/commands/status.md +1 -1
- package/template/commands/sync.md +5 -2
- package/template/commands/verifier.md +2 -2
- package/template/hooks/audit-context.sh +15 -2
- package/template/hooks/enforce-role.sh +21 -3
- package/template/hooks/protect-system-files.sh +2 -2
- package/template/hooks/review-rounds.sh +1 -1
- package/template/rules/code-standards.orchestra.md +3 -2
- package/template/rules/design-parity.orchestra.md +12 -1
- package/template/rules/observability.orchestra.md +3 -0
- package/template/rules/performance.orchestra.md +5 -1
- package/template/rules/phase-limits.orchestra.md +1 -1
- package/template/rules/pull-request.orchestra.md +7 -2
- package/template/rules/role-boundaries.orchestra.md +24 -9
- package/template/rules/security.orchestra.md +1 -1
- package/template/rules/stuck-detection.orchestra.md +1 -1
- package/template/rules/testing-standards.orchestra.md +10 -5
- package/template/rules/tracker-authority.orchestra.md +9 -1
- package/template/skills/push-notifications/SKILL.md +1 -1
- package/template/skills/testing/SKILL.md +2 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: "Independent code reviewer. Reviews a task's pull request — findings inline on the lines they are about, the verdict as a label. No memory of writing the code. Called by lead once the PR exists."
|
|
4
4
|
model: opus
|
|
5
|
-
effort:
|
|
5
|
+
effort: high
|
|
6
6
|
disallowedTools: [Write, Edit, NotebookEdit]
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -127,8 +127,10 @@ and neither is "looks fine" — the app has a token module precisely so this is
|
|
|
127
127
|
a number rather than an opinion.
|
|
128
128
|
|
|
129
129
|
If the design and the token module genuinely disagree — a value the tokens
|
|
130
|
-
cannot express — that is a blocker to report, not a difference to split.
|
|
131
|
-
|
|
130
|
+
cannot express — that is a blocker to report, not a difference to split. When
|
|
131
|
+
the pull request has a design source, read
|
|
132
|
+
`.claude/rules/design-parity.orchestra.md` before you start; it is not loaded
|
|
133
|
+
for you.
|
|
132
134
|
|
|
133
135
|
**And look for what no number catches:**
|
|
134
136
|
|
|
@@ -266,8 +268,8 @@ determine a base, say so and review the full working tree instead.
|
|
|
266
268
|
Severity is the impact on the product, not how interesting the finding is.
|
|
267
269
|
Blocking and Important are fixed in this pull request. A Suggestion does not
|
|
268
270
|
hold it: it is an inline comment tagged `[suggestion]` like any other finding,
|
|
269
|
-
and lead records each one — a `tech_debt` task with a provider,
|
|
270
|
-
`context.
|
|
271
|
+
and lead records each one — a `tech_debt` task with a provider,
|
|
272
|
+
`context.mjs decide <m> tech_debt` with `tracker.provider: none`. One run left the
|
|
271
273
|
scale undefined, and a reviewer probing a measuring tool's maths found a new
|
|
272
274
|
"medium" corner every round, nine rounds running.
|
|
273
275
|
|
|
@@ -71,6 +71,23 @@ convention is worse than an absent one, because it looks decided.
|
|
|
71
71
|
|---|---|
|
|
72
72
|
| Task tracker | none · GitHub Projects · ClickUp |
|
|
73
73
|
| Shared UI kit? | yes · no |
|
|
74
|
+
| Base branch — where tasks branch off and squash into | `main` · another (name it) |
|
|
75
|
+
|
|
76
|
+
Write the answer to `delivery.base_branch` in `.orchestra/config.yml`. Do not
|
|
77
|
+
read it from the repository's default branch: that is often the release
|
|
78
|
+
branch, not the one work lands on.
|
|
79
|
+
|
|
80
|
+
Write the platforms from Round 1 and 2 to `project.platforms`: Web → `web`,
|
|
81
|
+
Expo → `expo`, Native mobile → `ios, android`, Backend → `backend`. Desktop
|
|
82
|
+
and Game have no pack and add nothing. Step 5 narrows the install to this
|
|
83
|
+
list.
|
|
84
|
+
|
|
85
|
+
Add to the list, never replace it. With `--force` on a project that already
|
|
86
|
+
has apps, its platforms stay listed — Step 5 would otherwise retire the
|
|
87
|
+
existing app's skills and rule sections. If the stack you need is not under
|
|
88
|
+
`.orchestra/stacks/`, the install was narrowed before this app was asked
|
|
89
|
+
for: write the list now and run `npx -y agentic-team@<version>` (the version
|
|
90
|
+
in `.orchestra/.installed.json`) to bring the stack back, then scaffold.
|
|
74
91
|
|
|
75
92
|
If the user wants a shared UI kit **and** picked `standalone`, stop and
|
|
76
93
|
resolve the conflict now: standalone apps cannot import a workspace package.
|
|
@@ -168,6 +185,15 @@ command. Report that to the user; do not try to install it yourself.
|
|
|
168
185
|
Fix failures before reporting. If a fix fails 3 times, stop and report —
|
|
169
186
|
follow `.claude/rules/stuck-detection.orchestra.md`.
|
|
170
187
|
|
|
188
|
+
Then narrow the install to the platforms you wrote: run
|
|
189
|
+
`npx -y agentic-team@<version>`, where `<version>` is the `version` in
|
|
190
|
+
`.orchestra/.installed.json`. Same version, so nothing changes except what is
|
|
191
|
+
installed: the other platforms' stacks, skills and rule sections are retired.
|
|
192
|
+
Run it only now — Step 4 still needed the stacks. If that version cannot be
|
|
193
|
+
fetched — staged on npm and not yet approved, or installed from a checkout —
|
|
194
|
+
say so in the report and give the user the command; never substitute
|
|
195
|
+
`@latest`, which could install a different version over this one.
|
|
196
|
+
|
|
171
197
|
Commit once: `chore(setup): scaffold {platforms}`.
|
|
172
198
|
|
|
173
199
|
## Step 6 — Report
|
|
@@ -30,6 +30,7 @@ AGENTS:
|
|
|
30
30
|
scaffolder Interactive project setup (/orchestra:setup)
|
|
31
31
|
lead Team assembler + milestone executor (/orchestra:start)
|
|
32
32
|
reviewer Independent code review (called by lead)
|
|
33
|
+
re-reviewer Review rounds 2+ at lower effort (called by lead)
|
|
33
34
|
tracker Milestone export to an external tracker (/orchestra:export)
|
|
34
35
|
|
|
35
36
|
PIPELINE (set by PM via milestone Complexity field):
|
|
@@ -4,7 +4,9 @@ Usage: `/orchestra:hotfix {description}`
|
|
|
4
4
|
|
|
5
5
|
The lead will:
|
|
6
6
|
1. Auto-create a hotfix milestone + single phase
|
|
7
|
-
2. Implement the fix (minimal, focused change)
|
|
7
|
+
2. Implement the fix (minimal, focused change) — through an engineer whose
|
|
8
|
+
prompt starts with a line `Hotfix: {description}`, the one engineer the role
|
|
9
|
+
hook lets lead start from its own session
|
|
8
10
|
3. Run verification gate (test + lint MUST pass)
|
|
9
11
|
4. Commit with `fix({scope}): {description}`
|
|
10
12
|
5. Push immediately — no RFC, no review, no approval gates
|
|
@@ -9,13 +9,16 @@ Review milestone execution history for actionable insights. PM role only.
|
|
|
9
9
|
- No arguments: all milestones with `status: done`
|
|
10
10
|
- With numbers: only milestones matching those numbers (e.g., `1` matches `M1-*`)
|
|
11
11
|
3. For each milestone, read execution artifacts:
|
|
12
|
-
- `context.md` —
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
- `context.md` — `## Phases`: status, commits, errors per phase
|
|
13
|
+
- `decisions.md` — choices made during implementation; a line naming a
|
|
14
|
+
decision as `closed` says how it ended
|
|
15
|
+
- `journal.md` — append-only: what happened, and which alternatives were
|
|
16
|
+
rejected and why
|
|
17
|
+
- `node .orchestra/scripts/context.mjs metrics <m>` — review rounds and the
|
|
18
|
+
last commit per phase, computed now. Durations and retries are not
|
|
19
|
+
stored; say so rather than estimating them
|
|
17
20
|
- `grooming.md` — original scope vs what actually happened
|
|
18
|
-
- Review verdict and comments (from
|
|
21
|
+
- Review verdict and comments (from the pull requests or git log)
|
|
19
22
|
4. Extract and present — focus on **what the user needs to know**, not execution mechanics:
|
|
20
23
|
|
|
21
24
|
```
|
|
@@ -29,8 +32,7 @@ Review milestone execution history for actionable insights. PM role only.
|
|
|
29
32
|
|
|
30
33
|
### Performance
|
|
31
34
|
- Total phases: 5 | Completed: 5 | Failed: 0
|
|
32
|
-
-
|
|
33
|
-
- Verification retries: 3 total (phase-2: 2, phase-4: 1)
|
|
35
|
+
- Review rounds: phase-2: 3, phase-4: 1 (from `context.mjs metrics`)
|
|
34
36
|
- Stuck: No
|
|
35
37
|
|
|
36
38
|
### Review Findings
|
|
@@ -8,7 +8,8 @@ The scaffolder will:
|
|
|
8
8
|
3. Scaffold each app with its official create tool
|
|
9
9
|
4. Install the shared baseline (TypeScript, Biome, Vitest, CI, Node pin)
|
|
10
10
|
5. Write per-app `CLAUDE.md` and `.claude/` from `.orchestra/stacks/`
|
|
11
|
-
6. Run the verification gate
|
|
11
|
+
6. Run the verification gate, narrow the install to the chosen platforms,
|
|
12
|
+
and report what was created
|
|
12
13
|
|
|
13
14
|
Refuses to run if the working tree already contains a scaffolded app,
|
|
14
15
|
unless you pass `--force`.
|
|
@@ -19,8 +19,8 @@ sub-agents are unaffected either way; their effort comes from the phase.
|
|
|
19
19
|
The lead will:
|
|
20
20
|
1. Scan milestones for pending work
|
|
21
21
|
2. Assemble the right team for each phase (identity derived from phase content)
|
|
22
|
-
3.
|
|
23
|
-
4.
|
|
22
|
+
3. Run each milestone in a milestone agent, which delegates phases to sub-agents
|
|
23
|
+
4. Have each task's pull request reviewed there, by the reviewer agent
|
|
24
24
|
5. Push automatically after review passes
|
|
25
25
|
6. After milestone: `--auto` continues to next automatically, normal mode asks user
|
|
26
26
|
|
|
@@ -7,5 +7,5 @@ Show full milestone status report. PM role only.
|
|
|
7
7
|
- All milestones with status, current phase, next action
|
|
8
8
|
- Phase details for active milestone (status, effort, metrics)
|
|
9
9
|
- Git status (branch, unpushed commits)
|
|
10
|
-
- Metrics
|
|
10
|
+
- Metrics from `node .orchestra/scripts/context.mjs metrics <m>` — review rounds and last commit per phase, computed now; nothing else is stored
|
|
11
11
|
- Actions needed (specific next steps)
|
|
@@ -40,8 +40,11 @@ other's and stops. See `.claude/rules/tracker-authority.orchestra.md`.
|
|
|
40
40
|
6. **Plan change, as the PM:** revise the phase file, run
|
|
41
41
|
`/orchestra:export {id}` so the board carries the new text, reply under
|
|
42
42
|
the comment saying what changed. **As lead:** surface it and stop.
|
|
43
|
-
7. **Anything else, as lead:**
|
|
44
|
-
|
|
43
|
+
7. **Anything else, as lead:** launch a single-phase agent
|
|
44
|
+
(`.claude/agents/lead.md`, Single-Phase Agent) — fix mode for the task's open
|
|
45
|
+
PR, build mode for new work — with the comment quoted. It builds, runs the
|
|
46
|
+
full verification gate and opens or updates the pull request; lead itself
|
|
47
|
+
starts no engineer. Reply under the triggering comment with the pull request
|
|
45
48
|
link. Move the task to `in_review`. **As the PM:** surface it and stop.
|
|
46
49
|
|
|
47
50
|
## What it refuses
|
|
@@ -15,8 +15,8 @@ Verify that implemented milestones match their requirements. PM role only.
|
|
|
15
15
|
- `grooming.md` — scope decisions and phase breakdown
|
|
16
16
|
- All `phases/*.md` — phase acceptance criteria
|
|
17
17
|
4. For each milestone, read execution context:
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
18
|
+
- `decisions.md` — why specific approaches were chosen, and which were later closed
|
|
19
|
+
- `journal.md` — rejected alternatives, useful when a requirement shows as "deviated"
|
|
20
20
|
- `context.md` — `## Phases` section (which phases completed, which failed)
|
|
21
21
|
5. For each milestone, read the actual implementation:
|
|
22
22
|
- Run `git log --oneline` filtered to commits from that milestone's phases
|
|
@@ -79,7 +79,7 @@ printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}" node -e
|
|
|
79
79
|
const section = /(?:^|\r?\n)## Phases\r?\n([\s\S]*?)(?=\r?\n## |$)/.exec(text);
|
|
80
80
|
const body = section ? section[1] : "";
|
|
81
81
|
for (const line of body.split(/\r?\n/)) {
|
|
82
|
-
const m = /^-\s*(\S+):\s*(done|in-progress|failed|pending)\b/i.exec(line.trim());
|
|
82
|
+
const m = /^-\s*(\S+):\s*(done|in-progress|failed|pending|blocked)\b/i.exec(line.trim());
|
|
83
83
|
if (!m) continue;
|
|
84
84
|
const [, phase, statusRaw] = m;
|
|
85
85
|
const status = statusRaw.toLowerCase();
|
|
@@ -90,6 +90,19 @@ printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}" node -e
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
// decisions.md: one source for what a valid line is — the script that
|
|
94
|
+
// writes it — rather than a second parser here that drifts from it.
|
|
95
|
+
const script = path.join(root, ".orchestra", "scripts", "context.mjs");
|
|
96
|
+
if (fs.existsSync(script)) {
|
|
97
|
+
try {
|
|
98
|
+
require("node:child_process").execFileSync(process.execPath, [script, "check"], {
|
|
99
|
+
cwd: root,
|
|
100
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
101
|
+
});
|
|
102
|
+
} catch (e) {
|
|
103
|
+
for (const f of String(e.stdout || "").split("\n").filter(Boolean)) findings.push(f);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
93
106
|
return { findings, open };
|
|
94
107
|
}
|
|
95
108
|
|
|
@@ -132,7 +145,7 @@ printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}" node -e
|
|
|
132
145
|
|
|
133
146
|
const lines = [];
|
|
134
147
|
if (result.findings && result.findings.length) {
|
|
135
|
-
lines.push("Context audit after compaction —
|
|
148
|
+
lines.push("Context audit after compaction — the milestone record has unresolved defects:");
|
|
136
149
|
for (const f of result.findings) lines.push(` - ${f}`);
|
|
137
150
|
}
|
|
138
151
|
if (result.open && result.open.length) {
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# judged against the recorded role. Two terminals are two sessions, so the
|
|
15
15
|
# PM's marker never applies to lead.
|
|
16
16
|
#
|
|
17
|
+
# Lead is held to one rule: phase work starts inside a milestone agent.
|
|
18
|
+
#
|
|
17
19
|
# No marker means no role — discussion mode — and nothing is blocked.
|
|
18
20
|
#
|
|
19
21
|
# Reads the tool call on stdin. Exit 0 allows, exit 2 blocks.
|
|
@@ -89,10 +91,26 @@ verdict="$(printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD
|
|
|
89
91
|
} catch {
|
|
90
92
|
return;
|
|
91
93
|
}
|
|
94
|
+
// ── Lead ─────────────────────────────────────────────────────────────
|
|
95
|
+
// Phase work runs inside a milestone agent, so each milestone'"'"'s context is
|
|
96
|
+
// dropped when it ends. One run kept two milestones in the lead session
|
|
97
|
+
// instead: 738 calls, context up to 925k tokens. A call from a sub-agent
|
|
98
|
+
// carries agent_id; one from the lead session itself does not.
|
|
99
|
+
if (role === "lead") {
|
|
100
|
+
if (tool !== "Agent" || call.agent_id) return;
|
|
101
|
+
const type = input.subagent_type || "";
|
|
102
|
+
if (!/^(engineer-\w+|reviewer|re-reviewer)$/.test(type)) return;
|
|
103
|
+
if (/^engineer-/.test(type) && /^\s*Hotfix:/.test(String(input.prompt || ""))) return;
|
|
104
|
+
process.stdout.write(
|
|
105
|
+
`Lead runs phase work inside a milestone agent, not in its own session — launch a general-purpose agent with the Milestone Agent or Single-Phase Agent prompt in .claude/agents/lead.md, and let it start ${type}. A hotfix engineer'"'"'s prompt starts with a line "Hotfix: <description>".\n`,
|
|
106
|
+
);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
92
110
|
if (role !== "product-manager") return;
|
|
93
111
|
|
|
94
112
|
// ── The PM ───────────────────────────────────────────────────────────
|
|
95
|
-
// Writes milestones. Commits them to
|
|
113
|
+
// Writes milestones. Commits them to delivery.base_branch and pushes. Nothing else.
|
|
96
114
|
const deny = (why) => {
|
|
97
115
|
process.stdout.write(`Outside the PM'"'"'s scope: ${why}\n`);
|
|
98
116
|
};
|
|
@@ -140,10 +158,10 @@ verdict="$(printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD
|
|
|
140
158
|
const cmd = input.command || "";
|
|
141
159
|
|
|
142
160
|
if (/\bgh\s+pr\s+(create|merge|edit|close|ready|checkout)\b/.test(cmd)) {
|
|
143
|
-
return deny("the PM never opens, edits or merges a pull request. Milestone files go to
|
|
161
|
+
return deny("the PM never opens, edits or merges a pull request. Milestone files go to delivery.base_branch directly; code is lead'"'"'s.");
|
|
144
162
|
}
|
|
145
163
|
if (/\bgit\s+(checkout|switch)\s+(-b|-c|--create|-B)\b/.test(cmd)) {
|
|
146
|
-
return deny("the PM never creates a branch. Milestone files are committed to
|
|
164
|
+
return deny("the PM never creates a branch. Milestone files are committed to delivery.base_branch.");
|
|
147
165
|
}
|
|
148
166
|
if (/\bgit\s+(merge|rebase|cherry-pick|reset\s+--hard)\b/.test(cmd)) {
|
|
149
167
|
return deny("the PM never rewrites history or merges.");
|
|
@@ -56,7 +56,7 @@ blocked="$(printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD
|
|
|
56
56
|
}
|
|
57
57
|
if (!root) return;
|
|
58
58
|
|
|
59
|
-
// The
|
|
59
|
+
// The agentic-team repo is where these files are source. That is a fact
|
|
60
60
|
// about the tree, not about who is asking.
|
|
61
61
|
if (fs.existsSync(path.join(root, "bin/build-template.js"))) return;
|
|
62
62
|
|
|
@@ -114,7 +114,7 @@ Orchestra put it there. Editing it here is lost work: the next upgrade
|
|
|
114
114
|
overwrites it, and the next project meets the same problem you were about to
|
|
115
115
|
fix.
|
|
116
116
|
|
|
117
|
-
Change it in the
|
|
117
|
+
Change it in the agentic-team repo and reinstall. If it is genuinely
|
|
118
118
|
project-specific, it belongs in the app's own CLAUDE.md, a project skill of
|
|
119
119
|
your own, or .orchestra/config.yml — none of which is overwritten.
|
|
120
120
|
|
|
@@ -44,7 +44,7 @@ verdict="$(printf '%s' "$input" | CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD
|
|
|
44
44
|
}
|
|
45
45
|
if (call.tool_name !== "Agent") return;
|
|
46
46
|
const input = call.tool_input || {};
|
|
47
|
-
if (input.subagent_type !== "reviewer") return;
|
|
47
|
+
if (input.subagent_type !== "reviewer" && input.subagent_type !== "re-reviewer") return;
|
|
48
48
|
const prompt = String(input.prompt || "");
|
|
49
49
|
|
|
50
50
|
// The installer writes into the directory it ran in, which can be an app
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
This governs volume, never correctness. Validation, error handling, security
|
|
21
21
|
and accessibility are never on this ladder — they apply at every rung,
|
|
22
22
|
covered by their own rules (`security.orchestra.md`,
|
|
23
|
-
`observability.orchestra.md`, the `accessibility` skill
|
|
23
|
+
`observability.orchestra.md`, and the `accessibility` skill where the
|
|
24
|
+
platform has one), regardless of how
|
|
24
25
|
small the change looks. Rung 5 does not skip the wrapper
|
|
25
26
|
`testing-standards.orchestra.md` requires for anything calling a third-party
|
|
26
27
|
library (`src/integrations/<provider>/`) — that wrapper exists for the seam
|
|
@@ -28,7 +29,7 @@ test, not for swapability, and the ladder governs what sits on top of it,
|
|
|
28
29
|
never whether it exists.
|
|
29
30
|
|
|
30
31
|
**Zero-tolerance rules:**
|
|
31
|
-
- No workarounds — if the right solution is hard, do it right. Flag effort in report
|
|
32
|
+
- No workarounds — if the right solution is hard, do it right. Flag the effort in your report.
|
|
32
33
|
- No unused code — delete dead imports, functions, files. Don't comment out.
|
|
33
34
|
- No breaking changes without migration — update every consumer.
|
|
34
35
|
- Current library versions only — verify before using, don't assume from memory.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "designs/**"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Design Parity
|
|
2
7
|
|
|
3
8
|
## What a design source is
|
|
@@ -49,9 +54,15 @@ skipped. That is an honest unverified, not a pass.
|
|
|
49
54
|
designs/
|
|
50
55
|
├── <screen>.png the design, committed, mirroring the screen structure
|
|
51
56
|
├── .fetched/ a URL design, fetched once at milestone start
|
|
52
|
-
|
|
57
|
+
├── .captures/ what was built, committed so the PR can show it
|
|
58
|
+
└── .reports/ machine output of a comparison, gitignored
|
|
53
59
|
```
|
|
54
60
|
|
|
61
|
+
Only the images a pull request shows are committed. A comparison tool's
|
|
62
|
+
output — JSON reports, logs, diffs — goes to `designs/.reports/`, which is
|
|
63
|
+
never committed: it is regenerated from the images, and one project committed
|
|
64
|
+
~100k lines of it, which agents then read back as context.
|
|
65
|
+
|
|
55
66
|
A URL is fetched **once** into `designs/.fetched/`, when lead composes the
|
|
56
67
|
phase, not at each comparison. The capture goes to `designs/.captures/` and is
|
|
57
68
|
committed with the change, because `gh` cannot upload an image and a
|
|
@@ -35,6 +35,7 @@ Depth on what "handled" means — typed errors, propagation, what the user
|
|
|
35
35
|
sees, degrading instead of crashing — in
|
|
36
36
|
`.claude/skills/error-handling/SKILL.md`.
|
|
37
37
|
|
|
38
|
+
<!-- platforms: backend -->
|
|
38
39
|
## Structured logging
|
|
39
40
|
|
|
40
41
|
Logs are data, not prose. JSON, one event per line.
|
|
@@ -57,6 +58,7 @@ Logs are data, not prose. JSON, one event per line.
|
|
|
57
58
|
- Every line carries the release and environment, so a log and an error
|
|
58
59
|
report line up against the same deploy.
|
|
59
60
|
|
|
61
|
+
<!-- platforms: backend -->
|
|
60
62
|
## Health is two endpoints, not one
|
|
61
63
|
|
|
62
64
|
- **`/health`** — liveness. The process is up. Cheap, no dependencies.
|
|
@@ -76,6 +78,7 @@ anyway.
|
|
|
76
78
|
that makes it fail; if you add a dependency, add its probe and its failing
|
|
77
79
|
test in the same change.
|
|
78
80
|
|
|
81
|
+
<!-- platforms: backend -->
|
|
79
82
|
## Releasing
|
|
80
83
|
|
|
81
84
|
There is no percentage canary on Railway. What protects a release is:
|
|
@@ -122,6 +122,7 @@ Where the runtime is single-threaded, a synchronous call on a request path
|
|
|
122
122
|
stops every other request, not just this one. Blocking work there is a defect
|
|
123
123
|
even when it is fast in isolation.
|
|
124
124
|
|
|
125
|
+
<!-- platforms: web, expo, ios, android -->
|
|
125
126
|
## Rendering and interaction, wherever the UI runs
|
|
126
127
|
|
|
127
128
|
The words differ per platform; the constraints do not.
|
|
@@ -137,6 +138,7 @@ The words differ per platform; the constraints do not.
|
|
|
137
138
|
- **Never block the thread that draws.** Move parsing, crypto, image work and
|
|
138
139
|
large loops off it.
|
|
139
140
|
|
|
141
|
+
<!-- platforms: web -->
|
|
140
142
|
## The shipped size is a budget
|
|
141
143
|
|
|
142
144
|
Whatever the user downloads or installs has a number, and the number only goes
|
|
@@ -144,6 +146,7 @@ down. `.claude/rules/testing-standards.orchestra.md` holds the ratchet: it may
|
|
|
144
146
|
fall and may not rise, and deliberate growth is re-recorded in its own commit
|
|
145
147
|
so it is a decision rather than a drift.
|
|
146
148
|
|
|
149
|
+
<!-- platforms: web, expo, backend -->
|
|
147
150
|
## What is enforced
|
|
148
151
|
|
|
149
152
|
Only what can be decided precisely. Complexity, cache lifetime, index choice
|
|
@@ -181,6 +184,7 @@ as a library version.
|
|
|
181
184
|
## Depth
|
|
182
185
|
|
|
183
186
|
`.claude/skills/code-optimizer/SKILL.md` is for optimising code that already
|
|
184
|
-
exists. `.claude/skills/core-web-vitals/SKILL.md` is web-specific
|
|
187
|
+
exists. `.claude/skills/core-web-vitals/SKILL.md` is web-specific, and installed
|
|
188
|
+
only for web. Neither
|
|
185
189
|
covers writing something performant the first time, which is what this rule is
|
|
186
190
|
for.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Phase Limits
|
|
2
2
|
|
|
3
|
-
**Scope guard:** Working on something NOT in phase acceptance criteria → STOP.
|
|
3
|
+
**Scope guard:** Working on something NOT in phase acceptance criteria → STOP. Name it in your result's notes, don't implement; lead records it with `.orchestra/scripts/context.mjs journal`.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- ".github/**"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Pull Requests
|
|
2
7
|
|
|
3
8
|
**One task, one PR.** Always — there is no mode in which work reaches the
|
|
@@ -44,7 +49,7 @@ Open with a body file, never an inline string — the body contains newlines,
|
|
|
44
49
|
a table, and backticks:
|
|
45
50
|
|
|
46
51
|
```bash
|
|
47
|
-
gh pr create --title "#<task-id> - <subject>" --body-file .git/PR_BODY.md
|
|
52
|
+
gh pr create --base <delivery.base_branch> --title "#<task-id> - <subject>" --body-file .git/PR_BODY.md
|
|
48
53
|
```
|
|
49
54
|
|
|
50
55
|
## Naming
|
|
@@ -68,7 +73,7 @@ accepts `#<task-id> - <subject>` alongside the conventional form for exactly
|
|
|
68
73
|
this case. Without that, the delivery flow would produce the one commit the
|
|
69
74
|
repo's own gate rejects.
|
|
70
75
|
|
|
71
|
-
Record the returned URL. Lead reports it and stores it in `context.
|
|
76
|
+
Record the returned URL. Lead reports it and stores it in the phase's note (`context.mjs phase … "pr: <url>"`), so a
|
|
72
77
|
later session can find the PR without searching.
|
|
73
78
|
|
|
74
79
|
Reading the change is `gh pr diff <n>`, and a diff read straight into
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- ".orchestra/**"
|
|
4
|
+
- ".claude/**"
|
|
5
|
+
- "CLAUDE.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Role Boundary Enforcement
|
|
2
9
|
|
|
3
10
|
Before writing ANY file, check your role's ownership scope.
|
|
@@ -8,8 +15,8 @@ Before writing ANY file, check your role's ownership scope.
|
|
|
8
15
|
|------|-----------|----------------|
|
|
9
16
|
| Orchestrator | `.orchestra/roles/`, `.orchestra/config.yml`, `.orchestra/README.md`, `.orchestra/blueprints/`, `.orchestra/stacks/`, `.orchestra/trackers/`, `.orchestra/scripts/`, `.claude/agents/`, `.claude/hooks/`, `.claude/rules/*.orchestra.md`, `.claude/skills/*/SKILL.md`, `.claude/commands/orchestra/`, `CLAUDE.md`, `docs/` | Refuse |
|
|
10
17
|
| PM | `.orchestra/milestones/*` (prd, milestone, grooming, phases) | Refuse |
|
|
11
|
-
| Lead | `.orchestra/milestones/*/context.md` | Refuse |
|
|
12
|
-
| Scaffolder | `.orchestra/config.yml` (verification, tracker, observability keys only), scaffolded app files, repo config | Refuse |
|
|
18
|
+
| Lead | `.orchestra/milestones/*/{context,decisions,journal}.md`, through `.orchestra/scripts/context.mjs` | Refuse |
|
|
19
|
+
| Scaffolder | `.orchestra/config.yml` (verification, tracker, observability, `delivery.base_branch`, `project.platforms` keys only), scaffolded app files, repo config | Refuse |
|
|
13
20
|
| Tracker | Tracker id frontmatter in `.orchestra/milestones/*` | Refuse |
|
|
14
21
|
| Sub-agents | Only what phase `## Scope` defines | Refuse |
|
|
15
22
|
| Reviewer | Review verdict in phase file only | Refuse |
|
|
@@ -38,7 +45,7 @@ Two questions decide it, and neither is "which role is running": a slash
|
|
|
38
45
|
command is a markdown prompt and cannot export anything a hook could read on
|
|
39
46
|
its own, so a guard built only on the role would never fire.
|
|
40
47
|
|
|
41
|
-
**Which repo is this?** In the
|
|
48
|
+
**Which repo is this?** In the agentic-team repo these files are source, and
|
|
42
49
|
the hook allows everything. Elsewhere they are build output.
|
|
43
50
|
|
|
44
51
|
**Did Orchestra put this file here?** `.orchestra/.installed.json` records
|
|
@@ -63,7 +70,7 @@ Neither are `.orchestra/milestones/`, `blueprints/`, roles you create, or
|
|
|
63
70
|
skills and rules you write: none of them is in the manifest, because the
|
|
64
71
|
installer preserves them.
|
|
65
72
|
|
|
66
|
-
When it blocks: make the change in the
|
|
73
|
+
When it blocks: make the change in the agentic-team repo and reinstall, or —
|
|
67
74
|
if it is genuinely project-specific — put it in the app's own `CLAUDE.md`, a
|
|
68
75
|
project skill of your own, or `config.yml`, none of which is overwritten.
|
|
69
76
|
|
|
@@ -85,14 +92,22 @@ any `Agent` launch other than `milestone-reviewer` and `tracker`; any
|
|
|
85
92
|
backlog one. The last three came from one afternoon: the word "ultracode" in
|
|
86
93
|
a message told the platform to use the Workflow tool, and a PM whose role
|
|
87
94
|
said "cannot review code" ran a multi-agent code review, recommended itself
|
|
88
|
-
for it, and opened the task straight into `in progress`.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
for it, and opened the task straight into `in progress`.
|
|
96
|
+
|
|
97
|
+
Lead is held to one rule: phase work starts inside a milestone agent. An
|
|
98
|
+
`engineer-*`, `reviewer` or `re-reviewer` launched from the lead session
|
|
99
|
+
itself is refused; one launched by a milestone agent passes, because a call
|
|
100
|
+
from a sub-agent carries `agent_id` and one from the session does not —
|
|
101
|
+
verified against a live payload. A hotfix engineer whose prompt starts with
|
|
102
|
+
`Hotfix:` passes. One run kept two milestones in the lead session and grew
|
|
103
|
+
to 738 calls and a 925k-token context. Sub-agents share the session id, so
|
|
104
|
+
the role marker reaches them; lead's own sub-agents still write code, which
|
|
105
|
+
is why nothing else is restricted. The Orchestrator is recorded and not
|
|
106
|
+
restricted.
|
|
92
107
|
|
|
93
108
|
Two things are structural rather than hook-judged, because they do not
|
|
94
109
|
depend on the role. `Workflow` is denied in the project's `settings.json`;
|
|
95
|
-
no role runs one. The reviewer and the milestone reviewer carry
|
|
110
|
+
no role runs one. The reviewer, the re-reviewer and the milestone reviewer carry
|
|
96
111
|
`disallowedTools: [Write, Edit, NotebookEdit]` in their frontmatter; they
|
|
97
112
|
review, and Claude Code removes the tools rather than asking them not to.
|
|
98
113
|
|
|
@@ -52,7 +52,7 @@ staged changes, where it is still cheap to fix.
|
|
|
52
52
|
`scripts/policy-check.mjs` runs in the gate. These are the checks it makes
|
|
53
53
|
that belong to this rule — it decides others too;
|
|
54
54
|
`.claude/rules/performance.orchestra.md` and
|
|
55
|
-
`.claude/rules/comments.orchestra.md` each list their own:
|
|
55
|
+
`.claude/rules/comments.orchestra.md` each list their own where they apply:
|
|
56
56
|
|
|
57
57
|
| Check | What fails |
|
|
58
58
|
|---|---|
|
|
@@ -9,7 +9,7 @@ You are **stuck** when any of these happen:
|
|
|
9
9
|
## Recovery Protocol
|
|
10
10
|
|
|
11
11
|
1. **STOP immediately.** Do not attempt another fix.
|
|
12
|
-
2. **Log**
|
|
12
|
+
2. **Log** it: `node .orchestra/scripts/context.mjs journal <m> <phase> "stuck: <symptom>; tried <attempts>; likely <cause>"` — or, as a sub-agent, put it in your result's notes for lead to record.
|
|
13
13
|
3. **Try a different approach** (ONE attempt):
|
|
14
14
|
- Same code fix failed? → entirely different implementation strategy
|
|
15
15
|
- Dependency broken? → alternative library
|
|
@@ -15,6 +15,7 @@ if the suite covers the seams where our code meets someone else's.
|
|
|
15
15
|
Snapshot tests do not satisfy this. A snapshot passes while a handler
|
|
16
16
|
silently stops firing — assert behaviour, not markup.
|
|
17
17
|
|
|
18
|
+
<!-- platforms: backend -->
|
|
18
19
|
## Backend — the shape
|
|
19
20
|
|
|
20
21
|
The test pyramid is wrong for a backend. It comes from an era when starting
|
|
@@ -52,7 +53,7 @@ forbids this.
|
|
|
52
53
|
- Each test creates the data it needs. A shared seed fixture is what makes
|
|
53
54
|
a suite unmaintainable somewhere around test three hundred.
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
## Fake external services at the network boundary
|
|
56
57
|
|
|
57
58
|
Intercept the HTTP call — MSW or a stub server. Do **not** mock your own
|
|
58
59
|
`sendEmail()`.
|
|
@@ -60,7 +61,7 @@ Intercept the HTTP call — MSW or a stub server. Do **not** mock your own
|
|
|
60
61
|
Mocking your own wrapper means the wrapper is never tested, and the wrapper
|
|
61
62
|
is exactly where a provider's API change bites you.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
## Test data
|
|
64
65
|
|
|
65
66
|
Synthetic, built by factories, created per test. Never a copy of production
|
|
66
67
|
data — it carries PII and it drifts.
|
|
@@ -94,6 +95,7 @@ Do not chase the global number with unit tests. If the integration tests
|
|
|
94
95
|
are real, coverage arrives on its own. If tests are being written to move a
|
|
95
96
|
percentage, the gate has started doing harm — say so rather than complying.
|
|
96
97
|
|
|
98
|
+
<!-- platforms: web, expo, backend -->
|
|
97
99
|
## Mutation testing
|
|
98
100
|
|
|
99
101
|
Coverage says a line ran. Mutation says the line was **checked**.
|
|
@@ -113,6 +115,7 @@ On an app using TS 7 the scaffolder skips the install and says so — do not
|
|
|
113
115
|
work around it by pinning TypeScript backwards. The gate turns on by itself
|
|
114
116
|
once Stryker supports the new compiler.
|
|
115
117
|
|
|
118
|
+
<!-- platforms: web -->
|
|
116
119
|
## Web — jsdom is not a browser
|
|
117
120
|
|
|
118
121
|
It has no layout engine. `getBoundingClientRect` returns zeros, nothing
|
|
@@ -137,6 +140,7 @@ item here.
|
|
|
137
140
|
|
|
138
141
|
Depth in `.claude/skills/web-testing/SKILL.md`.
|
|
139
142
|
|
|
143
|
+
<!-- platforms: expo -->
|
|
140
144
|
## Mobile is a different shape
|
|
141
145
|
|
|
142
146
|
Jest does not run React Native — `jest-expo` runs components in Node against
|
|
@@ -151,10 +155,9 @@ expo-doctor
|
|
|
151
155
|
expo install --check
|
|
152
156
|
```
|
|
153
157
|
|
|
154
|
-
Depth in `.claude/skills/mobile-testing/SKILL.md`.
|
|
155
|
-
have their own shapes again — `.claude/skills/ios-testing/SKILL.md` and
|
|
156
|
-
`.claude/skills/android-testing/SKILL.md`.
|
|
158
|
+
Depth in `.claude/skills/mobile-testing/SKILL.md`.
|
|
157
159
|
|
|
160
|
+
<!-- platforms: ios, android -->
|
|
158
161
|
## Native has two more shapes
|
|
159
162
|
|
|
160
163
|
**iOS:** a green unit suite does not prove the app launches. A missing
|
|
@@ -175,6 +178,7 @@ accessibility instead of review noticing it.
|
|
|
175
178
|
Depth in `.claude/skills/ios-testing/SKILL.md` and
|
|
176
179
|
`.claude/skills/android-testing/SKILL.md`.
|
|
177
180
|
|
|
181
|
+
<!-- platforms: web -->
|
|
178
182
|
## The bundle has a budget, and it is a ratchet
|
|
179
183
|
|
|
180
184
|
Same shape as the coverage ratchet: the committed baseline is whatever the
|
|
@@ -187,6 +191,7 @@ browser downloads.
|
|
|
187
191
|
Deliberate growth is re-recorded on purpose, in its own commit, so it is a
|
|
188
192
|
decision somebody made rather than a number that drifted.
|
|
189
193
|
|
|
194
|
+
<!-- platforms: web, expo, backend -->
|
|
190
195
|
## A build is part of the suite
|
|
191
196
|
|
|
192
197
|
`tsc --noEmit` accepts an app that fails to bundle, and neither tests nor
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- ".orchestra/milestones/**"
|
|
4
|
+
- ".orchestra/trackers/**"
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Tracker Authority
|
|
2
8
|
|
|
3
9
|
`tracker.provider` in `.orchestra/config.yml` decides who owns requirements.
|
|
@@ -24,7 +30,9 @@ The milestone directory holds pointers, and only pointers:
|
|
|
24
30
|
tracker.yml committed provider, epic id, task ids, urls
|
|
25
31
|
phases/*.md committed the PM's draft — what export pushes; lead never reads it
|
|
26
32
|
.cache/ gitignored requirement text, fetched once per run
|
|
27
|
-
context.md committed lead's
|
|
33
|
+
context.md committed lead's state: status, phases, codebase map
|
|
34
|
+
decisions.md committed lead's decisions, open until closed
|
|
35
|
+
journal.md committed what was tried and why it lost
|
|
28
36
|
```
|
|
29
37
|
|
|
30
38
|
The draft is not a second source of truth, because nothing reads it but
|
|
@@ -17,7 +17,7 @@ arrives.
|
|
|
17
17
|
Push needs a build with your own credentials, on a real device, with the app
|
|
18
18
|
in each of three states — foreground, background, terminated. Anything less
|
|
19
19
|
tests the mock. This is the same reason the device layer is not optional in
|
|
20
|
-
`.claude/skills/mobile-testing/SKILL.md
|
|
20
|
+
`.claude/skills/mobile-testing/SKILL.md`, on Expo.
|
|
21
21
|
|
|
22
22
|
Resolve the SDK's current API and constraints from its own docs at
|
|
23
23
|
implementation time. This area changes across SDK releases, and a handler
|