From epic
Manages multi-agent orchestration runs: reads agent inboxes, resolves dependencies, formats messages, handles handoffs. Provides a status dashboard and intervention controls (pause/cancel/redirect).
How this skill is triggered — by the user, by Claude, or both
Slash command
/epic:orchestrateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**CRITICAL**: Run `HARNESS_DIR=$(epic-harness path)` first. NEVER use `.harness/` in the project directory.
CRITICAL: Run HARNESS_DIR=$(epic-harness path) first. NEVER use .harness/ in the project directory.
Triggered automatically when an active multi-agent orchestration is detected.
HARNESS_DIR=$(epic-harness path)$HARNESS_DIR/orchestrator/run.json$HARNESS_DIR/orchestrator/agents/{my_id}/inbox.jsonl$HARNESS_DIR/orchestrator/control.jsongeneration in control.json to acknowledge$HARNESS_DIR/orchestrator/run.json dependency graphstatus.json — if any dependency is not DONE, waitWhile working on the assigned task:
orchestrate hook automatically appends events to stream.jsonl on each tool callWhen task is complete:
orchestrate hook will evaluate dependencies and notify downstream agentsRead-only view of the current orchestration run. Displayed when user runs /status or asks about orchestration state.
$HARNESS_DIR/orchestrator/run.json existsNo active orchestration. Run
/goor/orbitto start.
status is not "running", output:
Last orchestration ended with status: {status}. No active run.
status is "running", proceed to Step 2.Extract the agent list from run.json.agents. For each agent {id}:
$HARNESS_DIR/orchestrator/agents/{id}/status.json (mark unknown if missing)$HARNESS_DIR/orchestrator/agents/{id}/stream.jsonl (show "no events yet" if missing)started_at set, completed_at not set: elapsed = now - started_atcompleted_at - started_atXm Ys or Xh Ymrun.json.dependenciesOutput a formatted dashboard (keep total under 30 lines):
## Orchestration Dashboard
- **Run ID**: {run.id}
- **Status**: {run.status}
- **Elapsed**: {total_elapsed since run.started_at}
- **Agents**: {count where status=running} / {total} active
| Agent | Role | Status | Elapsed | Last Event |
|-------|------|--------|---------|------------|
| {id} | {role} | {status} | {elapsed} | {summary of last event} |
### Dependency Graph
{render with ASCII arrows, e.g.:}
builder ──→ reviewer ──→ integrator
builder ──→ tester
### Recent Events (last 5 across all agents)
- [{timestamp}] {agent_id}: {event_summary}
### User Interventions
{read control.json; show directives if any, else "none"}
Dependency graph rendering rules:
run.json.dependencies (format: {"agent_a": ["agent_b", "agent_c"]})──→ arrowsEvent summary formatting:
stream.jsonl with fields: timestamp, type, messagemessage to at most 60 charactersgit diff --stat
If changes exist, append:
### File Changes
- {count} files modified ({insertions} insertions, {deletions} deletions)
- Key changes: {list up to 5 file paths}
Note: This mode is read-only — never modify orchestration state.
Write control directives that the orchestrate hook reads on the next agent tool call. Triggered when user runs /intervene.
$HARNESS_DIR/orchestrator/run.jsonInvocation format:
intervene pause {agent_id} — pause a specific agent (blocks next tool call)intervene pause all — pause all agentsintervene cancel {agent_id} — cancel a specific agentintervene cancel all — cancel entire orchestrationintervene redirect {agent_id} {new_instruction} — change what an agent is doingintervene resume {agent_id} — resume a paused agentIf the user provides no arguments, ask which action and target they want.
Validate the agent_id against the agent list in run.json. If not found, output: "Agent '{agent_id}' not found in active orchestration. Available agents: {list}" and stop.
Read current generation from $HARNESS_DIR/orchestrator/control.json (or 0 if file doesn't exist). Increment by 1.
Write to $HARNESS_DIR/orchestrator/control.json:
{
"action": "pause|cancel|redirect|resume",
"target": "agent_id or 'all'",
"message": "optional user message",
"generation": <current_generation + 1>
}
For redirect, the message field contains the new instruction.
For pause/cancel, the message field is optional — use an empty string if none provided.
For resume, set action to "resume" and target to the agent_id.
Additional actions by type:
$HARNESS_DIR/orchestrator/run.json status to "aborted"$HARNESS_DIR/orchestrator/inbox/{agent_id}.jsonl as a new line: {"type": "redirect", "instruction": "{new_instruction}", "at": "{ISO-8601}"}Output confirmation:
Intervention recorded: {action} {target}
The {target} agent will respond on its next tool call.
Use /status to monitor.
Notes:
control.json before every agent tool call, so interventions take effect within one tool call cycleWhen agents need to communicate (via SendMessage or future inbox/outbox):
{
"from": "agent_id",
"to": "agent_id",
"type": "handoff|question|blocked|result",
"body": "message content",
"timestamp": "ISO-8601"
}
| Excuse | Rebuttal | What to do instead |
|---|---|---|
| "I'll just work independently" | Orchestration exists to prevent conflicts and duplication | Check dependencies first, report status |
| "Progress reporting slows me down" | The hook does it automatically on every tool call | No manual action needed |
| "I'll read all agents' state" | Only read your own inbox and dependencies | Respect isolation boundaries |
| "I'll intervene directly in agent files" | Direct file edits bypass the generation protocol | Always write to control.json |
| "I'll skip the status check" | Stale state leads to incorrect interventions | Always read run.json first |
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub epicsagas/epic-harness --plugin epic-harness