From 758b76b397922018629018bb0d614745983cfd07 Mon Sep 17 00:00:00 2001 From: Robert Allen Date: Sat, 21 Feb 2026 22:38:56 -0500 Subject: [PATCH 1/4] perf(.claude): sync agents and spec-orchestrator from rust-template - Add team coordination tools to all agents - Update spec-orchestrator command with lifecycle fixes --- .claude/agents/code-reviewer.md | 5 +- .claude/agents/rust-developer.md | 5 +- .claude/agents/test-engineer.md | 5 +- .claude/commands/spec-orchestrator.md | 611 ++++++++++++++++++++++++++ 4 files changed, 617 insertions(+), 9 deletions(-) create mode 100644 .claude/commands/spec-orchestrator.md diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md index 06debfc..f5ed8fa 100644 --- a/.claude/agents/code-reviewer.md +++ b/.claude/agents/code-reviewer.md @@ -1,10 +1,9 @@ --- name: code-reviewer -description: > - Code review specialist for Rust projects. Use after completing features or before PRs to ensure memory safety, idiomatic Rust, and adherence to project standards. +description: Code review specialist for Rust projects. Use after completing features or before PRs to ensure memory safety, idiomatic Rust, and adherence to project standards. model: inherit color: orange -tools: Read, Glob, Grep, Bash +tools: Read, Write, Edit, Bash, Glob, Grep, LSP, SendMessage, TaskList, TaskGet, TaskCreate, TaskUpdate --- # Code Reviewer Agent diff --git a/.claude/agents/rust-developer.md b/.claude/agents/rust-developer.md index a5542da..222b9a8 100644 --- a/.claude/agents/rust-developer.md +++ b/.claude/agents/rust-developer.md @@ -1,10 +1,9 @@ --- name: rust-developer -description: > - Primary development agent for this Rust project. Handles implementation, testing, and ownership/borrowing patterns. Use for writing safe, performant Rust code. +description: Primary development agent for this Rust project. Handles implementation, testing, and ownership/borrowing patterns. Use for writing safe, performant Rust code. model: inherit color: red -tools: Read, Write, Edit, Bash, Glob, Grep, LSP +tools: Read, Write, Edit, Bash, Glob, Grep, LSP, SendMessage, TaskList, TaskGet, TaskUpdate --- # Rust Developer Agent diff --git a/.claude/agents/test-engineer.md b/.claude/agents/test-engineer.md index d778f8f..14b48b8 100644 --- a/.claude/agents/test-engineer.md +++ b/.claude/agents/test-engineer.md @@ -1,10 +1,9 @@ --- name: test-engineer -description: > - Testing specialist for Rust test suites. Use for writing tests, property-based testing, and establishing Rust testing patterns. +description: Testing specialist for Rust test suites. Use for writing tests, property-based testing, and establishing Rust testing patterns. model: inherit color: green -tools: Read, Write, Edit, Bash, Glob, Grep +tools: Read, Write, Edit, Bash, Glob, Grep, LSP, SendMessage, TaskList, TaskGet, TaskUpdate --- # Test Engineer Agent diff --git a/.claude/commands/spec-orchestrator.md b/.claude/commands/spec-orchestrator.md new file mode 100644 index 0000000..74593f2 --- /dev/null +++ b/.claude/commands/spec-orchestrator.md @@ -0,0 +1,611 @@ +--- +name: spec-orchestrator +description: Orchestrate implementation of a large specification using parallel agent teams. Reads specs via discovery subagents, synthesizes a task plan, spawns implementation teammates, and manages wave-based execution. +allowed-tools: + - Task + - Bash + - Read + - Write + - Glob + - Grep + - TaskCreate + - TaskUpdate + - TaskList + - TeamCreate + - TeamDelete + - SendMessage + - AskUserQuestion +argument-hint: "[--auto] [spec-directory]" +--- + +# Spec Orchestrator Command + +You are now running the **spec-orchestrator** procedure. You will execute this step-by-step in the main conversation, keeping the user informed at every phase. Heavy work (reading specs, writing code) is delegated to `Task` subagents. You orchestrate the lifecycle. + +## Argument Parsing + +Parse `$ARGUMENTS` for flags and the spec directory: + +- **`--auto`**: Autonomous mode. Skip all `AskUserQuestion` checkpoints, accept all recommendations as-is, and perform maximum work identified. Log decisions to `/tmp/orchestrator-decisions.md` instead of asking. +- **Spec directory**: Any argument that is not a flag. Defaults to `docs/spec/`. + +Examples: +- `/spec-orchestrator` → interactive mode, `docs/spec/` +- `/spec-orchestrator docs/api-spec/` → interactive mode, `docs/api-spec/` +- `/spec-orchestrator --auto` → autonomous mode, `docs/spec/` +- `/spec-orchestrator --auto docs/api-spec/` → autonomous mode, `docs/api-spec/` + +Set `AUTO_MODE=true` if `--auto` is present, `false` otherwise. + +--- + +## Phase 0: Bootstrap — Understand the Landscape + +Perform lightweight reconnaissance with native tools: + +1. **Read conventions**: `Read` CLAUDE.md in full — it defines the source root and all project conventions. +2. **Enumerate spec files**: `Glob` pattern `{spec_dir}/**/*` — group by type (`.md`, `.yaml`, `.json`). +3. **Enumerate source files**: `Glob` with the source root from CLAUDE.md (e.g., `crates/**/*.rs`). +4. **Assess large files**: `Read` with `limit: 5` on potentially large files to gauge scope before partitioning. + +From this, build a **partition plan**: group spec files into batches of 3-5, pairing each with the most relevant source directories. + +**Key principle**: Each discovery subagent should receive no more than ~40% of its context window in input material. + +**Show the partition plan to the user before proceeding.** + +--- + +## Phase 1: Distributed Discovery + +### 1.1 Spawn Discovery Subagents + +Spawn one `Task` subagent per partition (up to 5 concurrent), using `subagent_type: "general-purpose"`. Each produces a **structured inventory** at `/tmp/discovery/partition-{N}.json`. + +**IMPORTANT**: Discovery subagents are fire-and-done `Task` calls with NO `team_name`. They cannot use `SendMessage`. Their output is returned via the Task tool result. + +#### Discovery Prompt Template + +Give each subagent this directive (customized with their assigned files): + +``` +You are a **discovery analyst**. Your job is to thoroughly read assigned spec files +and related source code, then produce a structured inventory. + +## Your Assigned Files + +### Spec files to read (READ EVERY LINE): +- {spec_file_1} +- {spec_file_2} +- {spec_file_3} + +### Related existing source to read (for patterns and existing implementations): +- {src_dir_or_files} + +### Project conventions (read first): +- CLAUDE.md + +## What to Extract + +Read every file completely. Do not skim. Then produce a JSON inventory written to +`/tmp/discovery/{partition_name}.json` with this structure: + +{ + "partition": "{partition_name}", + "endpoints": [ + { + "method": "POST", + "path": "/api/v1/things", + "spec_file": "docs/spec/sections/things.md", + "request_schema": "CreateThingRequest { name: String, ... }", + "response_schema": "Thing { id: Uuid, ... }", + "status_codes": [201, 400, 401, 409, 422], + "error_cases": ["name already exists", "invalid field X"], + "auth_required": true, + "pagination": false, + "notes": "any special behavior, business rules, edge cases" + } + ], + "models": [ + { + "name": "Thing", + "spec_file": "docs/spec/sections/things.md", + "fields": [ + {"name": "id", "type": "Uuid", "constraints": "primary key, auto-generated"}, + {"name": "name", "type": "String", "constraints": "unique, 1-255 chars"} + ], + "relationships": ["belongs_to User via user_id"], + "existing_impl": "src/models/thing.rs (partial, missing field X)", + "notes": "" + } + ], + "enums": [ + { + "name": "ThingStatus", + "variants": ["Active", "Inactive", "Archived"], + "spec_file": "docs/spec/sections/things.md", + "existing_impl": "src/models/enums.rs (exists, correct)" + } + ], + "validation_rules": [ + { + "entity": "Thing", + "rule": "name must be unique within a workspace", + "spec_file": "docs/spec/sections/things.md" + } + ], + "business_logic": [ + { + "description": "When a Thing is archived, cascade soft-delete to child Widgets", + "spec_file": "docs/spec/sections/things.md", + "affected_entities": ["Thing", "Widget"] + } + ], + "cross_cutting": [ + { + "concern": "rate_limiting", + "details": "POST /things limited to 100/min per user", + "spec_file": "docs/spec/sections/things.md" + } + ], + "existing_code_notes": [ + "src/models/thing.rs exists but is missing the 'archived_at' field", + "src/handlers/things.rs has GET implemented but not POST/PUT/DELETE", + "Error types in src/errors.rs need new variants for Thing-specific errors" + ], + "gaps": [ + "Spec mentions WebSocket events for Thing updates but no handler exists", + "Migration for adding 'archived_at' column needed" + ] +} + +## Rules +- Be EXHAUSTIVE. Every endpoint, every field, every error case, every validation rule. +- Note what ALREADY EXISTS in the codebase and what is MISSING or INCOMPLETE. +- If the spec is ambiguous, note the ambiguity in `notes` — do not guess. +- Do NOT implement anything. Your only output is the inventory JSON file. +- When done, report: the path to your inventory file, a count of endpoints/models/enums + found, and a brief summary. This is your final output — the orchestrator reads it + from the Task result. +``` + +### 1.2 OpenAPI-Specific Discovery + +If an OpenAPI spec exists, spawn a dedicated `Task` subagent (`subagent_type: "general-purpose"`) for it (often too large and structurally different to bundle with prose spec files): + +``` +You are an **OpenAPI analyst**. Read the OpenAPI spec completely and produce +a structured inventory at `/tmp/discovery/openapi.json`. + +Extract: +- Every path + method combination with full request/response schemas +- All schema definitions from components/schemas +- All security schemes +- All error response schemas +- Any x-* extensions with behavioral meaning +- Parameter patterns (pagination, filtering, sorting query params) + +Use the same JSON structure as other discovery agents but also add: +{ + "openapi_schemas": [...], + "security_schemes": [...], + "common_parameters": [...] +} + +When done, report: the path to your inventory file, total paths/schemas found, +and a brief summary. +``` + +### 1.3 Schema-Specific Discovery + +If there are standalone JSON schemas, spawn a `Task` subagent (`subagent_type: "general-purpose"`): + +``` +You are a **schema analyst**. Read the JSON schema completely. +Produce inventory at `/tmp/discovery/schema.json`. + +Extract every type definition, property, constraint, $ref resolution, enum, +required field, and validation pattern. Map each to the Rust type it should become. + +When done, report: the path to your inventory file, total types found, and a brief summary. +``` + +### 1.4 Collect & Validate Discovery + +After all discovery `Task` subagents return their results, use `Glob` pattern `/tmp/discovery/*.json` to verify all inventory files exist. Read only the inventory JSON files — do NOT re-read the original spec files. + +### 1.5 User Checkpoint + +Present a summary of discovery results (endpoint count, model count, gaps). + +- **Interactive mode** (`AUTO_MODE=false`): Use `AskUserQuestion` to ask if discovery looks complete or if additional areas need investigation. Do NOT proceed to Phase 2 until the user confirms. +- **Autonomous mode** (`AUTO_MODE=true`): Log the summary to `/tmp/orchestrator-decisions.md` with the heading `## Phase 1: Discovery Results — Auto-Accepted`. Proceed immediately to Phase 2. + +--- + +## Phase 2: Synthesis — Build the Master Task Plan + +With all inventories loaded, synthesize the complete task plan. +**This phase is planning only — do NOT call `TaskCreate` yet.** + +### 2.1 Merge Inventories + +Combine all discovery outputs into a unified picture: + +- **Deduplicate**: Same model referenced in multiple partitions → merge into one entry +- **Resolve cross-references**: Endpoint X references Model Y from a different partition +- **Identify gaps**: Any spec area not covered by discovery? If so, spawn a follow-up discovery subagent for just that area. +- **Catalog existing code**: What's done, what's partial, what's missing entirely? + +### 2.2 Design Task Breakdown + +Decompose into tasks following this phase structure. Adapt phases as needed, but maintain the dependency ordering: + +#### Phase A: Foundation +- Project structure / directory scaffolding (if needed) +- Shared error types and error response formatting +- Shared types: enums, common structs, newtypes +- Configuration / environment +- Database migrations for all new/modified tables + +#### Phase B: Core Models +- One task per model (struct definition, Display/Debug, serde, builder if applicable) +- Validation logic per model +- Model tests + +#### Phase C: Data Layer +- Repository traits per domain area +- Database query implementations (one task per entity's CRUD) +- Query tests with test fixtures + +#### Phase D: API Handlers +- One task per endpoint (or tightly coupled endpoint group like CRUD for one entity) +- Request parsing, response formatting +- Handler-level error mapping + +#### Phase E: Business Logic / Services +- Service layer for complex operations +- Cross-entity workflows +- Event/notification triggers + +#### Phase F: Auth & Middleware +- Authentication middleware +- Authorization / permission checks per endpoint +- Rate limiting +- CORS, logging, request ID propagation + +#### Phase G: Integration Tests +- One task per endpoint or endpoint group +- Happy path + every error case from the spec +- Edge cases identified during discovery + +#### Phase H: Polish +- Clippy clean, fmt, doc comments +- Final `just check` pass +- Missing test coverage + +### 2.3 Task Format + +Plan each task with this structure: + +``` +subject: "Implement Thing model with validation" +description: | + ## What + Implement the `Thing` struct and its validation logic per the spec. + + ## Spec Reference + - docs/spec/sections/things.md (Thing model section) + - OpenAPI: #/components/schemas/Thing + + ## Fields + - id: Uuid (auto-generated) + - name: String (1-255 chars, unique per workspace) + - status: ThingStatus enum + - created_at: DateTime + - updated_at: DateTime + - archived_at: Option> + + ## Acceptance Criteria + - [ ] Struct defined with all fields + - [ ] serde Serialize/Deserialize derived + - [ ] Builder pattern per CLAUDE.md conventions + - [ ] Validation: name length, uniqueness constraint annotation + - [ ] Unit tests for builder and validation + - [ ] File: src/models/thing.rs + + ## Existing Code + - src/models/thing.rs exists but missing archived_at field — extend it + + ## Convention Reminders + - Use thiserror for error types + - Follow builder pattern from CLAUDE.md + - Run `cargo clippy` and `cargo fmt` before completing +activeForm: "Implementing Thing model" +blockedBy: [Phase A task IDs] +``` + +**Critical**: Include enough context in each task description that the implementing teammate does NOT need to read the full spec — only the specific files referenced. + +### 2.4 Write the Task Manifest + +Use `Write` to save the full plan to `/tmp/task-manifest.md` as an audit trail for spec coverage. + +Structure: + +```markdown +# Task Manifest + +## Spec Coverage Audit +| Spec Section | Endpoints Covered | Models Covered | Tasks | +|---|---|---|---| +| things.md | POST/GET/PUT/DELETE /things | Thing, ThingStatus | T-B01, T-C01, T-D01-04 | +| ... | ... | ... | ... | + +## Uncovered Items +(anything from discovery inventories not yet assigned to a task — should be empty) + +## Task List +### Phase A: Foundation +- T-A01: ... (blocked by: none) +- T-A02: ... (blocked by: none) +### Phase B: Core Models +- T-B01: ... (blocked by: T-A01) +... +``` + +### 2.5 User Checkpoint — Plan Approval + +Present the task breakdown with dependency graph and spec coverage audit. + +- **Interactive mode** (`AUTO_MODE=false`): Use `AskUserQuestion` to ask the user to approve the plan before any code is written. Do NOT proceed to Phase 3 until the user explicitly approves. +- **Autonomous mode** (`AUTO_MODE=true`): Log the full task manifest to `/tmp/orchestrator-decisions.md` with the heading `## Phase 2: Task Plan — Auto-Accepted`. Proceed immediately to Phase 3. + +--- + +## Phase 3: Execution + +### 3.1 Create Team + +**MANDATORY FIRST STEP**: Create the team BEFORE creating any tasks. Tasks created without a team context land in the wrong task list and teammates cannot see them. + +``` +TeamCreate: + team_name: "spec-impl" + description: "Specification implementation team" +``` + +### 3.2 Create ALL Tasks + +**After the team exists**, create every task from the manifest using `TaskCreate`. Tasks are now automatically associated with the team's task list. + +1. Call `TaskCreate` for every task in the manifest (all phases A through H). Each task MUST have `subject`, `description`, and `activeForm`. +2. Call `TaskUpdate` with `addBlockedBy` to set ALL dependency relationships (e.g., all Phase B tasks blocked by relevant Phase A tasks). +3. Call `TaskList` to verify all tasks exist with correct dependencies. + +**Do NOT proceed to 3.3 until every task is registered and all dependencies are set.** + +### 3.3 Spawn Teammates + +Spawn teammates in PARALLEL (single response turn). + +Determine how many parallel teammates you need for the current wave. Spawn them ALL in one response using multiple `Task` calls simultaneously. + +**CRITICAL requirements for teammate spawning:** + +1. Every teammate MUST be spawned with `run_in_background: true`. Without this, the orchestrator blocks on each Task call until that teammate finishes ALL its work — defeating parallelism entirely. + +2. Teammate agent types MUST have team coordination tools (`SendMessage`, `TaskList`, `TaskGet`, `TaskCreate`, `TaskUpdate`) in their tool list. The `rust-developer` agent includes these. If using a custom agent, verify its tools first. + +``` +Task: + subagent_type: "rust-developer" + team_name: "spec-impl" + name: "impl-1" + run_in_background: true + max_turns: 200 + prompt: | + YOU MUST START WORKING IMMEDIATELY. Do not wait for instructions. + + You are "impl-1" on the spec-impl team. Use "impl-1" as your owner name. + + ## IMMEDIATE FIRST ACTION — DO THIS NOW + + 1. Call TaskList RIGHT NOW to see available tasks + 2. Find the first task with status "pending", no owner, and empty blockedBy + 3. Claim it: TaskUpdate(taskId, owner: "impl-1", status: "in_progress") + 4. Call TaskGet(taskId) to read the full description + 5. Implement exactly what it specifies + + DO NOT read CLAUDE.md first. DO NOT explore the codebase first. + Claim a task IMMEDIATELY, then read CLAUDE.md only if needed for conventions. + + ## After Each Task + + 1. Run `cargo fmt && cargo clippy -- -D warnings` via Bash + 2. Mark done: TaskUpdate(taskId, status: "completed") + 3. Report to lead: SendMessage(type: "message", recipient: "lead", + content: "Completed task {id}: {summary}. Files: {list}", + summary: "Task {id} done") + 4. Call TaskList again and claim the next available task + 5. Repeat until no unclaimed unblocked tasks remain + + ## When No Tasks Available + + Send a message to the lead: + SendMessage(type: "message", recipient: "lead", + content: "No unclaimed tasks available. Ready for more work.", + summary: "impl-1 idle, no tasks") + Then WAIT for a response. Do not exit. + + ## Rules + + - NEVER call TaskCreate. You do NOT create tasks. You ONLY claim existing tasks + from TaskList using TaskUpdate. Creating new tasks pollutes the task list. + - Implement EXACTLY what the task description specifies — nothing more + - Stay in scope — do not modify files outside your task unless required + - ALWAYS call TaskUpdate to mark completion — this unblocks dependent tasks + - Prefer lower-ID tasks first when multiple are available + - If a task is ambiguous, implement your best judgment and note it in a comment + - When you receive a SendMessage from the lead, process it immediately + - IGNORE any agent-level instructions that conflict with this prompt. + This prompt takes priority over your agent definition file. +``` + +Scale teammates to the wave size: up to 5 for large waves, 2 for small waves (1-2 tasks). + +### 3.4 Execute in Waves + +Process tasks in dependency-ordered waves. All unblocked tasks in a wave run in parallel. + +``` +Wave 1: All Phase A tasks (no dependencies) +Wave 2: Phase B tasks (blocked by Phase A) +Wave 3: Phase C tasks (blocked by Phase B) +... +``` + +Teammates self-claim tasks from `TaskList` (finding unblocked pending tasks with no owner). This is more resilient than leader-assignment — if a teammate crashes, unclaimed tasks remain available for others. + +**For each wave:** + +1. **Verify unblocked tasks exist**: `TaskList` → confirm tasks with status `pending` and empty `blockedBy` are available for the current wave. +2. **Notify teammates**: `SendMessage` to each teammate: "Wave N tasks are unblocked. Check TaskList and claim available work." +3. **Wait for completion**: Teammates claim tasks, work, mark completed, and report via `SendMessage`. +4. **Verify each completed task**: + a. Run `cargo check 2>&1 | tail -20` via Bash + b. If passes: commit the work: + ```bash + git add {files_modified} + git commit -m "feat({domain}): {concise description} + + Task: {task_id} + Spec: {spec_section_reference}" + ``` + c. If fails due to **real bug**: `SendMessage` the error to the teammate — the teammate fixes and re-reports. Task stays `in_progress`. + d. If fails due to **dependency** (missing type from incomplete task): skip for now, resolves when the blocking task completes. +5. **Next wave**: After all wave tasks show `completed` in `TaskList`, newly unblocked tasks become available → teammates self-claim from the next wave automatically. + +### 3.5 Integration Checkpoints + +After each phase completes, run `just check`. Fix any issues via teammate fix tasks before proceeding to the next phase. + +--- + +## Phase 4: Final Verification + +After all execution tasks complete (confirm via `TaskList` — all tasks show `completed`): + +### 4.1 Full Test Suite + +```bash +cargo test --all 2>&1 +``` + +### 4.2 Spec Coverage Audit + +Spawn a **verification** `Task` subagent (`subagent_type: "general-purpose"`, no `team_name` — fire-and-done audit): + +``` +You are an **audit analyst**. Verify the implementation fully covers the specification. + +Read these via `Read` (use `Glob` to enumerate files first): +- /tmp/task-manifest.md (the task plan) +- /tmp/discovery/*.json (the spec inventories) +- Source files under the project's source root (check CLAUDE.md — may be `crates/`, not `src/`) + +For every endpoint: verify handler exists, tests exist, error cases are handled. +For every model: verify struct has all fields and validation logic exists. + +Produce a coverage report at /tmp/audit-report.md (covered, missing, partial items +with file references). Report the summary as your final output. +``` + +### 4.3 Address Gaps + +If the audit reveals gaps, create new tasks via `TaskCreate`. Teammates will self-claim from `TaskList` when notified via `SendMessage`. + +### 4.4 Final Commit + +```bash +git add {files_modified} +git commit -m "feat: complete specification implementation + +Implements all endpoints, models, validation, and tests per spec. +See /tmp/task-manifest.md for full task breakdown." +``` + +--- + +## Phase 5: Cleanup + +### 5.1 Shutdown Teammates + +Send `shutdown_request` to each teammate: + +``` +SendMessage: + type: "shutdown_request" + recipient: "impl-1" + content: "All tasks complete. Shutting down." +``` + +Repeat for each teammate (impl-2, impl-3, etc.). + +### 5.2 Wait for Shutdown Confirmations + +Wait for all teammates to confirm shutdown. + +### 5.3 Delete Team + +Call `TeamDelete` to clean up team and task resources. + +### 5.4 Report Final Summary + +Present to the user: +- Total tasks completed +- Files created/modified +- Test results +- Any unresolved issues or ambiguities logged in `/tmp/issues/` + +--- + +## Orchestrator Rules + +1. **Never read raw spec files yourself** — delegate to discovery subagents. +2. **Never write code yourself** — delegate to implementation teammates. +3. **Structured data over prose** — discovery produces JSON, not summaries. +4. **Fail fast, fix fast** — resolve issues before moving to dependent tasks. +5. **Commit after every task** — atomic commits enable rollback and show progress. +6. **Audit relentlessly** — trust but verify; the final phase catches what earlier phases miss. +7. **Parallelize within waves, serialize across waves** — spawn teammates with `run_in_background: true` in a single response turn for actual parallelism. +8. **Context budget** — give each subagent or teammate only CLAUDE.md, the relevant spec files, the relevant source files, and a self-contained task description. +9. **Task lifecycle is MANDATORY** — `TaskCreate` → teammate claims via `TaskUpdate(owner + in_progress)` → work → verify → `TaskUpdate(completed)`. Never skip status updates; they unblock dependent tasks. +10. **Team before tasks, tasks before teammates** — Phase 3.1 (TeamCreate) → 3.2 (TaskCreate) → 3.3 (spawn teammates). Tasks created without a team land in the wrong list. No exceptions. +11. **Teammate agent types MUST include team coordination tools** — Any agent used as a teammate needs `SendMessage`, `TaskList`, `TaskGet`, `TaskCreate`, `TaskUpdate` in its tool list. The `rust-developer` agent includes these. If using a custom agent, verify its tools first. Teammates are spawned via `Task` with `team_name`, `name`, and `run_in_background: true`. +12. **Teammates self-claim tasks** — Teammates find unblocked unclaimed tasks via `TaskList` and claim them with `TaskUpdate(owner)`. This is more resilient than leader-assignment. +13. **Clean shutdown** — Always send `shutdown_request` to all teammates and call `TeamDelete` when done. +14. **User checkpoints are mandatory in interactive mode** — `AskUserQuestion` gates between discovery→synthesis and synthesis→execution. In `--auto` mode, checkpoints are logged to `/tmp/orchestrator-decisions.md` and auto-accepted. The user can review decisions after completion. + +--- + +## Troubleshooting + +**Context overflow in discovery** — Use `Grep` to find section boundaries (`'^##'` for Markdown, `'paths:'` for OpenAPI), split the file across multiple `Task` subagents, then merge their partial inventories. + +**Teammate failure** — Reassign with narrower scope via `SendMessage`. For implementation failures, dispatch a fix task to another teammate with the error message, affected files, and original task description. Update task status via `TaskUpdate` to reflect retries. + +**`cargo check` failure after a task** — If caused by an incomplete dependency, note it on the blocked task via `TaskUpdate` and continue with other unblocked work. If it is a real error in the just-completed task, dispatch a fix immediately; do not mark the task `completed` until the fix lands. + +**Teammate goes idle immediately after spawn** — The teammate prompt may not be directive enough. The prompt MUST start with an imperative action ("Call TaskList RIGHT NOW") not a description of the workflow. Teammates that receive descriptive prompts ("Your workflow is...") may wait for further instructions instead of acting. Also ensure `max_turns` is set high enough (200+) so teammates don't exhaust their turn budget mid-task. + +**Teammate goes idle between tasks** — This is normal. Teammates go idle between turns. Send them a new `SendMessage` to wake them up with new work. Do NOT treat idle as an error or spawn a replacement. + +**Discovery subagent can't SendMessage** — This is by design. Fire-and-done `Task` subagents (no `team_name`) communicate via their Task return value, not `SendMessage`. Only team-member teammates (spawned with `team_name`) can use `SendMessage`. + +**Teammates not responding / not claiming tasks** — Three possible causes: +1. **Missing tools**: Verify the agent type's tool list includes `SendMessage`, `TaskList`, `TaskUpdate`, `TaskGet`, `TaskCreate`. Check `.claude/agents/*.md` and add missing tools. +2. **Tasks in wrong namespace**: Tasks created before `TeamCreate` land in the default task list, not the team's. Always create the team FIRST. +3. **Passive prompt**: The teammate prompt must command immediate action, not describe a workflow. Start with "Call TaskList RIGHT NOW" not "Your workflow is to check TaskList." + +**No parallelism despite multiple teammates** — Verify every teammate `Task` call includes `run_in_background: true`. Without it, the orchestrator blocks on each spawn until that teammate finishes, making execution sequential. From b3d69ac1f8174e7df98a8e28b7ad8b07d530ca55 Mon Sep 17 00:00:00 2001 From: Robert Allen Date: Sun, 22 Feb 2026 16:28:33 -0500 Subject: [PATCH 2/4] fix(ci): use workflow_run trigger for homebrew packaging The package-homebrew workflow was triggered by release:published, which fires before build-binaries finishes uploading assets. This caused all SHA-256 checksums to be computed from 404 error pages, resulting in identical (wrong) hashes in the formula. Switch to workflow_run trigger so the homebrew job waits for the entire Release workflow to complete. Add a guard that verifies binary SHAs are unique before proceeding. --- .github/workflows/package-homebrew.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/package-homebrew.yml b/.github/workflows/package-homebrew.yml index 37a0918..f77342f 100644 --- a/.github/workflows/package-homebrew.yml +++ b/.github/workflows/package-homebrew.yml @@ -2,8 +2,9 @@ name: Homebrew Package "on": - release: - types: [published] + workflow_run: + workflows: ["Release"] + types: [completed] workflow_dispatch: inputs: version: @@ -22,6 +23,9 @@ jobs: name: Update Homebrew Formulas runs-on: macos-latest environment: copilot + if: >- + github.event_name == 'workflow_dispatch' || + github.event.workflow_run.conclusion == 'success' steps: - name: Checkout homebrew tap @@ -36,13 +40,13 @@ jobs: id: release env: EVENT_NAME: ${{ github.event_name }} - RELEASE_TAG: ${{ github.event.release.tag_name }} + # workflow_run: tag is on head_branch + RUN_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} INPUT_VERSION: ${{ github.event.inputs.version }} REPO: ${{ github.repository }} run: | - if [ "$EVENT_NAME" = "release" ]; then - VERSION="$RELEASE_TAG" - VERSION="${VERSION#v}" + if [ "$EVENT_NAME" = "workflow_run" ]; then + VERSION="${RUN_HEAD_BRANCH#v}" else VERSION="$INPUT_VERSION" fi @@ -77,6 +81,15 @@ jobs: SRC_SHA=$(curl -sL "$SRC_URL" \ | shasum -a 256 | awk '{print $1}') + # Verify all SHAs are unique (identical = failed downloads) + SHAS="$ARM64_SHA $AMD64_SHA $LINUX_SHA" + UNIQUE=$(echo "$SHAS" | tr ' ' '\n' | sort -u | wc -l) + if [ "$UNIQUE" -lt 3 ]; then + echo "::error::SHA mismatch: binary SHAs are not unique." + echo " Assets may not have been uploaded yet." + exit 1 + fi + for key in arm64 amd64 linux comp man src; do eval "echo \"${key}_url=\$$(echo ${key} \ | tr '[:lower:]' '[:upper:]')_URL\"" \ From 427a2e15c3840284229db77f4a084f857c861b6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:03:44 +0000 Subject: [PATCH 3/4] Initial plan From 0ac9be83e4617833bc48ce429263ed8d480f2e4a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:07:10 +0000 Subject: [PATCH 4/4] fix(ci): apply review feedback to package-homebrew.yml - Add semver validation for workflow_run (tag ref check) and workflow_dispatch (input format check) version extraction - Expand SHA uniqueness guard from 3 binary assets to all 6 assets (ARM64, AMD64, Linux, completions, man pages, source tarball) - Replace wc -l with grep -c . for robust unique-SHA counting Co-authored-by: zircote <307960+zircote@users.noreply.github.com> --- .github/workflows/package-homebrew.yml | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/package-homebrew.yml b/.github/workflows/package-homebrew.yml index f77342f..20049fb 100644 --- a/.github/workflows/package-homebrew.yml +++ b/.github/workflows/package-homebrew.yml @@ -46,9 +46,21 @@ jobs: REPO: ${{ github.repository }} run: | if [ "$EVENT_NAME" = "workflow_run" ]; then - VERSION="${RUN_HEAD_BRANCH#v}" + # Expect RUN_HEAD_BRANCH to be a tag like "v1.2.3" + if printf '%s\n' "$RUN_HEAD_BRANCH" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+([0-9A-Za-z.+-]*)?$'; then + VERSION="${RUN_HEAD_BRANCH#v}" + else + echo "Error: workflow_run triggered from non-tag ref '$RUN_HEAD_BRANCH'. Expected a tag like 'v1.2.3'." >&2 + exit 1 + fi else - VERSION="$INPUT_VERSION" + # Normalize INPUT_VERSION by stripping optional leading "v" + RAW_VERSION="${INPUT_VERSION#v}" + if ! printf '%s\n' "$RAW_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([0-9A-Za-z.+-]*)?$'; then + echo "Error: Provided version '$INPUT_VERSION' is not a valid semantic version (e.g., 1.2.3)." >&2 + exit 1 + fi + VERSION="$RAW_VERSION" fi echo "version=$VERSION" >> "$GITHUB_OUTPUT" @@ -81,11 +93,11 @@ jobs: SRC_SHA=$(curl -sL "$SRC_URL" \ | shasum -a 256 | awk '{print $1}') - # Verify all SHAs are unique (identical = failed downloads) - SHAS="$ARM64_SHA $AMD64_SHA $LINUX_SHA" - UNIQUE=$(echo "$SHAS" | tr ' ' '\n' | sort -u | wc -l) - if [ "$UNIQUE" -lt 3 ]; then - echo "::error::SHA mismatch: binary SHAs are not unique." + # Verify all asset SHAs are unique (identical = failed downloads) + SHAS="$ARM64_SHA $AMD64_SHA $LINUX_SHA $COMP_SHA $MAN_SHA $SRC_SHA" + UNIQUE=$(echo "$SHAS" | tr ' ' '\n' | sort -u | grep -c .) + if [ "$UNIQUE" -lt 6 ]; then + echo "::error::SHA mismatch: asset SHAs are not unique." echo " Assets may not have been uploaded yet." exit 1 fi