---
title: "One agent · intentic sandbox API"
description: "Run a turn in one conversation, then attach to it, answer it, steer it or stop it. Every route in the one agent group of the intentic sandbox API, with its input, its answer and a playground."
url: "https://intentic.dev/api/agent/"
---

Agents

# One agent

Run a turn in one conversation, then attach to it, answer it, steer it or stop it

**On this page (8 sections)**

- [Say something to an agent](#agent-run)
- [Watch a turn happen](#agent-attach)
- [Answer a question the agent asked](#agent-reply)
- [Interrupt a running turn](#agent-steer)
- [Stop a turn now](#agent-stop)
- [Go back to an earlier message](#agent-rewind)
- [Shortcut commands the agent knows](#agent-commands)
- [The last time each provider said no](#agent-refusals)

The surface most callers are here for. Starting a turn answers with a run id and nothing else: the work happens inside the sandbox whether or not anybody stays connected, and attaching is how you watch it, from the beginning or from wherever you had got to. The rest is the things a person does to a turn in flight — answer a question it asked, redirect it, stop it, or put the whole conversation back to an earlier point. Everything here addresses one conversation by id.

8 calls. Pick one to open it, or use the list on the right.

**POST`/agent` Say something to an agent**

Starts a turn and answers immediately with its id; the work runs inside the sandbox whether or not anybody stays connected. Watch it by attaching. Naming a conversation that does not exist yet opens it.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `prompt` required What to say to the agent | string | body |
| `title` A title for a conversation this… | string | body |
| `attachments` Files to hand the agent along… | string[] | body |
| `agent` Which model provider serves this turn | string | body |
| `harness` Which agentic loop runs the turn | "native" | "claude-code" | body |
| `account` Which of that provider's connected accounts… | string | body |
| `actsAs` Which persona the turn speaks as… | string | body |
| `sessionId` Resume this provider session instead of… | string | body |
| `conversationId` The conversation this turn belongs to | string | body |
| `isolated` Work in this conversation's own private… | boolean | body |
| `worktreeBase` Pin a new private copy to… | object[] | body |
| `repo` required | string | body |
| `base` required | string | body |
| `autoLand` Whether this turn's work merges into… | boolean | body |
| `origin` Set by the sandbox alone: this… | object | body |
| `automationId` required | string | body |
| `provider` required | string | body |
| `channelId` | string | body |
| `author` | string | body |
| `forkOf` Where this conversation was cut from,… | object | body |
| `conversationId` required The conversation this one was cut… | string | body |
| `keep` required How many of that conversation's messages… | integer | body |
| `files` required Which files the fork opens on:… | "then" | "now" | body |
| `model` Which model to use | string | body |
| `unattended` Nobody chose a model for this… | boolean | body |
| `outsideWake` Content from outside caused this turn,… | string | body |
| `permissionMode` How tool calls are gated: ask… | "default" | "acceptEdits" | "plan" | "bypassPermissions" | body |
| `allowedTools` Narrow the turn to these tools | string[] | body |
| `effort` How hard the model should think,… | string | body |
| `thinking` Whether to show the model's reasoning… | boolean | body |
| `fast` Ask for the same work at… | boolean | body |
| `tierHold` Run exactly the model that was… | boolean | body |
| `editorContext` What the user has open in… | object | body |
| `file` required The file open in the editor,… | string | body |
| `startLine` First line of the selection, counting… | integer | body |
| `endLine` Last line of the selection, counting… | integer | body |
| `selection` The selected text itself | string | body |

### What comes back

| Field | Type |
| --- | --- |
| `run` The id of the run that… | string |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/agent" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"prompt":"Update the changelog for the last five commits.","title":"Update the changelog","attachments":["…","…"],"agent":"…","harness":"native","account":"work","actsAs":"…","sessionId":"a1b2c3d4","conversationId":"nightly-changelog","isolated":true,"worktreeBase":[{"repo":"root","base":"…"},{"repo":"site","base":"…"}],"autoLand":true,"origin":{"automationId":"a1b2c3d4","provider":"claude","channelId":"a1b2c3d4","author":"Ada Lovelace"},"forkOf":{"conversationId":"nightly-changelog","keep":0,"files":"then"},"model":"claude-sonnet-4-6","unattended":true,"outsideWake":"…","permissionMode":"default","allowedTools":["…","…"],"effort":"…","thinking":true,"fast":true,"tierHold":true,"editorContext":{"file":"…","startLine":1,"endLine":1,"selection":"…"}}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.run({
 "prompt": "Update the changelog for the last five commits.",
 "title": "Update the changelog",
 "attachments": [
 "…",
 "…"
 ],
 "agent": "…",
 "harness": "native",
 "account": "work",
 "actsAs": "…",
 "sessionId": "a1b2c3d4",
 "conversationId": "nightly-changelog",
 "isolated": true,
 "worktreeBase": [
 {
 "repo": "root",
 "base": "…"
 },
 {
 "repo": "site",
 "base": "…"
 }
 ],
 "autoLand": true,
 "origin": {
 "automationId": "a1b2c3d4",
 "provider": "claude",
 "channelId": "a1b2c3d4",
 "author": "Ada Lovelace"
 },
 "forkOf": {
 "conversationId": "nightly-changelog",
 "keep": 0,
 "files": "then"
 },
 "model": "claude-sonnet-4-6",
 "unattended": true,
 "outsideWake": "…",
 "permissionMode": "default",
 "allowedTools": [
 "…",
 "…"
 ],
 "effort": "…",
 "thinking": true,
 "fast": true,
 "tierHold": true,
 "editorContext": {
 "file": "…",
 "startLine": 1,
 "endLine": 1,
 "selection": "…"
 }
});
```

**POST`/agent/attach` Watch a turn happen stream**

Streams everything the agent does: its words, the tools it reaches for, and the answers it gets. Give it the point you have already seen and it replays from there before going live, so a reload loses nothing. The window that started the turn holds no special claim, and any number of watchers on any number of devices see the same thing.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required Which conversation to watch | string | body |
| `run` The run you were watching | string | body |
| `after` The last frame you already have | integer | body |

### What comes back

| Field | Type |
| --- | --- |
| `when event is "message"` | shape |
| `data` | object |
| `when kind is "attached"` | shape |
| `run` The run's id | string |
| `prompt` What was said to start it,… | string |
| `startedAt` When it started, in milliseconds, so… | number |
| `seq` How many frames already exist | number |
| `when kind is "frame"` | shape |
| `seq` Its position in the run, counting… | number |
| `when kind is "end"` | shape |
| `id` | string |
| `retry` | number |
| `when event is "done"` | shape |
| `data` | unknown |
| `id` | string |
| `retry` | number |
| `when event is "error"` | shape |
| `data` | unknown |
| `id` | string |
| `retry` | number |

Try it answered in this tab

curl

```bash
curl -N -X POST "$SANDBOX/agent/attach" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"conversationId":"nightly-changelog","run":"run_8c2f41d9","after":0}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.attach({
 "conversationId": "nightly-changelog",
 "run": "run_8c2f41d9",
 "after": 0
});
```

**POST`/agent/reply` Answer a question the agent asked**

Un-parks a turn that is waiting on you: approving a plan, choosing between options, or permitting a tool. The turn picks up where it stopped.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `when kind is "plan"` | shape | body |
| `requestId` required Which card you are answering, from… | string | body |
| `approve` required Whether to go ahead | boolean | body |
| `feedback` Why not, which goes back to… | string | body |
| `when kind is "question"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `answers` What you chose, keyed by the… | object | body |
| `cancelled` Dismissing it instead, which tells the… | boolean | body |
| `when kind is "permission"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `decision` required Once allows this call alone; always… | "once" | "always" | "deny" | body |
| `feedback` Why not, which goes back to… | string | body |
| `when kind is "browser_help"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `helped` required Whether you cleared it | boolean | body |
| `note` Anything the agent should know, which… | string | body |
| `when kind is "terminal_help"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `helped` required Whether you did it | boolean | body |
| `note` Anything the agent should know, which… | string | body |
| `when kind is "service_offer"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `approve` required Yes releases exactly one run | boolean | body |
| `when kind is "capability_offer"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `connect` required Yes keeps the agent waiting while… | boolean | body |
| `when kind is "payment_offer"` | shape | body |
| `requestId` required Which card you are answering | string | body |
| `approve` required Yes releases exactly one payment | boolean | body |

### What comes back

| Field | Type |
| --- | --- |
| `ok` Always true | true |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/agent/reply" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"kind":"plan","requestId":"a1b2c3d4","approve":true,"feedback":"…"}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.reply({
 "kind": "plan",
 "requestId": "a1b2c3d4",
 "approve": true,
 "feedback": "…"
});
```

**POST`/agent/steer` Interrupt a running turn**

Slips a message into a turn already under way, without stopping it. This is how you redirect an agent mid-thought rather than waiting for it to finish being wrong.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required Which running conversation to interrupt | string | body |
| `text` required What to say to it | string | body |
| `attachments` Files to send with it, as… | string[] | body |
| `editorContext` What you have open, folded in… | object | body |
| `file` required The file open in the editor,… | string | body |
| `startLine` First line of the selection, counting… | integer | body |
| `endLine` Last line of the selection, counting… | integer | body |
| `selection` The selected text itself | string | body |

### What comes back

| Field | Type |
| --- | --- |
| `ok` Always true | true |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/agent/steer" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"conversationId":"nightly-changelog","text":"export const start = () => listen(PORT);\n","attachments":["…","…"],"editorContext":{"file":"…","startLine":1,"endLine":1,"selection":"…"}}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.steer({
 "conversationId": "nightly-changelog",
 "text": "export const start = () => listen(PORT);\n",
 "attachments": [
 "…",
 "…"
 ],
 "editorContext": {
 "file": "…",
 "startLine": 1,
 "endLine": 1,
 "selection": "…"
 }
});
```

**POST`/agent/stop` Stop a turn now**

Cancels the running turn inside the sandbox. Whatever it had already written to disk stays written.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required Which conversation's running turn to cancel | string | body |

### What comes back

| Field | Type |
| --- | --- |
| `ok` Always true | true |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/agent/stop" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"conversationId":"nightly-changelog"}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.stop({
 "conversationId": "nightly-changelog"
});
```

**POST`/agent/rewind` Go back to an earlier message**

Puts the files back as they stood at that point, drops every message after it, and forgets what the model remembered, so the next thing you say starts from there cleanly. Refused while a turn is running, because a restore cannot overwrite files an agent is editing, and refused for a message with no saved state to return to.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required Which conversation to rewind | string | body |
| `index` required Which message to go back to,… | integer | body |

### What comes back

| Field | Type |
| --- | --- |
| `snapshot` The saved point the files were… | string |
| `dropped` How many messages were removed | integer |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/agent/rewind" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"conversationId":"nightly-changelog","index":0}'
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.rewind({
 "conversationId": "nightly-changelog",
 "index": 0
});
```

**GET`/agent/commands` Shortcut commands the agent knows**

The commands a provider published the last time one of its turns ran, so a composer can offer them before this conversation has run anything. A running turn's own list wins over this one.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `agent` Whose commands to read | string | query |

### What comes back

| Field | Type |
| --- | --- |
| `commands` The shortcut commands, as the provider… | object[] |
| `name` What to type, without the leading… | string |
| `description` What it does | string |
| `hint` What its argument should look like,… | string |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/agent/commands" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.commands();
```

**GET`/agent/refusals` The last time each provider said no**

What each model provider most recently refused and why. Read this alongside an account's usage: the usage says how full it was when last checked, this says whether it has since started turning work away.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `refusals` The most recent refusal per provider | object |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/agent/refusals" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

```typescript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.agent.refusals();
```

More in Agents

[Next The fleet →](https://intentic.dev/api/agents/)
