Tasks
Unified Harness Protocol, version 2026-08-11
A task is one unit of work: input in, a result out. It is the endpoint most clients spend all their time in.
1. Run a task
POST /v1/responses
Authorization: Bearer <token>
Content-Type: application/json
{
"input": "Summarise README.md in three bullets.",
"model": "claude-sonnet-4.6",
"metadata": { "harness_id": "chrn_08dae611630d467ab3e67ed792570ae5" },
"stream": true
}
1.1 Request fields
| Field | Type | Required | Meaning |
|---|---|---|---|
input |
string | item[] | yes | The work. A bare string is shorthand for one user message. See §2. |
model |
string | no | Canonical model id. Omitted means the harness's default. |
metadata |
object | no | Client metadata. harness_id selects the configured harness. See §1.2. |
stream |
boolean | no | true streams Server-Sent Events; default false returns one JSON object. |
previous_response_id |
string | no | Continue the session that produced that response. See Sessions. |
instructions |
string | no | Additional system guidance for this task only. |
store |
boolean | no | Whether the server retains the response for later reads. Default true. |
max_output_tokens |
integer | no | Upper bound on generated tokens. |
max_step |
integer | no | Upper bound on agent steps (tool-call rounds) for this task. |
timeout_seconds |
integer | no | Wall-clock budget for this task. |
tools |
array | no | Additional tools offered for this task. |
include |
string[] | no | Optional extra content to include in the result. |
background |
boolean | no | Return as soon as the task is accepted; follow it with the events endpoint. |
A server MUST ignore request fields it does not understand rather than rejecting the request. A client MUST NOT rely on an unknown field having an effect.
max_step and timeout_seconds are budgets, not guarantees of precision: a server MUST stop the
task at or after the budget, MUST report incomplete, and MUST NOT report completed for work it
truncated.
1.2 Selecting the harness
The configured harness is selected by metadata.harness_id:
{ "metadata": { "harness_id": "chrn_…" } }
- If
harness_idis absent, the server MUST use a default harness and MUST report which one it used in the responsemetadata. - If
harness_idnames an unknown harness, or one outside the caller's scope, the server MUST fail with404andcode: "harness_not_found". - If both
previous_response_idandharness_idare present and disagree, the server MUST fail with409andcode: "harness_mismatch"(see Lifecycle §4).
Why is the harness in
metadatarather than a top-level field? Because the task surface is deliberately Responses-compatible (see the README), andmetadatais the extension point that surface already defines for caller-supplied context. A top-levelharnessfield would be a second, conflicting convention for the same idea, and every existing Responses SDK would have to be patched to send it.
1.3 Model selection and substitution
model names a canonical model id, not a provider-specific one. Canonical ids are stable across
providers, so the same request works whether the server reaches a model directly or through an
aggregator.
If the requested model cannot be served for the selected harness, a server MUST NOT fail silently and MUST NOT pretend it ran what was asked. It MUST do exactly one of:
- Fail with
422andcode: "model_unavailable"; or - Substitute the harness's authorized default, and record the substitution in the response:
{
"model": "gpt-5.4",
"metadata": {
"requested_model": "gpt-5.6-sol",
"model_fallback": true,
"model_fallback_reason": "model 'gpt-5.6-sol' is not available for this harness's backend"
}
}
A client can therefore always answer "did the model I asked for actually run?" by comparing model
with metadata.requested_model.
This rule exists because its absence is expensive. A server that substitutes silently makes every measurement downstream wrong — benchmarks, cost attribution, quality comparisons — and the client has no way to detect it. Reporting the substitution costs two fields.
2. Input
input is either a string or an array of items.
{ "input": "Summarise README.md" }
{
"input": [
{ "role": "user", "content": [
{ "type": "input_text", "text": "Summarise this report." },
{ "type": "input_file", "filename": "q3.pdf", "file_data": "data:application/pdf;base64,…" }
]}
]
}
| Item type | Purpose |
|---|---|
input_text |
Text |
input_file |
A file, inline as a data URL in file_data, or by file_id from a prior upload |
input_image |
An image, inline or by file_id |
A server at conformance class Core MUST accept input_text. A server at Extended MUST also
accept input_file and input_image. See Files.
3. The response object
{
"id": "resp_a1b2c3",
"object": "response",
"created_at": 1786400000,
"status": "completed",
"error": null,
"incomplete_details": null,
"previous_response_id": null,
"model": "claude-sonnet-4.6",
"output": [
{ "id": "rs_1", "type": "reasoning", "summary": [ { "type": "summary_text", "text": "…" } ], "status": "completed" },
{ "id": "fc_1", "type": "function_call", "call_id": "call_1", "name": "read_file",
"arguments": "{\"path\":\"README.md\"}", "status": "completed" },
{ "id": "fco_1", "type": "function_call_output", "call_id": "call_1", "output": "…", "status": "completed" },
{ "id": "msg_1", "type": "message", "role": "assistant", "status": "completed",
"content": [ { "type": "output_text", "text": "- …\n- …\n- …", "annotations": [] } ] }
],
"store": true,
"usage": { "input_tokens": 5120, "output_tokens": 240, "total_tokens": 5360 },
"metadata": { "session_id": "hsess7e78…" }
}
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | yes | resp_-prefixed |
object |
string | yes | Always response |
created_at |
integer | yes | Unix seconds |
status |
string | yes | See Lifecycle §3 |
error |
object | null | yes | Present and non-null only when status is failed |
output |
item[] | yes | Ordered; MAY be empty for a task that produced nothing |
model |
string | yes | The model that actually ran |
usage |
object | null | yes | null when the server cannot account for usage — never a fabricated zero |
metadata |
object | yes | MUST include session_id; see §1.3 for substitution fields |
previous_response_id |
string | null | yes | The response this one continues, if any |
store |
boolean | yes | Whether this response was retained |
3.1 Output items
type |
Meaning |
|---|---|
message |
Assistant text, in content[].text, with annotations for artifacts |
reasoning |
The agent's summarised thinking, in summary[].text |
function_call |
A tool the agent invoked, with arguments as a JSON string |
function_call_output |
The result of that tool call, matched by call_id |
A client MUST tolerate output item types it does not recognise, and MUST NOT assume any ordering
beyond the array order given. A client that renders only message items and ignores the rest is a
valid client.
4. Reading a task back
GET /v1/responses/{response_id}
Returns the same response object. A server that retained the response (store: true) MUST return it
after completion; a server MAY return 404 with code: "response_not_found" for a response created
with store: false.
GET /v1/responses/{response_id}/input_items
Returns the input the task was created with, for clients that need to reconstruct a transcript without having stored it themselves.
5. Cancelling
POST /v1/responses/{response_id}/cancel
See Sessions §4.
6. Idempotency
A client MAY send an idempotency key:
Idempotency-Key: <client-generated-unique-string>
A server that advertises idempotency MUST, for a repeated key:
- return the result of the first request, and
- not start a second execution.
If the first request is still running, the server MUST wait for it and return its result rather than returning a partial or a conflict. Agent tasks are expensive and side-effecting: a retry that runs the work twice is worse than a slow answer.
Idempotency keys SHOULD be retained for at least 24 hours.
7. Deleting
DELETE /v1/responses/{response_id}
Deletes the stored response. A server MUST NOT let this cancel a running task — cancellation and deletion are different intentions, and conflating them means a client cannot clean up history without stopping work.