---
title: "System · intentic sandbox API"
description: "The daemon itself: its identity, its event stream, its terminals, its browsers, its helpers. Every route in the system group of the intentic sandbox API."
url: "https://intentic.dev/api/system/"
---

The sandbox itself

# System

The daemon itself: its identity, its event stream, its terminals, its browsers, its helpers

**On this page (25 sections)**

- [What this sandbox is](#system-info)
- [Stop offering one release](#system-skipUpdate)
- [Decide how updates are taken](#system-autoUpdate)
- [Settings files the sandbox could not read](#system-manifestProblems)
- [Take a stray setting out of a file](#system-repairManifest)
- [Trade a sign-in for a session](#system-session)
- [The live event stream](#system-events)
- [Say what you are looking at](#system-presence)
- [What has been spent](#system-usage)
- [What the sandbox is using right now](#system-metrics)
- [What is filling the disk](#system-storage)
- [Measure what is filling the disk](#system-scanStorage)
- [Stop measuring the disk](#system-cancelStorageScan)
- [Free the space one category holds](#system-cleanStorage)
- [Open terminals](#system-terminals)
- [Close a terminal](#system-killTerminal)
- [A terminal's history as plain text](#system-terminalScrollback)
- [Browsers the agent has open](#system-browsers)
- [Shut a browser down](#system-closeBrowser)
- [The sandbox's own desktop](#system-desktop)
- [Subagents the agents have started](#system-subagents)
- [The machines you have connected](#system-devices)
- [Drive a sandbox on one of your own devices](#system-manageDeviceSandbox)
- [Run one of your device's own CLI actions](#system-runDeviceCommand)
- [Update, restart, or clean up the links of the agent on one of your own devices](#system-runDeviceAgentFlow)

The group with the widest job. The identity read is what the daemon says it is, including the routes it implements, which is the one call that tells a newer client what this sandbox can do. The event stream is the sandbox-wide live feed. The rest is the machinery an agent leaves running: terminals and their history, browsers, and the records of helpers it delegated to.

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

**GET`/info` What this sandbox is**

The sandbox's own identity and state: which workspace it holds, which image it runs, what it is called, and the list of calls it actually implements. Start here, because a browser is routinely newer than the sandbox it is talking to and this is how it finds out what is there.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `name` What this sandbox is called | string |
| `image` The image it is running | string |
| `version` The version of that image | string |
| `latest` The newest published version on its… | string |
| `updateAvailable` Whether those two differ | boolean |
| `runtimes` Which agent runtimes can serve a… | object |
| `channel` Which release channel this sandbox follows | string |
| `previousImage` The image the last update replaced,… | string |
| `updateNotes` What is in the update, in… | string[] |
| `moreUpdateNotes` How many further notes there are… | number |
| `breakingNotes` What the update takes away, uncapped,… | string[] |
| `staged` An update already downloaded and built… | object |
| `version` What the downloaded build says it… | string |
| `channel` Which channel it was taken from | string |
| `at` When the download finished, in milliseconds,… | number |
| `plan` What the downloaded build's first boot… | object |
| `plan` The format of this line | 1 |
| `version` The release of the image that… | string |
| `engine` The conversion count builds before the… | number |
| `digest` What identifies the planning build's conversion… | string |
| `ok` False when a conversion would fail… | boolean |
| `downgrade` A newer release than the planning… | boolean |
| `failures` Each conversion or step that would… | object[] |
| `document` The stored file whose conversion would… | string |
| `detail` Why, in the conversion's own words | string |
| `steps` What the first boot changes on… | object[] |
| `document` The stored file, workspace-relative, or `<volume>:<path>`… | string |
| `change` What is done to it, in… | string |
| `detail` What was particular about this one:… | string |
| `converts` What the build's conversions change as… | object[] |
| `document` The stored file, workspace-relative, or `<volume>:<path>`… | string |
| `change` What is done to it, in… | string |
| `detail` What was particular about this one:… | string |
| `files` Every file the first boot writes,… | string[] |
| `preparing` A download of the next update… | object |
| `channel` Which channel it is being taken… | string |
| `startedAt` When the download began, in milliseconds | number |
| `at` When the machine last said it… | number |
| `phase` What it is doing: download (pulling… | string |
| `percent` How far through the download it… | number |
| `lastUpdate` What the machine running this sandbox… | object |
| `result` What happened | "updated" | "kept" | "restored" | "rolled-back" |
| `verb` What was asked for: update, rollback,… | string |
| `at` When it happened, in milliseconds | number |
| `from` The version (or, when it would… | string |
| `to` The version (or image) that was… | string |
| `reason` Why the host gave up on… | string |
| `log` Where the host kept the full… | string |
| `keepUntil` Until when the previous version stays… | number |
| `withdrawn` Set when the version this sandbox… | object |
| `version` The withdrawn version, which is the… | string |
| `reason` Why it was withdrawn, as the… | string |
| `skippedVersion` A release the owner chose to… | string |
| `autoUpdate` Whether and when this sandbox takes… | object |
| `enabled` Whether this sandbox takes downloaded updates… | boolean |
| `phase` Where it stands: idle (nothing downloaded… | string |
| `version` The downloaded version it will take | string |
| `holds` Everything keeping it waiting right now,… | object[] |
| `kind` What it waits on: agents (an… | string |
| `names` Who or what, by name: the… | string[] |
| `until` When this lifts by itself, in… | number |
| `startsAt` During a countdown, when the restart… | number |
| `pausedUntil` The owner's pause: no automatic update… | number |
| `failure` Why the last automatic try did… | string |
| `lastApplied` The last update this sandbox took… | object |
| `at` | number |
| `to` | string |

Try it answered in this tab

curl

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

TypeScript

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

const result = await sandbox.system.info();
```

**POST`/system/update/skip` Stop offering one release**

Stops offering the named release as an update, typically one this sandbox already tried and went back from. A newer release is offered as usual. Null offers the newest release again.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `version` required The release to stop offering, or… | string | null | body |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/update/skip" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"version":"1.4.0"}'
```

TypeScript

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

const result = await sandbox.system.skipUpdate({
 "version": "1.4.0"
});
```

**POST`/system/update/auto` Decide how updates are taken**

Turns taking a downloaded update by itself on or off, pauses it until a moment, or takes the downloaded update right now. A sandbox taking updates by itself waits for a quiet moment: no agent mid-turn, nobody at the editor, terminals quiet. Answers with where it stands afterwards.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `enabled` Turn taking downloaded updates by itself… | boolean | body |
| `pausedUntil` Hold automatic updates until this moment,… | number | body |
| `applyNow` Take the downloaded update now, without… | true | body |

### What comes back

| Field | Type |
| --- | --- |
| `enabled` Whether this sandbox takes downloaded updates… | boolean |
| `phase` Where it stands: idle (nothing downloaded… | string |
| `version` The downloaded version it will take | string |
| `holds` Everything keeping it waiting right now,… | object[] |
| `kind` What it waits on: agents (an… | string |
| `names` Who or what, by name: the… | string[] |
| `until` When this lifts by itself, in… | number |
| `startsAt` During a countdown, when the restart… | number |
| `pausedUntil` The owner's pause: no automatic update… | number |
| `failure` Why the last automatic try did… | string |
| `lastApplied` The last update this sandbox took… | object |
| `at` | number |
| `to` | string |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/update/auto" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"enabled":true,"pausedUntil":1,"applyNow":true}'
```

TypeScript

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

const result = await sandbox.system.autoUpdate({
 "enabled": true,
 "pausedUntil": 1,
 "applyNow": true
});
```

**GET`/system/manifest-problems` Settings files the sandbox could not read**

Anything the daemon tripped over in its own configuration on disk: a file it had to fall back from, a key it did not recognise, an entry it skipped. Separate from the identity call because it goes stale for a different reason, namely a file changing.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `path` The file, as a workspace path,… | string |
| `problems` Everything currently wrong with it | object[] |
| `kind` What to do about it | "unreadable" | "unknownKey" | "invalidEntry" |
| `reason` Why it could not be read:… | "io" | "not-json" | "conversion-failed" | "rejected" |
| `detail` What exactly was wrong, as one… | string |
| `suggestion` The name it was probably meant… | string |
| `fix` What to do about it, when… | string |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/manifest-problems" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.manifestProblems();
```

**POST`/system/manifest-problems/repair` Take a stray setting out of a file**

Removes a key the sandbox does not recognise from one of its settings files, or renames it to the one it was probably meant to be, keeping the value. Only the files a person hand-edits can be named, and only a key — never a value — so this can only ever remove something already being ignored. Renaming onto a key the file already has is refused instead of overwriting it.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `path` required The file to repair, as the… | string | body |
| `key` required The stray top-level key, exactly as… | string | body |
| `to` Rename the key to this instead… | string | body |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/manifest-problems/repair" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"path":"src/app.ts","key":"OPENAI_API_KEY","to":"src/server.ts"}'
```

TypeScript

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

const result = await sandbox.system.repairManifest({
 "path": "src/app.ts",
 "key": "OPENAI_API_KEY",
 "to": "src/server.ts"
});
```

**POST`/system/session` Trade a sign-in for a session**

Exchanges a verified sign-in, or a session that has not expired yet, for a fresh session the daemon minted. That session is the credential every other call carries, and calling this again with a live one renews it.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `token` The credential every other call carries | string |
| `expiresAt` When it stops working, in milliseconds,… | number |
| `email` Who the sandbox verified you as | string |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/session" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.session();
```

**GET`/events` The live event stream stream**

A stream held open for as long as you want it, carrying heartbeats so a caller notices the sandbox dying at once, batches of file changes so a tree or an editor can refresh itself, and the roster of who else is looking. Give it an id for this connection to appear in that roster; leave it out and you watch without being seen.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `clientId` | string | query |

### What comes back

| Field | Type |
| --- | --- |
| `when event is "message"` | shape |
| `data` | object |
| `when kind is "hello"` | shape |
| `workspaceId` | string |
| `routes` | string[] |
| `shapes` | object |
| `build` | string |
| `boot` | object |
| `projectDir` | string |
| `surface` | "sandbox" | "folder" |
| `when kind is "heartbeat"` | shape |
| `rev` | number |
| `when kind is "boot"` | shape |
| `ready` | boolean |
| `startedAt` | number |
| `steps` | object[] |
| `when kind is "workspaceChanged"` | shape |
| `paths` | string[] |
| `when kind is "treeChanged"` | shape |
| `from` The generation this applies on top… | integer |
| `generation` The generation it leaves the tree… | integer |
| `dirs` Each folder that changed, parents before… | object[] |
| `barren` The barren folders now, present only… | string[] |
| `when kind is "derivedChanged"` | shape |
| `paths` | string[] |
| `when kind is "reposChanged"` | shape |
| `repos` | string[] |
| `when kind is "refsChanged"` | shape |
| `repos` | string[] |
| `when kind is "runtimeChanged"` | shape |
| `domains` | string[] |
| `when kind is "presence"` | shape |
| `users` | object[] |
| `when kind is "agents"` | shape |
| `agents` | object[] |
| `rev` | number |
| `when kind is "accountUsage"` | shape |
| `provider` | string |
| `account` | string |
| `usage` | object |
| `when kind is "providerRefusal"` | shape |
| `provider` | string |
| `refusal` | object |
| `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 "$SANDBOX/events" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.events();
```

**POST`/system/presence` Say what you are looking at**

Reports which view, conversation or file this connection is on, or that it has gone idle. The daemon fans it back out on the event stream so everyone else's roster updates.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `clientId` required This connection's own id, the same… | string | body |
| `idle` required Whether the person has stopped doing… | boolean | body |
| `away` Whether the window is on screen… | boolean | body |
| `view` Which view they are on | string | body |
| `sessionId` Which conversation they have open | string | body |
| `path` Which file they are looking at | string | body |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/presence" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"clientId":"a1b2c3d4","idle":true,"away":true,"view":"…","sessionId":"a1b2c3d4","path":"src/app.ts"}'
```

TypeScript

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

const result = await sandbox.system.presence({
 "clientId": "a1b2c3d4",
 "idle": true,
 "away": true,
 "view": "…",
 "sessionId": "a1b2c3d4",
 "path": "src/app.ts"
});
```

**GET`/system/usage` What has been spent**

Token and cost totals per account, added up from the record of every finished turn.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `accounts` | object[] |
| `provider` | string |
| `account` | string |
| `turns` | number |
| `inputTokens` | number |
| `outputTokens` | number |
| `cacheReadTokens` | number |
| `cacheCreationTokens` | number |
| `costUsd` | number |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/usage" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.usage();
```

**GET`/system/metrics` What the sandbox is using right now**

CPU and memory for the sandbox as a whole, for the daemon that runs it, for each kind of process, and for each conversation's own processes. Measured when you ask and never in between, so CPU is the use since the previous reading: the first reading after a quiet spell has memory and no CPU, and the next one a few seconds later has both.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `at` When this reading was taken, in… | number |
| `windowMs` How long the CPU figures were… | number |
| `sandbox` The sandbox as a whole | object |
| `cpuPercent` CPU the whole sandbox used over… | number |
| `cores` How many cores the sandbox may… | number |
| `memoryBytes` Memory counted against the limit, as… | number |
| `memoryLimitBytes` The memory limit work is admitted… | number |
| `swapBytes` What was pushed out to swap,… | number |
| `swapLimitBytes` What swap can hold | number |
| `swapFull` Swap is nearly at `swapLimitBytes`: nothing… | boolean |
| `memoryRoom` What admission reads off the same… | object |
| `freeBytes` The limit less what is used… | number |
| `reservedBytes` What work admitted in the last… | number |
| `personNeedBytes` What a person's turn needs free… | number |
| `stallPercent` Percent of the last ten seconds… | number |
| `stallLimitPercent` The stall at or past which… | number |
| `stallSustainedPercent` Percent of the last minute in… | number |
| `stallSustainedLimitPercent` The minute's stall at or past… | number |
| `diskBytes` Space used on the volume the… | number |
| `diskTotalBytes` That volume's size | number |
| `loadAverage` The load average over 1, 5… | unknown[] |
| `machineCores` Cores the machine's load average reads… | number |
| `processes` How many processes are running in… | number |
| `pressure` How much work waited on CPU,… | object |
| `cpu` Percent of the last ten seconds… | number |
| `memory` Percent of the last ten seconds… | number |
| `io` Percent of the last ten seconds… | number |
| `daemon` The daemon that runs it, which… | object |
| `rssBytes` The daemon's own resident memory | number |
| `heapUsedBytes` Of that, JavaScript objects in use | number |
| `cpuPercent` CPU the daemon itself used over… | number |
| `eventLoopPercent` How much of the window the… | number |
| `sessions` What each conversation's processes use, by… | object |
| `roles` Every process in the sandbox but… | object |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/metrics" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.metrics();
```

**GET`/system/storage` What is filling the disk**

The last measurement of the sandbox's disk, by what the space is for: conversations, checkouts, restore points, caches, logs, the trash and the rest, each with its biggest parts and whether it can be cleaned from here. Reading it measures nothing; ask for a scan to measure again.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `scan` The last scan that finished | object |
| `startedAt` When the scan began, in milliseconds | number |
| `finishedAt` When it ended, in milliseconds: the… | number |
| `outcome` `partial` when the scan hit its… | "complete" | "partial" |
| `disk` The volume as a whole | object |
| `usedBytes` Space used on the volume the… | number |
| `totalBytes` That volume's size | number |
| `categories` Every category that holds anything, largest… | object[] |
| `id` | "workspace" | "conversations" | "checkouts" | "restorePoints" … (22) |
| `cleanability` Whether this category can be cleaned… | "none" | "safe" | "confirm" |
| `bytes` Its size in bytes | number |
| `files` How many files it holds | number |
| `cleanableBytes` What cleaning it would free right… | number |
| `items` Its biggest parts, largest first, at… | object[] |
| `path` Where it is, as an absolute… | string |
| `bytes` Its size in bytes | number |
| `unreadable` Files and folders the scan could… | number |
| `scanning` Whether a scan is running now | boolean |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/storage" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.storage();
```

**POST`/system/storage/scan` Measure what is filling the disk**

Walks the sandbox's volumes and answers with the new measurement once it is done. A scan already running is joined rather than doubled. It stops at a time limit and says so, since a size it could not finish is still worth reading. A cancelled scan answers with the previous measurement.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `scan` The last scan that finished | object |
| `startedAt` When the scan began, in milliseconds | number |
| `finishedAt` When it ended, in milliseconds: the… | number |
| `outcome` `partial` when the scan hit its… | "complete" | "partial" |
| `disk` The volume as a whole | object |
| `usedBytes` Space used on the volume the… | number |
| `totalBytes` That volume's size | number |
| `categories` Every category that holds anything, largest… | object[] |
| `id` | "workspace" | "conversations" | "checkouts" | "restorePoints" … (22) |
| `cleanability` Whether this category can be cleaned… | "none" | "safe" | "confirm" |
| `bytes` Its size in bytes | number |
| `files` How many files it holds | number |
| `cleanableBytes` What cleaning it would free right… | number |
| `items` Its biggest parts, largest first, at… | object[] |
| `path` Where it is, as an absolute… | string |
| `bytes` Its size in bytes | number |
| `unreadable` Files and folders the scan could… | number |
| `scanning` Whether a scan is running now | boolean |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/storage/scan" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.scanStorage();
```

**DELETE`/system/storage/scan` Stop measuring the disk**

Stops a running scan. Whoever was waiting on it gets the previous measurement back; nothing is lost but the time.

### What you send

Nothing. Call it as it is.

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X DELETE "$SANDBOX/system/storage/scan" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.cancelStorageScan();
```

**POST`/system/storage/clean` Free the space one category holds**

Removes what one cleanable category holds, and says how much space that gave back. Only what is old enough and not in use goes: today's logs, a browser that is open, the weights a running model reads and a pack still being written all stay. Nothing outside the sandbox's own volumes, and nothing a category may not hold, is ever removed. Categories that cannot be cleaned are refused.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `category` required The category to clean; one whose… | "workspace" | "conversations" | "checkouts" | "restorePoints" … (22) | body |

### What comes back

| Field | Type |
| --- | --- |
| `category` | "workspace" | "conversations" | "checkouts" | "restorePoints" … (22) |
| `freedBytes` Space the removals gave back, in… | number |
| `removed` How many items were removed | number |
| `kept` How many were left in place:… | number |
| `failed` How many removals the filesystem refused | number |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/storage/clean" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"category":"workspace"}'
```

TypeScript

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

const result = await sandbox.system.cleanStorage({
 "category": "workspace"
});
```

**GET`/system/terminals` Open terminals**

The terminal sessions this sandbox is holding, which is what a terminal panel rebuilds its tabs from after a reload. The live typing and output run over a separate socket; this is the list.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `sessions` Every live surface the sandbox is… | object[] |
| `name` Its id, and what the close… | string |
| `label` What to call it on screen | string |
| `kind` What sort of thing it is:… | "shell" | "panel" | "agent" | "job" … (5) |
| `running` Whether it is alive | boolean |
| `activityAt` When it last produced output, in… | number |
| `exitCode` How the last thing in it… | number |
| `command` What is running in it right… | string |
| `extensionId` Which extension declared this process, when… | string |
| `processName` Which of that extension's processes it… | string |
| `help` The agent has stopped at something… | object |
| `requestId` What to send back when you… | string |
| `message` What the agent needs, in its… | string |
| `requestedAt` When it asked, in milliseconds | number |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/terminals" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.terminals();
```

**DELETE`/system/terminals/{name}` Close a terminal**

Destroys one terminal session and whatever was running inside it.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `name` required Which terminal | string | address |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X DELETE "$SANDBOX/system/terminals/nightly%20changelog" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.killTerminal({
 "name": "nightly changelog"
});
```

**GET`/system/terminals/{name}/scrollback` A terminal's history as plain text**

What has scrolled past in one terminal, as text you can select and copy. The live view is a picture of a screen on the far side of a socket, with nothing in the page to select, so scrolling back and copying is this call rather than a gesture.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `name` required Which terminal | string | address |
| `lines` How far back to ask for | number | query |

### What comes back

| Field | Type |
| --- | --- |
| `name` Which terminal this is from | string |
| `text` The history, oldest line first, with… | string |
| `lines` How many lines you got | number |
| `truncated` It stopped because you asked for… | boolean |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/terminals/nightly%20changelog/scrollback" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.terminalScrollback({
 "name": "nightly changelog"
});
```

**GET`/system/browsers` Browsers the agent has open**

Every browser a conversation currently has running and the pages inside each one. The picture of what they are showing comes over a separate socket; this is the roster.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `sessions` Every browser the agents have running,… | object[] |
| `name` Its id, and what the close… | string |
| `label` What to call it on screen:… | string |
| `server` Which browser drives it: the credential-free… | string |
| `running` Whether it is still open | boolean |
| `activityAt` When it last did anything, in… | number |
| `finishedAt` When it closed, in milliseconds | number |
| `help` The agent has hit something only… | object |
| `requestId` What to send back when you… | string |
| `message` What the agent needs, in its… | string |
| `requestedAt` When it asked, in milliseconds | number |
| `dialog` A dialog a page has open… | object |
| `pageId` Which page opened it | string |
| `kind` What it asks: an alert wants… | "alert" | "confirm" | "prompt" | "beforeunload" |
| `message` What the page says | string |
| `defaultValue` A prompt's prefilled answer | string |
| `pages` Every page it has open | object[] |
| `id` Stable for the life of the… | string |
| `title` The page's title | string |
| `url` Where it is | string |
| `active` The one the agent last touched,… | boolean |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/browsers" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.browsers();
```

**DELETE`/system/browsers/{name}` Shut a browser down**

Closes one of the agent's browsers. Its next attempt to use that browser then fails as though it had crashed, which is the honest account of somebody pulling the plug.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `name` required Which browser | string | address |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X DELETE "$SANDBOX/system/browsers/nightly%20changelog" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.closeBrowser({
 "name": "nightly changelog"
});
```

**GET`/system/desktop` The sandbox's own desktop**

Whether the sandbox's desktop is up, which display it is, and how many windows are open on it. The live picture of it comes over a separate socket; this says whether there is anything to see.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `running` Whether the desktop is up | boolean |
| `display` The X display it is, present… | string |
| `windows` How many windows are open on… | integer |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/desktop" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.desktop();
```

**GET`/system/subagents` Subagents the agents have started**

Every subagent that conversations the caller can see have delegated work to, whichever tool started it, with what each one is doing: all that are still working, and the most recent that have settled.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `sessions` The subagents conversations the caller can… | object[] |
| `id` The id of the tool call… | string |
| `kind` How it was started: in-process by… | "subagent" | "spawned" |
| `conversationId` The conversation whose turn started it,… | string |
| `agentType` What kind of subagent it is | string |
| `description` What it was asked to do,… | string |
| `model` Which model it runs on: the… | string |
| `effort` How hard it was told to… | string |
| `provider` Which provider serves it, for a… | string |
| `spawnDepth` How deep in the chain it… | number |
| `background` The parent carried on working instead… | boolean |
| `status` How it is going | "pending" | "running" | "blocked" | "completed" … (7) |
| `startedAt` When it started, in milliseconds | number |
| `endedAt` When it finished, in milliseconds | number |
| `activityAt` When it last did anything, in… | number |
| `tokens` What it has spent | number |
| `toolUses` How many tools it has used | number |
| `lastTool` The last one it reached for | string |
| `summary` Its report: what it concluded, without… | string |
| `error` Why it failed, when it did | string |
| `verification` Whether anything proved the work its… | object |
| `state` Whether anything proved its work: a… | "verified" | "unproven" | "failing" | "no-code" |
| `paths` The code files it changed, most… | string[] |
| `check` The command that spoke: the one… | string |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/subagents" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.subagents();
```

**GET`/system/devices` The machines you have connected**

Every computer this sandbox can see, whether it reached it through desktop sync or through a connected device, in one row per machine: what it says about itself, which sandboxes it holds, and what stopped it answering when nothing came back.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `devices` | object[] |
| `key` | string |
| `label` | string |
| `sync` | object |
| `machine` | string |
| `mode` | "sync" | "mirror" |
| `seenAt` | number |
| `machineId` | string |
| `environment` | string |
| `hostId` | string |
| `card` | string |
| `machineId` | string |
| `online` | boolean |
| `platform` | string |
| `facts` | object |
| `machineId` | string |
| `os` | string |
| `arch` | string |
| `shell` | string |
| `home` | string |
| `roots` | string[] |
| `engine` | object |
| `memoryBytes` | number |
| `cpus` | number |
| `hostname` | string |
| `wsl` | object |
| `distro` | string |
| `wslDistros` | string[] |
| `links` | object |
| `total` | number |
| `unreachable` | number |
| `unreachableSince` | number |
| `features` | string[] |
| `icOutOfDate` | string |
| `upkeep` | object |
| `at` | number |
| `found` | object |
| `fixed` | object |
| `skipped` | object[] |
| `agentVersion` | string |
| `lastSeen` | number |
| `report` | object |
| `machineId` | string |
| `hostname` | string |
| `os` | string |
| `wsl` | object |
| `distro` | string |
| `pairings` | object[] |
| `sandboxId` | string |
| `mode` | "sync" | "mirror" |
| `localDir` | string |
| `remoteDir` | string |
| `projectsHost` | boolean |
| `deliver` | "auto" | "off" |
| `mirroring` | "on" | "off" |
| `mutagenStatus` | string |
| `conflicts` | integer |
| `conflictedPaths` | object[] |
| `paused` | boolean |
| `backupStatus` | string |
| `ports` | object[] |
| `port` | integer |
| `host` | "127.0.0.1" | "::1" |
| `sandboxId` | string |
| `state` | "mirrored" | "held-by-sandbox" | "busy" | "ignored" |
| `heldBy` | string |
| `command` | string |
| `agent` | object |
| `running` | boolean |
| `pid` | integer |
| `installed` | string |
| `build` | string |
| `lastTickAt` | number |
| `capturedAt` | number |
| `sandboxes` | object[] |
| `slug` | string |
| `container` | string |
| `name` | string |
| `running` | boolean |
| `image` | string |
| `tunnelRunning` | boolean |
| `resources` | object |
| `memoryBytes` | number |
| `cpus` | number |
| `privileged` | boolean |
| `gpu` | boolean |
| `hostRuntime` | string[] |
| `overlayRuntime` | string[] |
| `shape` | object |
| `desired` | object |
| `saved` | object |
| `staged` | object |
| `image` | string |
| `version` | string |
| `channel` | string |
| `version` | string |
| `parked` | boolean |
| `probationUntil` | number |
| `lastUpdate` | object |
| `result` What happened | "updated" | "kept" | "restored" | "rolled-back" |
| `verb` What was asked for: update, rollback,… | string |
| `at` When it happened, in milliseconds | number |
| `from` The version (or, when it would… | string |
| `to` The version (or image) that was… | string |
| `reason` Why the host gave up on… | string |
| `log` Where the host kept the full… | string |
| `keepUntil` Until when the previous version stays… | number |
| `rollbackTargets` | object[] |
| `image` The local image a rollback would… | string |
| `version` What that image says it is | string |
| `download` The local pin is gone (pruned… | boolean |
| `keptElsewhere` | string |
| `keptElsewhereName` | string |
| `adoptedFrom` | string |
| `keeperSilentSince` | number |
| `gap` | "offline" | "scope-off" | "unreported" |

Try it answered in this tab

curl

```bash
curl "$SANDBOX/system/devices" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.devices();
```

**POST`/system/devices/{id}/sandboxes/{slug}` Drive a sandbox on one of your own devices stream**

Start, stop, restart, update, rebuild, roll back, reshape (its memory and CPU caps, privileged, GPU) or remove a sandbox running on a machine you own, relayed over the connection that machine holds open. The answer is a stream because the slowest of these takes minutes, and it is the same stream whichever you ask for. The daemon adds no opinion: the machine enforces its own permissions and a refusal arrives as the last line, in the machine's words, naming the switch to flip.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `id` required | string | address |
| `slug` required | string | address |
| `op` required | "start" | "stop" | "restart" | "prepare" … (17) | body |
| `hash` | string | body |
| `to` | string | body |
| `shape` | object | body |
| `memoryGib` required | integer | null | body |
| `cpus` required | integer | null | body |
| `privileged` required | boolean | body |
| `gpu` required | boolean | body |
| `when` | "now" | "nextRestart" | body |
| `resources` | object | body |
| `memoryGib` | integer | null | body |
| `cpus` | integer | null | body |
| `privileged` | boolean | body |
| `gpu` | boolean | body |
| `later` | boolean | body |
| `parentUrl` | string | body |
| `pair` | string | body |
| `setupCode` | string | body |
| `platformUrl` | string | body |
| `definition` | string | body |
| `overlay` | string | body |
| `overlayHash` | string | body |
| `resumeTurns` | boolean | body |

### What comes back

| Field | Type |
| --- | --- |
| `when event is "message"` | shape |
| `data` | object |
| `when kind is "line"` | shape |
| `text` | string |
| `when kind is "result"` | shape |
| `message` | string |
| `when kind is "error"` | shape |
| `message` | string |
| `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/system/devices/a1b2c3d4/sandboxes/nightly-changelog" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"op":"start","hash":"…","to":"src/server.ts","shape":{"memoryGib":1,"cpus":1,"privileged":true,"gpu":true},"when":"now","resources":{"memoryGib":1,"cpus":1,"privileged":true,"gpu":true},"later":true,"parentUrl":"https://sandbox-a1b2c3d4e5f6.intentic.dev","pair":"…","setupCode":"…","platformUrl":"https://sandbox-a1b2c3d4e5f6.intentic.dev","definition":"…","overlay":"…","overlayHash":"…","resumeTurns":true}'
```

TypeScript

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

const result = await sandbox.system.manageDeviceSandbox({
 "id": "a1b2c3d4",
 "slug": "nightly-changelog",
 "op": "start",
 "hash": "…",
 "to": "src/server.ts",
 "shape": {
 "memoryGib": 1,
 "cpus": 1,
 "privileged": true,
 "gpu": true
 },
 "when": "now",
 "resources": {
 "memoryGib": 1,
 "cpus": 1,
 "privileged": true,
 "gpu": true
 },
 "later": true,
 "parentUrl": "https://sandbox-a1b2c3d4e5f6.intentic.dev",
 "pair": "…",
 "setupCode": "…",
 "platformUrl": "https://sandbox-a1b2c3d4e5f6.intentic.dev",
 "definition": "…",
 "overlay": "…",
 "overlayHash": "…",
 "resumeTurns": true
});
```

**POST`/system/devices/{id}/commands/{command}` Run one of your device's own CLI actions**

Performs a named action on a machine you own by running its own intentic-machine command there — turning that device's port mirroring off, say — over the connection it holds open. The set of actions is fixed and the command line is built here from the name, never sent by the caller. The machine enforces its own permissions and a refusal comes back as its own sentence, naming the switch to flip.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `id` required | string | address |
| `command` required | "mirror-off" | "mirror-on" | "mirror-ignore" | "mirror-unignore" … (12) | address |
| `sandboxId` | string | body |
| `mode` | "sync" | "mirror" | body |
| `localDir` | string | body |
| `port` | integer | body |

### What comes back

| Field | Type |
| --- | --- |
| `ok` | boolean |
| `message` | string |
| `output` | string |
| `refused` | boolean |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/system/devices/a1b2c3d4/commands/mirror-off" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"sandboxId":"a1b2c3d4e5f6","mode":"sync","localDir":"…","port":5173}'
```

TypeScript

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

const result = await sandbox.system.runDeviceCommand({
 "id": "a1b2c3d4",
 "command": "mirror-off",
 "sandboxId": "a1b2c3d4e5f6",
 "mode": "sync",
 "localDir": "…",
 "port": 5173
});
```

**POST`/system/devices/{id}/agent/{op}` Update, restart, or clean up the links of the agent on one of your own devices stream**

Updates a machine you own to the current intentic-machine agent, restarts the loop it is running, or drops the links it holds to sandboxes that have stopped answering — over the connection that machine holds open. The answer is a stream of the run's own output — and it normally stops mid-run, because the agent's loop is what carries this connection: the work is detached from it first, so it finishes regardless, and the device's reported version is what confirms it. Takes the machine's "Run commands" permission, the same one a command typed there would.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `id` required | string | address |
| `op` required | "upgrade" | "restart" | "forget-unreachable" | address |

### What comes back

| Field | Type |
| --- | --- |
| `when event is "message"` | shape |
| `data` | object |
| `when kind is "line"` | shape |
| `text` | string |
| `when kind is "result"` | shape |
| `message` | string |
| `when kind is "error"` | shape |
| `message` | string |
| `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/system/devices/a1b2c3d4/agent/upgrade" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.system.runDeviceAgentFlow({
 "id": "a1b2c3d4",
 "op": "upgrade"
});
```

More in The sandbox itself

[Next Activity →](https://intentic.dev/api/activity/)
