Sessions
Unified Harness Protocol, version 2026-09-12
A session is what makes a second task cheaper than the first: the conversation is still there, and so is the working directory. This chapter defines continuing a session, inspecting one, and stopping work in one.
1. Continuing a session
Send the next task with previous_response_id:
{
"input": "Now add tests for the function you just wrote.",
"previous_response_id": "resp_a1b2c3"
}
The server MUST:
- run the new task in the same session, with the same working directory and its files;
- give the harness the conversational context of the earlier tasks;
- use the same configured harness;
- report the same
metadata.session_id.
model MAY differ between tasks in a session. A server MUST honour a per-task model change, because
switching to a cheaper model for a follow-up is a common and legitimate pattern.
If previous_response_id names an unknown response, the server MUST fail with 404 and
code: "response_not_found". If the session it referred to has expired, 404 with
code: "session_expired" — a client can retry the first from scratch, and should not retry the
second.
Why chain on the response id rather than the session id? Because the response id is what the client already has: it comes back from the task it just ran. Chaining on it also names an exact point in the conversation, which leaves room for a server to branch from an earlier response later without changing the request shape.
2. Listing sessions
Conformance class Extended.
GET /v1/sessions?limit=20&cursor=&harness=chrn_…
{
"sessions": [
{
"id": "hsess7e78…",
"object": "session",
"harness_id": "chrn_…",
"title": "Summarise README.md",
"status": "completed",
"created_at": 1786400000,
"updated_at": 1786400240
}
],
"next_cursor": null
}
Pagination is cursor-based. A server MUST return next_cursor: null on the last page, and MUST NOT
require a client to detect the end by receiving fewer items than it asked for — that heuristic is
wrong whenever a page is exactly full.
3. Inspecting a session
GET /v1/sessions/{session_id}
GET /v1/sessions/{session_id}/turns
/turns returns the ordered task history of the session, so a client can rebuild a transcript it did
not store. Each turn identifies its response id, so a client can fetch the full response for any of
them.
Each item in turns MUST carry at least:
| Field | Type | Meaning |
|---|---|---|
id |
string | The response id of the turn, usable with GET /v1/responses/{id}. |
status |
string | The turn's status, in the response-status vocabulary of Tasks §1. |
and SHOULD carry, when the server has them: user (string, the user message), assistant (string,
the assistant's final text), tools (array, the tool calls of the turn), and files (array, the
files the turn produced). A server MAY add fields; a client MUST ignore fields it does not
understand. This was previously an object with no stated shape, which meant no conformance check
could assert anything past the status code, and every client that rebuilt a transcript did so
against one implementation's habits.
4. Cancelling
Two scopes, deliberately distinct:
POST /v1/responses/{response_id}/cancel # stop this task
POST /v1/sessions/{session_id}/cancel # stop whatever is running in this session
Semantics:
- Cancellation is a request, not a guarantee of immediacy. A server MUST stop the work as soon as it can and MUST reach a terminal state.
- A cancelled task MUST end with
status: "cancelled", neverfailed. - Output produced before cancellation MUST be retained.
- Cancelling an already-terminal task MUST succeed and change nothing. A client retrying a cancel after a dropped connection should not receive an error for having succeeded twice.
- Cancelling MUST NOT delete the session. The conversation remains continuable.
A server SHOULD respond to cancel within one second even if the harness takes longer to wind down. The client is usually a user interface, and a Stop button that does nothing visible for thirty seconds reads as broken.
5. Session sharing
Conformance class Full. A server MAY let a client publish a read-only view of a session.
POST /v1/sessions/{session_id}/share # publish (a body is OPTIONAL; no body means publish)
GET /v1/sessions/{session_id}/share # read the share back
DELETE /v1/sessions/{session_id}/share # revoke
If implemented, the share object returned by POST and GET MUST carry:
| Field | Type | Meaning |
|---|---|---|
id |
string | The share's identity. |
url |
string | Where the shared view is served. May be relative, in which case it resolves against the base URL the caller is already using — a server behind a proxy cannot know its public origin, and a base-relative path survives every fronting. |
object SHOULD be "session.share". A server MAY carry additional fields (the reference also
returns an enabled toggle and accepts {"enabled": bool} bodies); a client MUST ignore fields it
does not understand. A second POST MAY return the existing share or mint a new one, but
revocation MUST reach every link minted for the session — revoking only the newest tells an
operator the session is private while somebody still holds a working link.
The rules, unchanged:
- the shared view MUST be read-only — it MUST NOT permit continuing, cancelling, or uploading;
GETon the publishedurlMUST serve the view to a holder of the link with no other credential — a view only its creator can open has not been published to anyone;- after
DELETE, and after the session itself is deleted (§6), the publishedurlMUST stop resolving (404 or 410); - the share's id MUST NOT function as a credential for the rest of the API;
- the server MUST NOT expose provider credentials, tokens, or another principal's data through the view.
These were previously behaviors the conformance suite had to discover by probing (the endpoints and the object had no stated shape, so a portable check could only guess at paths and skip when the guesses missed). They are codified from the shapes the reference implementation demonstrates and the R-series measures; the suite now asserts them.
6. Deleting
DELETE /v1/sessions/{session_id}
Deletes the session and its stored history: the transcript, the trace, and the working folder the
session's tasks wrote. Afterwards the session MUST NOT count toward any storage or memory allowance
the server enforces, because deletion is how a client makes room. A server MUST answer 2xx, and a
later GET /v1/sessions/{session_id} MUST return 404.
DELETE /v1/traces/{session_id} is the older path for the same operation. It predates the session
vocabulary; a server MAY keep serving it (the reference implementation does, as the same handler),
but the path above is the one the protocol names and the one clients SHOULD use.
A server MUST cancel any in-flight task in the session first, and MUST make the session unreadable afterwards. Deletion is the one place where cancel and delete are legitimately coupled, because the alternative is a running task writing into storage that no longer has an owner.