Observe & control
Steering a Run
Send additional instructions to the active native task.
On this page
Add instructions to the active task
Steering enters the current native task at its next injection boundary, keeping
its Run, model, usage and checkpoint. Codex uses app-server turn/steer guarded
by the active turn ID; Pi uses native RPC steer. Claude Code uses persistent
streaming input with transcript-only admission; Kimi Code and ZCode use their
native SDKs with active-turn fencing. All five require matching coding-agent
template images. Native harnesses determine tool preemption and delivery timing.
The API returns a durable queued message receipt. Native accepted confirms
admission rather than model obedience; unconfirmed means dispatch may have
occurred without a surviving acknowledgment. Read ordered receipts or follow
run.message.* events. Reuse the same idempotency key and exact text after an
ambiguous transport failure. Pending messages never transfer to another Run.
The authored contract and generated endpoint reference own paths and limits.
Queued, stopping and terminal Runs reject new messages. A task may finish
before the Platform state updates, in which case the native bridge rejects the
late message. Existing Runs retain their original execution mode. Only Runs
with steeringEnabled: true accept steering.
Append instructions to the current running Run
/v1/environments/{environmentId}/sessions/{sessionId}/runs/{runId}/steerRequires Idempotency-Key, a running Run, and steeringEnabled=true. Native steering enters the same execution without starting another Run. Returns a durable queued receipt; accepted means the harness acknowledged admission, not that the model has acted on it. Terminal, stopping, and unsupported Runs return 409. At most 100 messages per Run, each up to 32768 UTF-8 bytes.
Authentication: Platform API bearer token
Parameters and headers
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: environmentId | string · min length 1 | Yes | Environment identifier. It must belong to the caller’s account or Project. |
path: sessionId | string · min length 1 | Yes | Existing Session identifier within the named Environment. |
path: runId | string · min length 1 | Yes | Run identifier within the named Environment and, where applicable, Session. |
header: idempotency-key | string · min length 1; max length 128 | Yes | Stable key for one logical operation. Retry with the same key and exact request body; a new key can admit new work. |
Request example
curl -X POST \
"https://api.sandpi.ai/v1/environments/$ENVIRONMENT_ID/sessions/$SESSION_ID/runs/$RUN_ID/steer" \
-H "Authorization: Bearer $SANDPI_API_TOKEN" \
-H "idempotency-key: $REQUEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "example"
}'Request body · required application/json
Additional text for the currently running native task.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
input | string · min length 1; max length 32768Validation pattern\S | Yes | Instructions supplied to the agent for this task. |
Example
{
"input": "example"
}Responses
202 Accepted.Response body application/json
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | Steering instruction and durable harness-admission receipt. |
data.id | string | Yeswithin data | Resource identifier used to read or manage this resource. |
data.runId | string | Yeswithin data | Run identifier within the named Environment and, where applicable, Session. |
data.sequence | integer · ≥ -9007199254740991; ≤ 9007199254740991 | Yeswithin data | Message order within the Run. |
data.input | string | Yeswithin data | Instructions supplied to the agent for this task. |
data.status | string · values: "queued" | "accepted" | "rejected" | "unconfirmed" | Yeswithin data | Steering receipt state. Accepted confirms harness admission; unconfirmed may have been dispatched without a surviving acknowledgment. |
data.errorCode | string | Nowithin data | Stable diagnostic code when execution or cleanup reports a failure. |
data.nativeTurnId | string | Nowithin data | Native task identity used to fence steering to the intended active turn. |
data.createdAt | string · format: date-timeValidation pattern^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$ | Yeswithin data | Creation time as a UTC date-time string. |
data.updatedAt | string · format: date-timeValidation pattern^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$ | Yeswithin data | Last update time as a UTC date-time string. |
Example
{
"data": {
"id": "",
"runId": "",
"sequence": -9007199254740991,
"input": "",
"status": "queued",
"createdAt": "2026-10-12T01:00:00Z",
"updatedAt": "2026-10-12T01:00:00Z"
}
}Error responses
default Sandpi error.Error body application/json
Standard error envelope containing a stable code, diagnostic message and request identity.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
Example
{
"error": {
"code": "platform_balance_insufficient",
"message": "Top up Platform credits before submitting a Run.",
"requestId": "req_example"
}
}Track delivery
Follow the message receipt, not just the HTTP response. queued means the API persisted it; accepted means the harness admitted it; rejected means it did not enter the task; unconfirmed means dispatch may have happened without a surviving acknowledgment. The native harness decides when to consume it.
List steering messages and their receipts in order
/v1/environments/{environmentId}/sessions/{sessionId}/runs/{runId}/messagesAuthentication: Platform API bearer token
Parameters and headers
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: environmentId | string · min length 1 | Yes | Environment identifier. It must belong to the caller’s account or Project. |
path: sessionId | string · min length 1 | Yes | Existing Session identifier within the named Environment. |
path: runId | string · min length 1 | Yes | Run identifier within the named Environment and, where applicable, Session. |
Request example
curl \
"https://api.sandpi.ai/v1/environments/$ENVIRONMENT_ID/sessions/$SESSION_ID/runs/$RUN_ID/messages" \
-H "Authorization: Bearer $SANDPI_API_TOKEN"No request body.
Responses
200 Successful response.Response body application/json
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | array | Yes | Successful result wrapped by the API. The child fields describe its content. |
data[] | object · extra fields rejected | Yeseach array item | Steering instruction and durable harness-admission receipt. |
data[].id | string | Yeseach array item | Resource identifier used to read or manage this resource. |
data[].runId | string | Yeseach array item | Run identifier within the named Environment and, where applicable, Session. |
data[].sequence | integer · ≥ -9007199254740991; ≤ 9007199254740991 | Yeseach array item | Message order within the Run. |
data[].input | string | Yeseach array item | Instructions supplied to the agent for this task. |
data[].status | string · values: "queued" | "accepted" | "rejected" | "unconfirmed" | Yeseach array item | Steering receipt state. Accepted confirms harness admission; unconfirmed may have been dispatched without a surviving acknowledgment. |
data[].errorCode | string | Noeach array item | Stable diagnostic code when execution or cleanup reports a failure. |
data[].nativeTurnId | string | Noeach array item | Native task identity used to fence steering to the intended active turn. |
data[].createdAt | string · format: date-timeValidation pattern^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$ | Yeseach array item | Creation time as a UTC date-time string. |
data[].updatedAt | string · format: date-timeValidation pattern^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$ | Yeseach array item | Last update time as a UTC date-time string. |
Example
{
"data": [
{
"id": "",
"runId": "",
"sequence": -9007199254740991,
"input": "",
"status": "queued",
"createdAt": "2026-10-12T01:00:00Z",
"updatedAt": "2026-10-12T01:00:00Z"
}
]
}Error responses
default Sandpi error.Error body application/json
Standard error envelope containing a stable code, diagnostic message and request identity.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
Example
{
"error": {
"code": "platform_balance_insufficient",
"message": "Top up Platform credits before submitting a Run.",
"requestId": "req_example"
}
}Retry an ambiguous request
Keep the original idempotency key and text. A new key can admit the same instruction twice. If the Run has finished, start a new Run for further work; steering messages never transfer to that later Run. See events and errors and retries.