Start one autonomous coding run against a repo in the caller's org
Runs a coding task on a repository: clones it into a sandbox, lets a model read and edit the code, run the tests, and push the work to a branch.
POST /v1/agents/coding
| Address | https://api.hanzo.ai/v1/agents/coding |
| Method | POST |
| Operation | post_agents_coding |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Runs a coding task on a repository: clones it into a sandbox, lets a model read and edit the code, run the tests, and push the work to a branch. Say the thing you want done — "fix the failing auth test in hanzoai/cloud" — and the run infers the repo, the branch and the plan. No prefix, no ceremony.
It answers 202 with the run's handle the moment the run is ADMITTED — not when it finishes. A coding run takes minutes; holding a request open for one would tie a connection to a model loop and give the caller nothing it cannot get better from the session stream.
The handle is a session id, and that is deliberate: the session is already the run's durable record and its live stream (/v1/agents/sessions/{id}/stream), so this door does not grow a progress endpoint, a status endpoint or a cancel endpoint of its own. One way to watch a run, whoever started it.
It is also how work CONTINUES. Pass an earlier run's session as after and
this one starts from where that one stopped, so "now add tests for it" builds
on the branch already pushed instead of a fresh clone. The follow-up still gets
its own branch and its own session — one run, one branch, always reviewable on
its own.
Request
12 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
after | body | string | — | After names a previous run's session, and starts this one from where that one stopped instead of from the repository's default. |
agentRef | body | string | — | AgentRef names a configured agent to run as, which is how an org pins a harness, a model and a prompt to a name. |
base | body | string | — | Base is the branch to start from. |
desktop | body | boolean | — | Desktop asks for a run with a SCREEN — an image carrying an X server — for a task that has to drive a browser or another windowed program. |
project | body | string | — | Project scopes the run to one board's work when the org keeps more than one. |
prompt | body | string | — | Prompt is the task, in the words you would use with a colleague who has the checkout open. |
replyChannel | body | string | — | ReplyChannel / ReplyThread are WHERE THE RUN NARRATES ITSELF, when the door that started it has somewhere for it to talk. |
replyThread | body | string | — | ReplyThread narrows that address to one THREAD inside the channel: on Slack it is the parent message's ts, the same value a reply carries as thread_ts. |
repo | body | string | — | Repo is what to work on, as owner/name in the caller's own org. |
targetId | body | string | — | TargetID routes the run to a registered machine the org has claimed instead of to a sandbox in our cluster. |
timeoutSeconds | body | integer | — | TimeoutSeconds bounds the whole run. |
tool | body | string | — | Tool is which harness runs the prompt — dev | claude | codex | python | node — and Desktop is whether the run needs a screen. |
Response
| Status | Body | Meaning |
|---|---|---|
202 | CodingStarted | accepted |
202 body — 5 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
branch | body | string | — | Branch is the ref the run will push its work to, and the ONLY ref it is permitted to write. |
repo | body | string | — | Repo is the repository the run was admitted against, echoed back as the engine resolved it. |
routed | body | boolean | — | Routed says the run went to one of the org's own registered machines rather than to a sandbox in our cluster. |
sessionId | body | string | — | SessionID is the run's handle: its durable record, and the id its live progress streams under at /v1/agents/sessions/{sessionId}/stream. |
targetId | body | string | — | TargetID names that machine when Routed is true, and is empty otherwise. |
Failure carries the platform error shape — see Errors.
Examples
hanzo has no subcommand for this operation — the CLI serves only what cloud's live route table confirms. Use HTTP or an SDK.
import { Configuration, AgentsApi } from 'hanzoai';
const api = new AgentsApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postAgentsCoding({ after: "<after>", agentRef: "<agentRef>" });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import AgentsApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = AgentsApi(client).post_agents_coding(after="<after>", agent_ref="<agentRef>")cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.AgentsAPI.PostAgentsCoding(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, agents_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = agents_api::post_agents_coding(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.AgentsApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new AgentsApi(client).postAgentsCoding();The method above is the one at the current release of the document. [email protected] (npm) and [email protected] (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →
curl -X POST https://api.hanzo.ai/v1/agents/coding \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"after": "<after>",
"agentRef": "<agentRef>"
}'The door reaches agents through the agents tool, which names its 36 operations with its own verbs — this one among them, under a name only the door declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_agent_conversations"
}
}
}'How is this guide?