sandpi/ platform

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

POST /v1/environments/{environmentId}/sessions/{sessionId}/runs/{runId}/steer

Requires 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
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1YesEnvironment identifier. It must belong to the caller’s account or Project.
path: sessionIdstring · min length 1YesExisting Session identifier within the named Environment.
path: runIdstring · min length 1YesRun identifier within the named Environment and, where applicable, Session.
header: idempotency-keystring · min length 1; max length 128YesStable key for one logical operation. Retry with the same key and exact request body; a new key can admit new work.

Request example

sh
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.

FieldType and constraintsRequiredDescription
inputstring · min length 1; max length 32768
Validation pattern\S
YesInstructions supplied to the agent for this task.
Example
Example
{
  "input": "example"
}

Responses

202 Accepted.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesSteering instruction and durable harness-admission receipt.
data.idstringYeswithin dataResource identifier used to read or manage this resource.
data.runIdstringYeswithin dataRun identifier within the named Environment and, where applicable, Session.
data.sequenceinteger · ≥ -9007199254740991; ≤ 9007199254740991Yeswithin dataMessage order within the Run.
data.inputstringYeswithin dataInstructions supplied to the agent for this task.
data.statusstring · values: "queued" | "accepted" | "rejected" | "unconfirmed"Yeswithin dataSteering receipt state. Accepted confirms harness admission; unconfirmed may have been dispatched without a surviving acknowledgment.
data.errorCodestringNowithin dataStable diagnostic code when execution or cleanup reports a failure.
data.nativeTurnIdstringNowithin dataNative task identity used to fence steering to the intended active turn.
data.createdAtstring · format: date-time
Validation 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 dataCreation time as a UTC date-time string.
data.updatedAtstring · format: date-time
Validation 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 dataLast update time as a UTC date-time string.
Example
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.

FieldType and constraintsRequiredDescription
errorobject · extra fields rejectedYesStructured failure information. Inspect the stable code and retain the request ID for investigation.
error.codestringYeswithin errorStable error code used to distinguish failures programmatically.
error.messagestringYeswithin errorHuman-readable diagnostic text.
error.requestIdstringYeswithin errorRequest identifier for correlating diagnostics and support investigations.
error.detailsanyNowithin errorOptional structured error context. Its shape is specific to the service failure.
error.loginUrlstringNowithin errorAuthentication URL supplied when a browser login is required.
error.registrationOpenbooleanNowithin errorWhether new account registration is enabled for this deployment.
Example
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

GET /v1/environments/{environmentId}/sessions/{sessionId}/runs/{runId}/messages

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1YesEnvironment identifier. It must belong to the caller’s account or Project.
path: sessionIdstring · min length 1YesExisting Session identifier within the named Environment.
path: runIdstring · min length 1YesRun identifier within the named Environment and, where applicable, Session.

Request example

sh
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
FieldType and constraintsRequiredDescription
dataarrayYesSuccessful result wrapped by the API. The child fields describe its content.
data[]object · extra fields rejectedYeseach array itemSteering instruction and durable harness-admission receipt.
data[].idstringYeseach array itemResource identifier used to read or manage this resource.
data[].runIdstringYeseach array itemRun identifier within the named Environment and, where applicable, Session.
data[].sequenceinteger · ≥ -9007199254740991; ≤ 9007199254740991Yeseach array itemMessage order within the Run.
data[].inputstringYeseach array itemInstructions supplied to the agent for this task.
data[].statusstring · values: "queued" | "accepted" | "rejected" | "unconfirmed"Yeseach array itemSteering receipt state. Accepted confirms harness admission; unconfirmed may have been dispatched without a surviving acknowledgment.
data[].errorCodestringNoeach array itemStable diagnostic code when execution or cleanup reports a failure.
data[].nativeTurnIdstringNoeach array itemNative task identity used to fence steering to the intended active turn.
data[].createdAtstring · format: date-time
Validation 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 itemCreation time as a UTC date-time string.
data[].updatedAtstring · format: date-time
Validation 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 itemLast update time as a UTC date-time string.
Example
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.

FieldType and constraintsRequiredDescription
errorobject · extra fields rejectedYesStructured failure information. Inspect the stable code and retain the request ID for investigation.
error.codestringYeswithin errorStable error code used to distinguish failures programmatically.
error.messagestringYeswithin errorHuman-readable diagnostic text.
error.requestIdstringYeswithin errorRequest identifier for correlating diagnostics and support investigations.
error.detailsanyNowithin errorOptional structured error context. Its shape is specific to the service failure.
error.loginUrlstringNowithin errorAuthentication URL supplied when a browser login is required.
error.registrationOpenbooleanNowithin errorWhether new account registration is enabled for this deployment.
Example
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.