feat(#347): promote engineering-dept roles to sub-agents + Activation mode (Wave 1 PR 1)#355
Conversation
…/*) per AgDR-0050 Axis 1 + 2 Promotes the 7 engineering-department personas to first-class Claude Code sub-agents — Wave 1 PR 1 of the agent-runtime-overhaul shipped against AgDR-0050. Agent files are THIN WRAPPERS per AgDR-0050 Axis 1 (WRAP): - roles/engineering/<role>.md stays the canonical persona definition - .claude/agents/<slug>.md owns only name/description/model/ allowed-tools/persona_name frontmatter + a body that references @roles/engineering/<slug>.md - No content duplication; the persona is read at activation time Default model matrix per AgDR-0050 Axis 2: - opus: head-of-engineering (Khalid), tech-lead (Hisham), sre (Saif) - sonnet: backend-engineer (Karim), frontend-engineer (Yasmin), platform-engineer (Adel) - haiku: qa-engineer (Salim) — read-only by design (no Edit/Write), AC verification + checklist work is repeatable + cheap Adopters will override per-agent via the routing config landing in #351 (Wave 1 PR 1 of that ticket runs in parallel with this). Refs #347
…gDR-0050 Axis 6
Every persona definition in roles/{department}/<role>.md now declares
its activation class explicitly. This closes the gap where the
hybrid sub-agent vs in-thread choice from AgDR-0050 § Axis 6 lived
only in the AgDR body — operators couldn't see at a glance whether
activating a role spawns an isolated sub-agent or adopts the persona
in-thread.
Section format per role:
- **Class**: isolated-work-class | in-flow-class
- **Sub-agent file**: .claude/agents/<slug>.md + which PR ships it
- **On trigger**: what detect-role-trigger.sh does once the sub-agent
is wired in (PR 5)
- **Rationale**: one sentence tying the class choice to the AgDR
Classification follows AgDR-0050 § Axis 6 table exactly:
- isolated-work-class (12): all 5 Heads of, Tech Lead, QA Engineer,
SRE, Security Auditor, Pen Tester, Product Analyst, Data Analyst
- in-flow-class (7): Backend / Frontend Engineer, Platform Engineer,
Data Engineer, Product Manager, UI Designer, UX Designer
The 7 engineering-dept sub-agent files exist as of the prior commit
(this PR); the other 12 ship in #347 PR 2 (product + design) and
PR 3 (security + data). Until those land, the in-thread role-
adoption mechanism continues to apply for un-shipped roles — the
section documents the intended state, not a runtime guarantee.
Refs #347
…ivation mode coverage Pins the AgDR-0050 invariants this PR establishes so future Wave 1-4 work (and any drift from the agent-routing config sync hook landing in #351) can verify it isn't regressing them: 1. All 7 engineering agent files exist at .claude/agents/<slug>.md 2. Each has the required frontmatter (name, description, model, allowed-tools, persona_name) 3. Each model value is one of opus | sonnet | haiku AND matches the AgDR-0050 § Axis 2 default matrix entry for that role 4. Each agent body references @roles/engineering/<slug>.md (the WRAP contract — agents delegate identity to roles/, no duplication) 5. All 19 role files have a ## Activation mode section 6. Each role's Class value matches the AgDR-0050 § Axis 6 hybrid table exactly Style follows the existing framework convention (set -u, ROOT from dirname, red/green helpers, FAIL counter, exit 0/1). No external test framework. Tests live under .claude/agents/tests/ — first file in that new tree; sibling to .claude/hooks/tests/ and .claude/skills/<name>/tests/. 26 invariants verified, all PASS at this commit. Refs #347
… 7 engineering)
The framework-integration table's Agents row previously named the 5
utility agents (Rex, Hatim, Munir, Tariq, Idris). After this PR, 7
engineering-role-derived agents land in .claude/agents/ alongside
the utility agents, so the row needs to name the new shape.
New row text (23 words, under the ≤ 25-word Wave 1 invariant on
table rows per AgDR-0044):
12 sub-agents (5 utility: Rex, Hatim, Munir, Tariq, Idris;
7 engineering: Khalid, Hisham, Karim, Yasmin, Salim, Adel,
Saif). Growing to 24 per AgDR-0050.
The growth footer ("Growing to 24 per AgDR-0050") signals the
direction without spelling out the per-wave breakdown — that lives
in AgDR-0050's PR plan section + each PR's body.
test_token_efficiency_wave1.sh continues to pass (all four
invariants OK) — the row stays terse and discoverable.
Refs #347
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #355
Commit: b68bb5c9e507e02f2e62af5d45574b196ea1f6ee
Summary
Wave 1 PR 1 of #347 (AgDR-0050 agent-runtime-overhaul). Ships the 7 engineering-department sub-agent wrappers per Axis 1 (thin WRAP shape — frontmatter + body referencing @roles/engineering/<slug>.md), assigns the framework default model matrix per Axis 2, restricts the QA Engineer to read-only tools by design, and adds a ## Activation mode section to all 19 role files per Axis 6. CLAUDE.md's Agents row updates from "5 sub-agents" to "12 sub-agents (5 utility + 7 engineering). Growing to 24 per AgDR-0050." — 23 words, under the 25-word Wave 1 budget.
Checklist Results
- Architecture & Design: Pass — clean WRAP separation, agent files own runtime overlay only, role files remain canonical persona definitions, zero content duplication
- Code Quality: Pass — 26-invariant smoke test follows the framework
.claude/hooks/tests/convention (set -u, ROOT-from-dirname, red/green helpers, FAIL counter, exit 0/1) - Testing: Pass — the test asserts file existence, all 5 required frontmatter keys, model values strictly in the matrix, persona-name match, role-file reference in each body, every role-file
## Activation modeheading +**Class**:value matching the AgDR-0050 § Axis 6 table - Security: Pass — no secrets, no auth surface touched; QA Engineer's read-only contract is now mechanical (
allowed-tools: Bash, Read, Grep, Glob) - Performance: Pass — model matrix routes haiku for repeatable QA, sonnet for implementation, opus for depth; matches the cost/latency design in AgDR-0050
- PR Description & Glossary: Pass — 6 narrative bullets, each answers what + why; Glossary covers WRAP, isolated-work-class, in-flow-class, persona_name, model matrix, Wave 1 invariants
- Technical Decisions (AgDR):Pass (N/A new) — implements AgDR-0050 (already merged on dev); no new decisions introduced, no scope-creep needing a fresh AgDR
- Adopter Handbooks: N/A — diff is markdown + bash only; no language handbooks apply, no public
handbooks/architectureorhandbooks/generalrule trips
Issues Found
None blocking. Verified against the requested 11 invariants:
- WRAP shape uniform across 7 agents — every file has the 5 frontmatter keys, body references
@roles/engineering/<slug>.md, no duplicated persona content. QA wrapper carries one extra paragraph explaining the read-only ticket-bounce-back contract — appropriate, the tool restriction is load-bearing. - Model matrix matches AgDR-0050 § Axis 2 EXACTLY — opus (head-of-engineering, tech-lead, sre), sonnet (backend, frontend, platform), haiku (qa-engineer). No drift.
- QA Engineer tool restriction correct —
allowed-tools: Bash, Read, Grep, Glob(no Edit, no Write); the other 6 carry the full set. - All 19 role files have
## Activation modewith correct class — 12 isolated-work-class + 7 in-flow-class match the AgDR table exactly. - Smoke test would FAIL on any drift — per-agent loop checks 4 invariants per agent, per-role loop checks 2 per role; both encode the matrix as data so a future regression is mechanically caught.
- CLAUDE.md Agents row 23 words —
wc -wconfirms; under 25-word budget; "Growing to 24" matches the wave plan (5 + 7 + 6 + 6 = 24). - No
model:frontmatter on utility agents —code-reviewer.md/security-reviewer.md/dependency-auditor.md/pr-manager.md/ticket-manager.mdare NOT in the diff. PR 4 territory preserved. - No routing config / sync hook / drift guards — diff stays within
.claude/agents/{7 wrappers + 1 test}+ 19 role files + CLAUDE.md. No.claude/hooks/, noproject-config.defaults.json. #351 territory preserved. - No role-trigger integration —
detect-role-trigger.shunchanged;## Activation modesections document the future state with "once PR 5 lands…" prose. PR 5 territory preserved. - PR body — narrative bullets, Glossary,
Refs #347(not Closes),Per AgDR-0050-agent-runtime-overhaul.reference, wave plan documented in body. - Wave 1 invariants PASS — Agents row at 23 words confirms the row-length invariant directly; agent's reported 4/4 PASS on
test_token_efficiency_wave1.shis consistent with the diff (no SKILL.md changes, no banner changes).
Handbook Findings
No handbook findings. Diff is markdown + bash. No architecture/ or general/ always-load handbooks trip on this content; no language/typescript|python|go|rust/ handbooks apply.
Suggestions
nit: (non-blocking)
- N1 — The smoke test's invariant list (header comment, lines 162-173 of the test) doesn't explicitly note that the QA wrapper is allowed to carry one extra paragraph by design. A future contributor adding similar prose to another wrapper might cite QA as precedent. Consider a one-line note in the header: "Wrappers are thin by convention; the QA wrapper carries one additional read-only-contract paragraph by design (AgDR-0050 § Axis 2)."
- N2 —
## Activation context(in agent bodies) vs## Activation mode(in role files) are visually close. Both reference AgDR-0050 § Axis 6, so the rendered hierarchy is coherent, but a future reader could conflate them. The smoke test pins the role-file heading exactly, so accidental drift would surface — leave as is or rename one in a follow-up if it bites. - N3 —
roles/data/head-of-data.mdandroles/security/head-of-security.mdRationale lines are terser ("strategy; sparse.") than the engineering-side Heads. Consistency would be nicer, but the role files belong to PR 2/3's stewardship and the activation-class is what's load-bearing.
Verdict
APPROVED
The PR ships exactly what AgDR-0050 Wave 1 PR 1 specifies, with mechanical drift-protection via the smoke test, and zero scope-creep into PR 2-5 or #351. CI 4/4 green. The model matrix, tool-restriction, and activation-class assignments all match the AgDR. Wave 1 token-budget invariants pass.
Sandbox blocked the approval-marker write — operator should write the marker on Rex's behalf:
printf '%s\n' "b68bb5c9e507e02f2e62af5d45574b196ea1f6ee" > /Users/ahmed/Projects/apexstack/.claude/session/reviews/355-rex.approved(Per the operator's MEMORY note feedback_rex_marker_sandbox_workaround.md.)
🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: b68bb5c9e507e02f2e62af5d45574b196ea1f6ee
… mode (Wave 1 PR 1) (#355) * feat(#347): add 7 engineering-dept sub-agent wrappers (.claude/agents/*) per AgDR-0050 Axis 1 + 2 Promotes the 7 engineering-department personas to first-class Claude Code sub-agents — Wave 1 PR 1 of the agent-runtime-overhaul shipped against AgDR-0050. Agent files are THIN WRAPPERS per AgDR-0050 Axis 1 (WRAP): - roles/engineering/<role>.md stays the canonical persona definition - .claude/agents/<slug>.md owns only name/description/model/ allowed-tools/persona_name frontmatter + a body that references @roles/engineering/<slug>.md - No content duplication; the persona is read at activation time Default model matrix per AgDR-0050 Axis 2: - opus: head-of-engineering (Khalid), tech-lead (Hisham), sre (Saif) - sonnet: backend-engineer (Karim), frontend-engineer (Yasmin), platform-engineer (Adel) - haiku: qa-engineer (Salim) — read-only by design (no Edit/Write), AC verification + checklist work is repeatable + cheap Adopters will override per-agent via the routing config landing in #351 (Wave 1 PR 1 of that ticket runs in parallel with this). Refs #347 * feat(#347): add ## Activation mode section to all 19 role files per AgDR-0050 Axis 6 Every persona definition in roles/{department}/<role>.md now declares its activation class explicitly. This closes the gap where the hybrid sub-agent vs in-thread choice from AgDR-0050 § Axis 6 lived only in the AgDR body — operators couldn't see at a glance whether activating a role spawns an isolated sub-agent or adopts the persona in-thread. Section format per role: - **Class**: isolated-work-class | in-flow-class - **Sub-agent file**: .claude/agents/<slug>.md + which PR ships it - **On trigger**: what detect-role-trigger.sh does once the sub-agent is wired in (PR 5) - **Rationale**: one sentence tying the class choice to the AgDR Classification follows AgDR-0050 § Axis 6 table exactly: - isolated-work-class (12): all 5 Heads of, Tech Lead, QA Engineer, SRE, Security Auditor, Pen Tester, Product Analyst, Data Analyst - in-flow-class (7): Backend / Frontend Engineer, Platform Engineer, Data Engineer, Product Manager, UI Designer, UX Designer The 7 engineering-dept sub-agent files exist as of the prior commit (this PR); the other 12 ship in #347 PR 2 (product + design) and PR 3 (security + data). Until those land, the in-thread role- adoption mechanism continues to apply for un-shipped roles — the section documents the intended state, not a runtime guarantee. Refs #347 * test(#347): smoke test for engineering agent wrap-shape + 19-role Activation mode coverage Pins the AgDR-0050 invariants this PR establishes so future Wave 1-4 work (and any drift from the agent-routing config sync hook landing in #351) can verify it isn't regressing them: 1. All 7 engineering agent files exist at .claude/agents/<slug>.md 2. Each has the required frontmatter (name, description, model, allowed-tools, persona_name) 3. Each model value is one of opus | sonnet | haiku AND matches the AgDR-0050 § Axis 2 default matrix entry for that role 4. Each agent body references @roles/engineering/<slug>.md (the WRAP contract — agents delegate identity to roles/, no duplication) 5. All 19 role files have a ## Activation mode section 6. Each role's Class value matches the AgDR-0050 § Axis 6 hybrid table exactly Style follows the existing framework convention (set -u, ROOT from dirname, red/green helpers, FAIL counter, exit 0/1). No external test framework. Tests live under .claude/agents/tests/ — first file in that new tree; sibling to .claude/hooks/tests/ and .claude/skills/<name>/tests/. 26 invariants verified, all PASS at this commit. Refs #347 * docs(#347): CLAUDE.md agent-count row reflects 12 agents (5 utility + 7 engineering) The framework-integration table's Agents row previously named the 5 utility agents (Rex, Hatim, Munir, Tariq, Idris). After this PR, 7 engineering-role-derived agents land in .claude/agents/ alongside the utility agents, so the row needs to name the new shape. New row text (23 words, under the ≤ 25-word Wave 1 invariant on table rows per AgDR-0044): 12 sub-agents (5 utility: Rex, Hatim, Munir, Tariq, Idris; 7 engineering: Khalid, Hisham, Karim, Yasmin, Salim, Adel, Saif). Growing to 24 per AgDR-0050. The growth footer ("Growing to 24 per AgDR-0050") signals the direction without spelling out the per-wave breakdown — that lives in AgDR-0050's PR plan section + each PR's body. test_token_efficiency_wave1.sh continues to pass (all four invariants OK) — the row stays terse and discoverable. Refs #347 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Summary
.claude/agents/(head-of-engineering, tech-lead, backend-engineer, frontend-engineer, qa-engineer, platform-engineer, sre) — promotes the engineering personas from passive markdown role docs to first-class Claude Code sub-agents with explicit model assignment and tool restriction. Wave 1 PR 1 of the agent-runtime-overhaul shipped against AgDR-0050.name/description/model/allowed-tools/persona_namefrontmatter + a body that references@roles/engineering/<role>.md. The persona definition stays inroles/; agent files are the runtime overlay. Zero content duplication, so a persona edit lands in one place and the wrapper stays inert.opusfor depth (Khalid, Hisham, Saif),sonnetfor implementation default (Karim, Yasmin, Adel),haikufor repeatable checklist work (Salim, QA Engineer). QA also ships without Edit/Write per its read-only contract: QA verifies, doesn't ship; the fix flows back to an engineer through a fresh ticket. Adopters override per-agent via the routing config landing in [Feature] Centralised agent-routing config — agent-routing.yaml in private repo, propagates to .claude/agents/*.md at SessionStart #351 (Wave 1 PR 1 of that ticket runs in parallel).## Activation modesection added to all 19 role files per AgDR-0050 § Axis 6 — every persona definition now declares its activation class explicitly (isolated-work-class for 12 roles like QA / Pen Tester / Data Analyst / all 5 Heads of / Security Auditor / Tech Lead; in-flow-class for 7 roles like Backend / Frontend Engineer / Platform Engineer / PM / Designers / Data Engineer). Closes the gap where the hybrid sub-agent vs in-thread choice lived only in the AgDR body — operators can now see at a glance whether activating a role spawns an isolated sub-agent or adopts the persona in-thread..claude/agents/tests/test_engineering_agents_wrap_shape.shpins 26 invariants (agent files exist, frontmatter complete, model values in the matrix, role-file references present, all 19 role files declare a## Activation modeClass matching the AgDR table). First test under.claude/agents/tests/; style matches.claude/hooks/tests/(set -u, ROOT from dirname, red/green helpers, FAIL counter, exit 0/1). All PASS at this commit.test_token_efficiency_wave1.shcontinues to pass (all four invariants OK).This is Wave 1 PR 1 of 4 for #347. Per the AgDR-0050 PR plan: PR 1 (this) + #351 PR 1 are parallelisable. PR 2 ships the product + design agents (6); PR 3 ships security + data (6) + Hatim/Hakim consolidation decision; PR 4 adds
model:frontmatter to the 5 utility agents (Rex, Hatim, Munir, Tariq, Idris); PR 5 wiresdetect-role-trigger.shto spawn sub-agents for isolated-work-class roles. The role-trigger integration is deliberately deferred to PR 5 — until then, the## Activation modesections document the intended state, and in-thread role-adoption remains the active mechanism for un-shipped roles.Per AgDR-0050-agent-runtime-overhaul.
Testing
bash .claude/agents/tests/test_engineering_agents_wrap_shape.sh— all 26 invariants PASS (7 engineering agents pass file-exists + frontmatter shape + model-matrix + role-reference; all 19 role files pass## Activation modeClass match)bash .claude/hooks/tests/test_token_efficiency_wave1.sh— all four Wave 1 invariants PASS (CLAUDE.md skill-table row word-count, SKILL.md description char budget, skill catalogue completeness, SessionStart banner char budget)head -8 .claude/agents/qa-engineer.mdshowsmodel: haiku+allowed-tools: Bash, Read, Grep, Glob(NO Edit/Write — read-only by mechanical contract perroles/engineering/qa-engineer.md)head -8 .claude/agents/tech-lead.mdshowsmodel: opus,persona_name: Hishamgrep -c "## Activation mode" roles/*/*.md | wc -lreturns 19 (every role file gained the section)Refs #347
Glossary
roles/<dept>/<role>.md; the runtime wrapper at.claude/agents/<slug>.mdowns only frontmatter (model,allowed-tools,persona_name) plus a body that references the role file. Zero content duplication.persona_namefrontmatter field▸ Activating <name> (<role>) for #<ticket>activation-marker line.opus/sonnet/haiku). Opus for depth + reasoning; Sonnet for implementation + tool-use-heavy work; Haiku for repeatable checklist-shaped work. Adopters override per-agent via the routing config landing in #351..claude/hooks/tests/test_token_efficiency_wave1.sh— CLAUDE.md skill-table row ≤ 25 words, SKILL.mddescription:≤ 200 chars hard / ≤ 120 soft, every skill catalogued in CLAUDE.md, SessionStart banner ≤ 600 chars. This PR adjusts the Agents row to a 23-word description so it stays under the row-length cap.