# Loops: keep a goal moving

Megastructure Arc documentation

Give an Arc-managed agent an ongoing goal that Arc works through in repeated cycles, then read, steer, pause and stop it.

An Arc Loop is a persistent goal that one Arc-managed agent works through in repeated cycles in a Full Access room. Arc schedules each cycle, saves its result, and starts the next one after a delay until someone pauses or stops the loop or it reaches its cycle limit. Read this page before you create a loop, when you are the agent working a cycle, or when you need to change or stop one. Exact schemas are in the [loop tool reference](/arc/docs/mcp/loops).

## Choose a loop, a run or a task

| Use | When the work | Ends when |
| --- | --- | --- |
| A [task](/arc/docs/mcp/tasks) | is one tracked piece of work with an owner | its owner completes it |
| A [run](/arc/docs/guides/runs) | has a finite objective, possibly across several seats | its Done-when is met and `arc_complete_run` succeeds |
| A loop | is open-ended improvement or monitoring on one seat | someone stops it, or it pauses at a limit |

A loop never completes on its own. When its goal is met, the worker says so and stops the loop, or the operator does.

## Check what a loop needs

- **Full Access.** Creating, resuming, editing and restarting need a Full Access room. Pause and stop stay available after the room drops to Safe, within your room write permissions. If the room is Safe, ask the operator to switch it.
- **A managed worker.** The loop runs on an enabled Arc-managed seat: a local GGUF model, a self-hosted model server, or an API model. An external harness agent can create and control loops but cannot be the worker; it names a managed seat with `membership_id` or `agent_id`, found with [`arc_list_seats`](/arc/docs/mcp/runs#arc_list_seats).
- **A running daemon on an awake computer.** A cycle that came due while the computer slept runs once when it wakes; missed intervals do not pile up.
- **No dollar budget.** Loops take no spending limit. Bound the work with `max_cycles` and read cost a provider reports with [`arc_run_status`](/arc/docs/mcp/runs#arc_run_status).

## Create a loop

The four loop tools form the progressive group `loop`. If they are not in your tool list, call [`arc_search_tools`](/arc/docs/mcp/discovery#arc_search_tools) with the query `loop`.

```text
arc_create_loop {
  "title": "Improve onboarding",
  "brief": "Verify and fix one onboarding step per cycle. Preserve unrelated work. Report when a clean setup check passes end to end.",
  "interval_seconds": 60,
  "max_cycles": 5
}
```

Only `brief` is required (up to 20,000 characters). `room_id` defaults to your joined room and the worker defaults to your own managed seat. `interval_seconds` is the delay between cycles: default 30, range 1 to 86,400. An omitted `max_cycles` means unlimited cycles. Omitted `cycle_instructions` use the operator's Loop cycle default. The first cycle is scheduled at once, and the result carries the loop's `run_id`.

Keep the cadence and limits the operator gave you. Never create a child or replacement loop to get around an existing loop's limits.

## Work a cycle

Each cycle reaches the worker as a turn headed `[Arc loop <run_id>, cycle <n>]`. It contains the cycle instructions, the configured `max_cycles`, the goal and its boundaries, the last result, and up to three recent failed approaches. The system prompt also carries the Loop control prompt.

1. Inspect current files and Arc state before acting. Do not blindly repeat an action whose result is uncertain.
2. Do one bounded piece of work and leave evidence: a workspace change, an artifact, or a fitness verdict.
3. Record a failed approach with [`arc_remember`](/arc/docs/mcp/memory#arc_remember), tagged with the loop's `run_id`.
4. Call [`finish`](/arc/docs/reference/runtime#finish) with a summary. Arc saves it as the loop's last result and schedules the next cycle.

Do not call `arc_complete_run` for a loop; Arc refuses it. Do not dispatch loop work with `arc_run_seat`: Arc admits only the loop's current scheduled cycle. [`wait`](/arc/docs/reference/runtime#wait) ends your turn as waiting and keeps the current cycle open until the wait fires. A [`remind`](/arc/docs/reference/runtime#remind) continuation runs inside the loop without starting a new cycle.

## Read progress

`arc_list_loops` returns each loop's `run_id`, `status` (such as `running`, `paused` or `stopped`) and `revision`. Progress is in `metadata.loop`, including `cycle`, `last_result`, `next_run_at`, `waiting_reason`, `resume_blocked_reason`, `failed_approaches` and `instructions_revision`. The response's `defaults` hold the current Loop cycle and Loop control text. For turns, events and spend, call `arc_run_status` with the loop's `run_id`.

## Know why a loop paused

Arc pauses a loop and sets `waiting_reason` when:

| Cause | What to do |
| --- | --- |
| It reached `max_cycles` | Resume is refused. Raise `max_cycles` with a definition edit and resume, or restart. |
| Three finished cycles left no new evidence | Review the goal or approach before resuming. A workspace write, a fitness verdict, or an artifact other than a memory or session summary counts. |
| A runtime or connection failure repeated five times | Check the model connection. Retryable failures back off from 30 seconds up to 15 minutes first. |
| A cycle was interrupted, or its dispatch result is uncertain | Inspect the last action's effects before resuming; Arc does not replay it. |
| A cycle's wait was cancelled | Resume when ready. |
| A cycle ended unfinished for another reason | Read `last_result`, adjust, then resume. |

## Pause, resume or stop

```text
arc_control_loop {"run_id": "<run_id>", "action": "pause"}
```

The actions are `pause`, `resume` and `stop`. Pause keeps progress and limits and cancels the loop's running and queued work, including a cycle in progress, so record your result before you pause or stop from inside a cycle. Resume works only on a paused loop below its cycle limit, needs Full Access, and is refused while the seat is still running an action. Stop ends the loop for good; a stopped loop cannot resume, but you can edit or restart it.

## Change the cycle instructions

Read `instructions_revision` from `arc_list_loops`, then:

```text
arc_update_loop_instructions {
  "run_id": "<run_id>",
  "cycle_instructions": "Fix one failing onboarding check per cycle and record the check's output.",
  "expected_instructions_revision": 2
}
```

Replace `2` with the revision you read. New text applies from the next dispatch; work already running or queued keeps its instructions. The edit never changes the goal, limits, progress or control rules, and it works on stopped loops without restarting them. A stale revision is refused: reload, merge, and retry.

The operator owns two global prompts in Settings > Arc instructions. **Loop cycle** is the default text for new loops and for a loop's Reset to default; existing loops keep their own. **Loop control** joins every cycle's system prompt from the next cycle on, including queued ones; a cycle underway keeps its wording. Read both in `defaults`. Change them only when the operator asks, through the [built-in instructions routes](/arc/docs/http/builtin-instructions) with the ids `arc-loop-cycle` and `arc-loop-control`.

## Edit or restart a loop over HTTP

Full definition edits and restarts have no MCP tool. Both need Full Access, the loop's current `revision` as `expected_revision`, and a paused or stopped loop.

```json
{"expected_revision": 4, "max_cycles": 10, "interval_seconds": 120}
```

Replace `4` with the `revision` you read and send the body to `PATCH /v1/loops/<run_id>`. It accepts `title`, `brief`, `membership_id`, `interval_seconds`, `max_cycles` and `cycle_instructions`. Saving does not start work or reset counters, and a paused loop keeps its worker. `POST /v1/loops/<run_id>/restart` takes the same body and, once the old loop's work has settled, starts a new loop with a fresh cycle counter. `restarted_from_run_id` and `restarted_as_run_id` in `metadata.loop` link the two; each loop can be restarted once.

The MCP tools map to `GET` and `POST /v1/rooms/{id}/loops` (list and create, on the [room routes](/arc/docs/http/rooms) page), `POST /v1/loops/{id}/pause`, `/resume` and `/stop`, and `PATCH /v1/loops/{id}/instructions`.

## Related

- [Loop tools](/arc/docs/mcp/loops)
- [Loop HTTP routes](/arc/docs/http/loops)
- [Managed agents, runs and completion](/arc/docs/guides/runs)
- [Managed runtime tools](/arc/docs/reference/runtime)
- [State changes and wakes](/arc/docs/guides/events)
