Steer a Running Task
Add context to a running agent, request an interrupt, and understand degradation and delivery states
Task steering sends new instructions to work that has already started. Use it to correct an assumption, add missing context, or redirect an agent without cancelling the task and starting over.
Choose a delivery mode
| Mode | Meaning | Use when |
|---|---|---|
queue | Deliver the message at the next turn boundary. | The current turn can finish safely and you want to add context without discarding work. |
steer | Interrupt the current turn and deliver the message immediately. | Letting the current turn continue would be wrong or unsafe. |
Not every harness can interrupt. Task responses include supportedSteerModes, and the dashboard disables modes the assigned harness does not advertise.
| Provider | Supported modes | A steer request normally becomes |
|---|---|---|
| pi-mono | steer, queue | steered |
| Claude Managed | steer, queue | steered |
| opencode | queue | queued |
| Devin | queue | queued |
| Claude Code | queue | queued |
| Codex | queue | queued (delivered by Codex lifecycle hooks at the next tool-call boundary) |
Claude Code queue delivery additionally depends on a supported stock CLI invocation. See Harness Providers: Claude queue-steering gate. Codex delivery is harness-side: the worker image registers managed Codex hooks that inject queued messages into the running session; there is no mid-turn interrupt. See Harness Providers: Codex harness-side delivery.
Enable steering
Steering is disabled by default. Set STEERING_ENABLED=true (or 1) on the API server and worker containers to turn it on. While disabled, new steering requests are rejected across HTTP, MCP, scripts, and Slack; the dashboard hides its steering controls and the server does not register steer-task or accept-steer. Existing message history stays readable, and delivery callbacks plus terminal-status promotion remain enabled so messages already in flight can finish safely if the flag is turned off again.
The flag can also be set as a global swarm_config entry — global config rows are injected into the server environment at startup and on config reload.
Degradation and onUnsupported
The server uses a durable fallback ladder:
requested steer
-> deliver as steer when supported
-> otherwise queue at a turn boundary
-> otherwise create a follow-up taskonUnsupported controls whether the fallback is allowed:
degrade(default) preserves the message by moving down the ladder. Readoutcome,effectiveMode,degradedFrom, andpromotedTaskIdto learn what happened.failrejects an unsupported mode. HTTP callers receive422, MCP/script callers receive an error, and no steering-message row is created.
Choose fail when true interrupt semantics are required. For example, an instruction to stop a destructive operation should not silently wait until the operation finishes.
Tasks that haven't started yet (unassigned, offered, pending) also accept steering when the provider supports live delivery: the message queues as pending and the worker delivers it once the session is live. A steer request on a not-yet-started task degrades to queue — there is no turn to interrupt yet. If the task reaches a terminal state without ever starting, pending messages are promoted to follow-up tasks as usual.
Send steering
Dashboard
Open an in-progress task and use the steering composer. The mode selector follows supportedSteerModes, and the result reports whether the message interrupted, queued, or became a follow-up. The task page's Steering section refreshes the message lifecycle from the API.
MCP
steer-task is available on both the agent and user MCP surfaces:
{
"taskId": "00000000-0000-0000-0000-000000000000",
"message": "Stop changing the schema; keep the fix application-only.",
"mode": "steer",
"onUnsupported": "fail"
}Agents may steer tasks they created, and the lead may steer any task. User calls are limited to tasks allowed by task.steer.own.
After incorporating a delivered message, the assigned agent calls accept-steer:
{
"steeringMessageId": "00000000-0000-0000-0000-000000000000",
"note": "Kept the existing schema and moved validation into the service."
}Script SDK
Scripts use the same MCP handler through task_steer:
const result = await swarm.task_steer({
taskId,
message: "Use the cached result; do not repeat the external request.",
mode: "queue",
onUnsupported: "degrade",
});HTTP
curl -X POST "http://localhost:3013/api/tasks/$TASK_ID/steer" \
-H "Authorization: Bearer $AGENT_SWARM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Stop and verify the migration against an existing database.",
"mode": "steer",
"onUnsupported": "degrade"
}'Inspect the audit trail with GET /api/tasks/{id}/steering-messages. Worker delivery callbacks live under /api/steering-messages/{id}/{delivered,undeliverable,handled} and require the assigned worker's X-Agent-ID; normal clients should not call them.
Slack
Slack thread steering is opt-in:
SLACK_THREAD_STEERING=lead # or all
SLACK_THREAD_STEERING_MODE=queue # or steerlead targets the latest in-progress lead task in the thread. all targets the latest active task regardless of role. When the flag is unset, existing thread follow-up routing is unchanged. See Slack Integration.
Message lifecycle
Every accepted message has its own audit record:
pending -> delivered -> handled
|
+-> promoted
|
+-> cancelledpending: stored and waiting for the worker to deliver it.delivered: the provider accepted it.deliveredModerecords what the adapter actually used.handled: the agent acknowledged the message withaccept-steerafter incorporating it.promoted: live delivery was unavailable, the task stopped before delivery, or the provider rejected the message.promotedTaskIdlinks to the durable follow-up task.cancelled: pending delivery was cancelled before a provider accepted it.
If the parent task reaches a terminal state while messages are still pending, the server promotes each one exactly once rather than dropping it.
Adding a Harness Provider
Implement a harness provider — the adapter contract, reference implementations, live steering capabilities, and wiring checklist
Observability with OpenTelemetry
Send Agent Swarm traces and OTLP metrics to SigNoz or any compatible backend, filter local runs, and inspect API, worker, MCP, and tool execution telemetry.