---
title: "Loops · intentic sandbox API"
description: "One conversation run again until it gets there, and the saved designs behind them. Every route in the loops group of the intentic sandbox API, with its input, its answer and a playground."
url: "https://intentic.dev/api/loops/"
---

Agents

# Loops

One conversation run again until it gets there, and the saved designs behind them

**On this page (6 sections)**

- [Every loop that has run](#loops-list)
- [Run a conversation until it is done](#loops-start)
- [Make this round the last](#loops-stop)
- [Saved loop designs](#loops-designs)
- [Create or replace a saved loop](#loops-saveDesign)
- [Delete a saved loop](#loops-removeDesign)

A loop repeats a conversation towards a goal until it converges or gives up. One half is what is running right now; the other is the designs somebody authored once and can point at a different job each time.

**GET`/loops` Every loop that has run**

The loops this workspace has run, newest first, kept after they end. Why it stopped on the fourth round is the question a loop gets read for, and the round-by-round history is the answer.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `loops` Every loop this workspace has run,… | object[] |
| `conversationId` The conversation to loop | string |
| `goal` What done means, in your words | string |
| `prompt` What each round is asked to… | string |
| `context` How each round meets the last | "fresh" | "continue" |
| `output` | object |
| `when kind is "none"` | shape |
| `when kind is "claim"` | shape |
| `when kind is "json"` | shape |
| `fields` The shape that answer has to… | object[] |
| `checks` What else has to be true,… | object[] |
| `when kind is "command"` | shape |
| `command` The command to run in the… | string |
| `when kind is "judge"` | shape |
| `rubric` What that judge is asked | string |
| `model` Which model judges | string |
| `maxIterations` How many rounds before it gives… | integer |
| `maxSpendUsd` A ceiling on what the whole… | number |
| `stallLimit` Stop after this many rounds in… | integer |
| `isolated` Whether it works in the conversation's… | boolean |
| `agent` Which provider the rounds run on | string |
| `harness` Which agentic loop they run on | "native" | "claude-code" |
| `account` Which account pays | string |
| `model` Which model | string |
| `actsAs` Which persona the rounds act as | string |
| `worktreeBase` Pin the private copy to these… | object[] |
| `repo` | string |
| `base` | string |
| `autoLand` Whether the work merges as it… | boolean |
| `state` How it ended, and each of… | "running" | "done" | "exhausted" | "stalled" … (7) |
| `startedAt` When it began, in milliseconds | number |
| `endedAt` When it ended, in milliseconds | number |
| `resumed` How many times the sandbox restarted… | integer |
| `detail` Why it ended, for the endings… | string |
| `iterations` Every round, in order | object[] |
| `n` Which round this was | integer |
| `at` When it ran, in milliseconds | number |
| `outcome` How the round ended, which is… | "continue" | "done" | "error" |
| `detail` What the check said, in its… | string |
| `costUsd` What the round cost, in dollars | number |
| `changed` Whether anything on disk moved | boolean |
| `sessionId` The session it ran on, and… | string |

Try it answered in this tab

curl

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

TypeScript

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

const result = await sandbox.loops.list();
```

**POST`/loops` Run a conversation until it is done**

Starts repeating a conversation towards a goal and answers straight away with the loop as recorded; the work carries on without you. The conversation need not exist yet, so run this until it passes can be the first thing you ever say to a new agent. A conversation already looping is refused.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required The conversation to loop | string | body |
| `goal` required What done means, in your words | string | body |
| `prompt` required What each round is asked to… | string | body |
| `context` required How each round meets the last | "fresh" | "continue" | body |
| `output` required | object | body |
| `when kind is "none"` | shape | body |
| `when kind is "claim"` | shape | body |
| `when kind is "json"` | shape | body |
| `fields` required The shape that answer has to… | object[] | body |
| `name` required | string | body |
| `type` required | "string" | "number" | "boolean" | "string[]" | body |
| `description` required | string | body |
| `required` required | boolean | body |
| `checks` required What else has to be true,… | object[] | body |
| `when kind is "command"` | shape | body |
| `command` required The command to run in the… | string | body |
| `when kind is "judge"` | shape | body |
| `rubric` required What that judge is asked | string | body |
| `model` Which model judges | string | body |
| `maxIterations` required How many rounds before it gives… | integer | body |
| `maxSpendUsd` A ceiling on what the whole… | number | body |
| `stallLimit` required Stop after this many rounds in… | integer | body |
| `isolated` required Whether it works in the conversation's… | boolean | body |
| `agent` Which provider the rounds run on | string | body |
| `harness` Which agentic loop they run on | "native" | "claude-code" | body |
| `account` Which account pays | string | body |
| `model` Which model | string | body |
| `actsAs` Which persona the rounds act as | string | body |
| `worktreeBase` Pin the private copy to these… | object[] | body |
| `repo` required | string | body |
| `base` required | string | body |
| `autoLand` Whether the work merges as it… | boolean | body |

### What comes back

| Field | Type |
| --- | --- |
| `conversationId` The conversation to loop | string |
| `goal` What done means, in your words | string |
| `prompt` What each round is asked to… | string |
| `context` How each round meets the last | "fresh" | "continue" |
| `output` | object |
| `when kind is "none"` | shape |
| `when kind is "claim"` | shape |
| `when kind is "json"` | shape |
| `fields` The shape that answer has to… | object[] |
| `name` | string |
| `type` | "string" | "number" | "boolean" | "string[]" |
| `description` | string |
| `required` | boolean |
| `checks` What else has to be true,… | object[] |
| `when kind is "command"` | shape |
| `command` The command to run in the… | string |
| `when kind is "judge"` | shape |
| `rubric` What that judge is asked | string |
| `model` Which model judges | string |
| `maxIterations` How many rounds before it gives… | integer |
| `maxSpendUsd` A ceiling on what the whole… | number |
| `stallLimit` Stop after this many rounds in… | integer |
| `isolated` Whether it works in the conversation's… | boolean |
| `agent` Which provider the rounds run on | string |
| `harness` Which agentic loop they run on | "native" | "claude-code" |
| `account` Which account pays | string |
| `model` Which model | string |
| `actsAs` Which persona the rounds act as | string |
| `worktreeBase` Pin the private copy to these… | object[] |
| `repo` | string |
| `base` | string |
| `autoLand` Whether the work merges as it… | boolean |
| `state` How it ended, and each of… | "running" | "done" | "exhausted" | "stalled" … (7) |
| `startedAt` When it began, in milliseconds | number |
| `endedAt` When it ended, in milliseconds | number |
| `resumed` How many times the sandbox restarted… | integer |
| `detail` Why it ended, for the endings… | string |
| `iterations` Every round, in order | object[] |
| `n` Which round this was | integer |
| `at` When it ran, in milliseconds | number |
| `outcome` How the round ended, which is… | "continue" | "done" | "error" |
| `detail` What the check said, in its… | string |
| `costUsd` What the round cost, in dollars | number |
| `changed` Whether anything on disk moved | boolean |
| `sessionId` The session it ran on, and… | string |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/loops" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"conversationId":"nightly-changelog","goal":"…","prompt":"Update the changelog for the last five commits.","context":"fresh","output":{"kind":"none"},"checks":[{"kind":"command","command":"pnpm dev"},{"kind":"command","command":"pnpm build"}],"maxIterations":1,"maxSpendUsd":1,"stallLimit":1,"isolated":true,"agent":"…","harness":"native","account":"work","model":"claude-sonnet-4-6","actsAs":"…","worktreeBase":[{"repo":"root","base":"…"},{"repo":"site","base":"…"}],"autoLand":true}'
```

TypeScript

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

const result = await sandbox.loops.start({
 "conversationId": "nightly-changelog",
 "goal": "…",
 "prompt": "Update the changelog for the last five commits.",
 "context": "fresh",
 "output": {
 "kind": "none"
 },
 "checks": [
 {
 "kind": "command",
 "command": "pnpm dev"
 },
 {
 "kind": "command",
 "command": "pnpm build"
 }
 ],
 "maxIterations": 1,
 "maxSpendUsd": 1,
 "stallLimit": 1,
 "isolated": true,
 "agent": "…",
 "harness": "native",
 "account": "work",
 "model": "claude-sonnet-4-6",
 "actsAs": "…",
 "worktreeBase": [
 {
 "repo": "root",
 "base": "…"
 },
 {
 "repo": "site",
 "base": "…"
 }
 ],
 "autoLand": true
});
```

**POST`/loops/{conversationId}/stop` Make this round the last**

Means do not start another round, not stop what is running. Somebody watching the sixth round do good work can say this is the last one without throwing that work away. To cut the current round off as well, stop the conversation too.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `conversationId` required Which conversation's loop | string | address |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/loops/nightly-changelog/stop" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

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

**GET`/loops/designs` Saved loop designs**

Loops somebody authored once and can point at a different job each time. A saved loop is the same loop with its goal left blank until you type one, not a different feature.

### What you send

Nothing. Call it as it is.

### What comes back

| Field | Type |
| --- | --- |
| `designs` Saved loops: the machinery with the… | object[] |
| `id` The design's id | string |
| `name` What to call it | string |
| `description` What it is for, in one… | string |
| `prompt` What each round is asked to… | string |
| `context` How each round meets the last:… | "fresh" | "continue" |
| `output` What it has to produce | object |
| `when kind is "none"` | shape |
| `when kind is "claim"` | shape |
| `when kind is "json"` | shape |
| `fields` The shape that answer has to… | object[] |
| `checks` What else has to be true | object[] |
| `when kind is "command"` | shape |
| `command` The command to run in the… | string |
| `when kind is "judge"` | shape |
| `rubric` What that judge is asked | string |
| `model` Which model judges | string |
| `maxIterations` How many rounds before it gives… | integer |
| `maxSpendUsd` A ceiling on what it may… | number |
| `stallLimit` Stop after this many rounds in… | integer |

Try it answered in this tab

curl

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

TypeScript

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

const result = await sandbox.loops.designs();
```

**POST`/loops/designs` Create or replace a saved loop**

Say which of the two you mean, so a name that happens to collide cannot silently overwrite somebody's work. A design that could never finish, with nothing to produce and nothing to check, is refused in the same words an ad-hoc loop would be: catching that at save time is the whole advantage of saving.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `design` required The design to write | object | body |
| `id` required The design's id | string | body |
| `name` required What to call it | string | body |
| `description` What it is for, in one… | string | body |
| `prompt` What each round is asked to… | string | body |
| `context` required How each round meets the last:… | "fresh" | "continue" | body |
| `output` required What it has to produce | object | body |
| `when kind is "none"` | shape | body |
| `when kind is "claim"` | shape | body |
| `when kind is "json"` | shape | body |
| `fields` required The shape that answer has to… | object[] | body |
| `checks` required What else has to be true | object[] | body |
| `when kind is "command"` | shape | body |
| `command` required The command to run in the… | string | body |
| `when kind is "judge"` | shape | body |
| `rubric` required What that judge is asked | string | body |
| `model` Which model judges | string | body |
| `maxIterations` required How many rounds before it gives… | integer | body |
| `maxSpendUsd` A ceiling on what it may… | number | body |
| `stallLimit` required Stop after this many rounds in… | integer | body |
| `create` required Whether you mean to make a… | boolean | body |

### What comes back

| Field | Type |
| --- | --- |
| `id` The design's id | string |
| `name` What to call it | string |
| `description` What it is for, in one… | string |
| `prompt` What each round is asked to… | string |
| `context` How each round meets the last:… | "fresh" | "continue" |
| `output` What it has to produce | object |
| `when kind is "none"` | shape |
| `when kind is "claim"` | shape |
| `when kind is "json"` | shape |
| `fields` The shape that answer has to… | object[] |
| `name` | string |
| `type` | "string" | "number" | "boolean" | "string[]" |
| `description` | string |
| `required` | boolean |
| `checks` What else has to be true | object[] |
| `when kind is "command"` | shape |
| `command` The command to run in the… | string |
| `when kind is "judge"` | shape |
| `rubric` What that judge is asked | string |
| `model` Which model judges | string |
| `maxIterations` How many rounds before it gives… | integer |
| `maxSpendUsd` A ceiling on what it may… | number |
| `stallLimit` Stop after this many rounds in… | integer |

Try it answered in this tab

curl

```bash
curl -X POST "$SANDBOX/loops/designs" \
 -H "x-intentic-control: $INTENTIC_TOKEN" \
 -H "content-type: application/json" \
 -d '{"design":{"id":"a1b2c3d4","name":"nightly changelog","description":"Runs every night and opens a pull request when anything changed.","prompt":"Update the changelog for the last five commits.","context":"fresh","output":{"kind":"none"},"checks":[{"kind":"command","command":"pnpm dev"},{"kind":"command","command":"pnpm build"}],"maxIterations":1,"maxSpendUsd":1,"stallLimit":1},"create":true}'
```

TypeScript

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

const result = await sandbox.loops.saveDesign({
 "design": {
 "id": "a1b2c3d4",
 "name": "nightly changelog",
 "description": "Runs every night and opens a pull request when anything changed.",
 "prompt": "Update the changelog for the last five commits.",
 "context": "fresh",
 "output": {
 "kind": "none"
 },
 "checks": [
 {
 "kind": "command",
 "command": "pnpm dev"
 },
 {
 "kind": "command",
 "command": "pnpm build"
 }
 ],
 "maxIterations": 1,
 "maxSpendUsd": 1,
 "stallLimit": 1
 },
 "create": true
});
```

**DELETE`/loops/designs/{id}` Delete a saved loop**

Removes the design. A loop already running from it keeps going on its own terms, because it took a copy of what it needed when it started.

### What you send

| Field | Type | Where |
| --- | --- | --- |
| `id` required Which saved loop | string | address |

### What comes back

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

Try it answered in this tab

curl

```bash
curl -X DELETE "$SANDBOX/loops/designs/a1b2c3d4" \
 -H "x-intentic-control: $INTENTIC_TOKEN"
```

TypeScript

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

const result = await sandbox.loops.removeDesign({
 "id": "a1b2c3d4"
});
```

More in Agents

[Previous ← Workflows](https://intentic.dev/api/workflows/)[Next Automations →](https://intentic.dev/api/automations/)
