Skip to main content
A harness is the agent loop itself: assemble a turn, call the model, parse the tool calls, decide what carries into the next turn. It is the one layer of Vetta you select, and it is a single field on an agent:
Everything under it is unchanged when you change it — the durable loop, the budget gate, the tool policy, the event log and the ledger all sit beneath the harness, not inside it. That is what makes the field safe to change on an existing agent.

The loops

This table says what each loop is. It does not say what you can use — that varies by environment, because a harness needs both an adapter compiled in and, for one that runs as a process, a base image built in that environment’s provider account. GET /v1/harnesses is authoritative, and its runnable field answers for the deploy you are talking to.

Two questions decide which one

They are separate, and both matter. What must the loop be able to do? Harnesses differ in real ways, and the differences are published as capabilities:

Where the tools come from, and the two limits

Every harness now declares injected_tools: true, and these families reach every published loop:
  • The team tools. send_to_agent, wait_for_agents, list_agents, board_read and board_write. A coordinator runs on any harness.
  • MCP servers declared on the agent, with their tools named <server>.<tool> as always.
  • Connected accounts and the tools they contribute, named <connector>.<tool>, plus the tools for asking for a connection the agent does not yet have.
  • Social publishing and your apps, including the tools an app declares for itself.
On a harness whose agent is a CLI process in a machine of its own, these arrive by a different road. The loop is given a session-scoped tool endpoint, scoped to that one session by a credential minted for the turn, and it calls the tools over it. You configure nothing: the endpoint is written into the machine for you at the start of every turn. The agent’s own toolset — its file, shell and search tools — is unchanged and sits alongside ours.
Vetta’s own built-ins do not travel that second road yetweb search and fetch, image and video generation, skill disclosure, publish_file and the managed browser are offered on pi and vetta only. A claude_code or hermes agent has its own CLI’s web, file and search tools in their place; write your prompt against those, not against publish_file.
Your tools policy still governs all of it, by the same names. A tool set to deny is never offered to the model on any harness: on these it is not merely refused when called, it is left out of the list the agent is given, so the model never learns it exists. Two limits are real on this road, and both are consequences of approvals: false:
A tool whose permission is ask is left out entirely, not gated. Nothing in such a machine can hold a call open while a person decides — the agent’s own prompt is closed, and the call is one request that must be answered now. This is why a session whose toolset carries an ask is refused when it starts on a harness declaring approvals: false, naming harness. The one case you can meet without writing ask yourself is social publishing: social.post defaults to ask, so on these harnesses it is not offered unless you set it to allow explicitly.wait_for_agents does not pause the turn. A coordinator that fans work out and then calls it is not suspended mid-turn the way it is on a loop we host; it parks once the turn goes idle, and the delegated threads open correctly either way. The cost is a few extra model calls between the fan-out and the park, not a wrong answer.

The values, per harness

Harness capabilities is the matrix: which of the four each loop declares, what an idle session holds, which pairings are refused and where — and the one catalogue entry that is still optimistic.
A session that asks for a capability its harness does not declare is refused when it starts, with a 400 naming the field — and where the configuration can be judged earlier, the refusal happens earlier still, at the agent save. It is never a quiet best effort: an ask toolset that silently became allow would remove your human-in-the-loop gate with nothing to notice it by. What should an idle session cost? This is the execution field, and it is not the same question as who operates the loop:
A long-running task that spends most of its life waiting — for a schedule, for a person, for a webhook — costs very differently on isolate than on sandbox. That is usually the deciding factor for long-horizon work, and it is why the field is published rather than left for you to infer from a bill.

Reading the catalogue

The set is not fixed in the documentation, because a harness needs an adapter compiled in and an environment can have a different set. Read it at runtime:
runnable answers for the deploy you are talking to. A harness can be published — so a picker can show it, disabled — while this environment cannot run it, in which case starting a session on it is a 501 naming the field rather than a failure part-way through a turn. Full field reference: GET /v1/harnesses and client.harnesses.

Changing it

harness is versioned with the rest of the agent, so changing it creates a new agent version and a session pins the version it started on. An in-flight session is never re-hosted onto a different loop mid-run. The prompt, the skills, the budget and the window all carry across unchanged — that is the point of the seam. The tools carry across too, and that is newer than the rest of this page. Moving an agent onto a harness that runs a CLI in a machine of its own no longer withdraws its team tools, its MCP servers or its connected accounts — they are served over a session-scoped tool endpoint instead of handed to the loop. What does not carry across is anything that needs a capability the destination does not declare: an ask in your toolset, or structured_output_required. Because harness is create-only you meet that at the agent save, where the refusal names the field to change.