# Coding agents

> Run Claude Code, Codex, or Pi inside a machine, follow what it does, steer or interrupt it, and pick up a conversation later.

A coding agent runs inside a running machine, in its `/work` directory, with the machine's tools. You send it a prompt, follow its events as they happen, add instructions while it works, and stop it. Each machine keeps several conversations, and you can resume any of them. Prompts, attachments, and the agent's output stay on the machine's disk.

In the console, open a machine and choose **Agents**.

## Provider keys

The agent uses the provider keys in the machine's [environment](/docs/guides/environments): for example `ANTHROPIC_API_KEY` for Claude Code or `OPENAI_API_KEY` for Codex. A machine created without an environment gives the agent no keys, so add one to an environment and create the machine with it. Keys never appear in requests, events, or VMYard's records.

## Start or resume a conversation

```sh
curl -X POST "$VMYARD_API_URL/v1/machines/$MACHINE/agents/prompt" \
  -H "Authorization: Bearer $VMYARD_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"provider": "claude", "model": "sonnet", "reasoning_effort": "medium", "text": "Add a health check endpoint and run the tests."}'
```

The answer (`202`) is the turn, with its `conversation_id`. Send that `conversation_id` with the next prompt to continue the conversation; a conversation keeps its agent. `GET /v1/provider-models` lists each agent's models and reasoning efforts. Up to 16 attachments (16 MiB together) are written to the machine for the agent to read.

## Follow the events

`GET /v1/machines/{id}/agents/events?conversation_id=…` answers JSON by `cursor`, waiting up to `wait_seconds` (at most 30) for an event, or a server-sent event stream with `Accept: text/event-stream`. Each SSE event's `id` is the cursor after it, so a client that reconnects with `Last-Event-ID` resumes where it stopped, without repeats. The stream ends with an `idle` event when no turn is running.

| `type` | Meaning |
| --- | --- |
| `turn_started` | The agent started, with its model and reasoning effort. |
| `input_accepted` | The agent took an input (`kind`: `prompt`, `steer`, or `interrupt`) with this `input_id`. |
| `text_delta`, `message` | Text the agent wrote, piece by piece or whole. |
| `thinking_delta` | The agent's reasoning, when it shares it. |
| `tool_call`, `tool_result` | A tool the agent ran (`id`, `name`, `input`) and what came back (`output`, `is_error`). |
| `usage` | Tokens and the agent's own cost estimate. |
| `error` | Something went wrong (`code`, `message`). |
| `turn_end` | The turn ended: `outcome` is `completed`, `failed`, or `interrupted`. |

## Steer and interrupt

While a turn runs, `POST /v1/machines/{id}/agents/steer` with the `conversation_id` and `text` adds instructions; the agent confirms when it takes them with an `input_accepted` event carrying the steer's `input_id`. `POST /v1/machines/{id}/agents/interrupt` asks the turn to stop, and `force: true` stops it at once. Both need an `Idempotency-Key`. See [Errors](/docs/guides/errors#coding-agents).
