intentic
Create your workspace
Agents

Loops

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

On this page(6 sections)

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/loopsEvery 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

FieldType
loopsEvery loop this workspace has run,…object[]
conversationIdThe conversation to loopstring
goalWhat done means, in your wordsstring
promptWhat each round is asked to…string
contextHow each round meets the last"fresh" | "continue"
outputobject
when kind is "none"shape
when kind is "claim"shape
when kind is "json"shape
fieldsThe shape that answer has to…object[]
checksWhat else has to be true,…object[]
when kind is "command"shape
commandThe command to run in the…string
when kind is "judge"shape
rubricWhat that judge is askedstring
modelWhich model judgesstring
maxIterationsHow many rounds before it gives…integer
maxSpendUsdA ceiling on what the whole…number
stallLimitStop after this many rounds in…integer
isolatedWhether it works in the conversation's…boolean
agentWhich provider the rounds run onstring
harnessWhich agentic loop they run on"native" | "claude-code"
accountWhich account paysstring
modelWhich modelstring
actsAsWhich persona the rounds act asstring
worktreeBasePin the private copy to these…object[]
repostring
basestring
autoLandWhether the work merges as it…boolean
stateHow it ended, and each of…"running" | "done" | "exhausted" | "stalled" … (7)
startedAtWhen it began, in millisecondsnumber
endedAtWhen it ended, in millisecondsnumber
resumedHow many times the sandbox restarted…integer
detailWhy it ended, for the endings…string
iterationsEvery round, in orderobject[]
nWhich round this wasinteger
atWhen it ran, in millisecondsnumber
outcomeHow the round ended, which is…"continue" | "done" | "error"
detailWhat the check said, in its…string
costUsdWhat the round cost, in dollarsnumber
changedWhether anything on disk movedboolean
sessionIdThe session it ran on, and…string
Try itanswered in this tab
curl
curl "$SANDBOX/loops" \
  -H "x-intentic-control: $INTENTIC_TOKEN"
TypeScript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.loops.list();
POST/loopsRun 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

FieldTypeWhere
conversationIdrequiredThe conversation to loopstringbody
goalrequiredWhat done means, in your wordsstringbody
promptrequiredWhat each round is asked to…stringbody
contextrequiredHow each round meets the last"fresh" | "continue"body
outputrequiredobjectbody
when kind is "none"shapebody
when kind is "claim"shapebody
when kind is "json"shapebody
fieldsrequiredThe shape that answer has to…object[]body
namerequiredstringbody
typerequired"string" | "number" | "boolean" | "string[]"body
descriptionrequiredstringbody
requiredrequiredbooleanbody
checksrequiredWhat else has to be true,…object[]body
when kind is "command"shapebody
commandrequiredThe command to run in the…stringbody
when kind is "judge"shapebody
rubricrequiredWhat that judge is askedstringbody
modelWhich model judgesstringbody
maxIterationsrequiredHow many rounds before it gives…integerbody
maxSpendUsdA ceiling on what the whole…numberbody
stallLimitrequiredStop after this many rounds in…integerbody
isolatedrequiredWhether it works in the conversation's…booleanbody
agentWhich provider the rounds run onstringbody
harnessWhich agentic loop they run on"native" | "claude-code"body
accountWhich account paysstringbody
modelWhich modelstringbody
actsAsWhich persona the rounds act asstringbody
worktreeBasePin the private copy to these…object[]body
reporequiredstringbody
baserequiredstringbody
autoLandWhether the work merges as it…booleanbody

What comes back

FieldType
conversationIdThe conversation to loopstring
goalWhat done means, in your wordsstring
promptWhat each round is asked to…string
contextHow each round meets the last"fresh" | "continue"
outputobject
when kind is "none"shape
when kind is "claim"shape
when kind is "json"shape
fieldsThe shape that answer has to…object[]
namestring
type"string" | "number" | "boolean" | "string[]"
descriptionstring
requiredboolean
checksWhat else has to be true,…object[]
when kind is "command"shape
commandThe command to run in the…string
when kind is "judge"shape
rubricWhat that judge is askedstring
modelWhich model judgesstring
maxIterationsHow many rounds before it gives…integer
maxSpendUsdA ceiling on what the whole…number
stallLimitStop after this many rounds in…integer
isolatedWhether it works in the conversation's…boolean
agentWhich provider the rounds run onstring
harnessWhich agentic loop they run on"native" | "claude-code"
accountWhich account paysstring
modelWhich modelstring
actsAsWhich persona the rounds act asstring
worktreeBasePin the private copy to these…object[]
repostring
basestring
autoLandWhether the work merges as it…boolean
stateHow it ended, and each of…"running" | "done" | "exhausted" | "stalled" … (7)
startedAtWhen it began, in millisecondsnumber
endedAtWhen it ended, in millisecondsnumber
resumedHow many times the sandbox restarted…integer
detailWhy it ended, for the endings…string
iterationsEvery round, in orderobject[]
nWhich round this wasinteger
atWhen it ran, in millisecondsnumber
outcomeHow the round ended, which is…"continue" | "done" | "error"
detailWhat the check said, in its…string
costUsdWhat the round cost, in dollarsnumber
changedWhether anything on disk movedboolean
sessionIdThe session it ran on, and…string
Try itanswered in this tab
curl
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
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}/stopMake 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

FieldTypeWhere
conversationIdrequiredWhich conversation's loopstringaddress

What comes back

FieldType
okAlways truetrue
Try itanswered in this tab
curl
curl -X POST "$SANDBOX/loops/nightly-changelog/stop" \
  -H "x-intentic-control: $INTENTIC_TOKEN"
TypeScript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.loops.stop({
  "conversationId": "nightly-changelog"
});
GET/loops/designsSaved 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

FieldType
designsSaved loops: the machinery with the…object[]
idThe design's idstring
nameWhat to call itstring
descriptionWhat it is for, in one…string
promptWhat each round is asked to…string
contextHow each round meets the last:…"fresh" | "continue"
outputWhat it has to produceobject
when kind is "none"shape
when kind is "claim"shape
when kind is "json"shape
fieldsThe shape that answer has to…object[]
checksWhat else has to be trueobject[]
when kind is "command"shape
commandThe command to run in the…string
when kind is "judge"shape
rubricWhat that judge is askedstring
modelWhich model judgesstring
maxIterationsHow many rounds before it gives…integer
maxSpendUsdA ceiling on what it may…number
stallLimitStop after this many rounds in…integer
Try itanswered in this tab
curl
curl "$SANDBOX/loops/designs" \
  -H "x-intentic-control: $INTENTIC_TOKEN"
TypeScript
import { sandbox } from "@intentic/sandbox-client";

const result = await sandbox.loops.designs();
POST/loops/designsCreate 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

FieldTypeWhere
designrequiredThe design to writeobjectbody
idrequiredThe design's idstringbody
namerequiredWhat to call itstringbody
descriptionWhat it is for, in one…stringbody
promptWhat each round is asked to…stringbody
contextrequiredHow each round meets the last:…"fresh" | "continue"body
outputrequiredWhat it has to produceobjectbody
when kind is "none"shapebody
when kind is "claim"shapebody
when kind is "json"shapebody
fieldsrequiredThe shape that answer has to…object[]body
checksrequiredWhat else has to be trueobject[]body
when kind is "command"shapebody
commandrequiredThe command to run in the…stringbody
when kind is "judge"shapebody
rubricrequiredWhat that judge is askedstringbody
modelWhich model judgesstringbody
maxIterationsrequiredHow many rounds before it gives…integerbody
maxSpendUsdA ceiling on what it may…numberbody
stallLimitrequiredStop after this many rounds in…integerbody
createrequiredWhether you mean to make a…booleanbody

What comes back

FieldType
idThe design's idstring
nameWhat to call itstring
descriptionWhat it is for, in one…string
promptWhat each round is asked to…string
contextHow each round meets the last:…"fresh" | "continue"
outputWhat it has to produceobject
when kind is "none"shape
when kind is "claim"shape
when kind is "json"shape
fieldsThe shape that answer has to…object[]
namestring
type"string" | "number" | "boolean" | "string[]"
descriptionstring
requiredboolean
checksWhat else has to be trueobject[]
when kind is "command"shape
commandThe command to run in the…string
when kind is "judge"shape
rubricWhat that judge is askedstring
modelWhich model judgesstring
maxIterationsHow many rounds before it gives…integer
maxSpendUsdA ceiling on what it may…number
stallLimitStop after this many rounds in…integer
Try itanswered in this tab
curl
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
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

FieldTypeWhere
idrequiredWhich saved loopstringaddress

What comes back

FieldType
okAlways truetrue
Try itanswered in this tab
curl
curl -X DELETE "$SANDBOX/loops/designs/a1b2c3d4" \
  -H "x-intentic-control: $INTENTIC_TOKEN"
TypeScript
import { sandbox } from "@intentic/sandbox-client";

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

Type to search every page, in the docs and the API reference.