# NanoPencil `/loop` Design

## Goal

`/loop` is an autonomous task runner, not a timer.

The feature is meant to keep the agent working on one goal until the goal is truly finished, the agent reports that it is blocked, the user stops the loop, or a safety limit is reached.

## User Commands

```text
/loop <goal>
/loop status
/loop stop
```

## Runtime Model

1. The user starts a loop with `/loop <goal>`.
2. The loop extension creates one active per-session loop controller.
3. The extension dispatches a loop-owned user message through `sendUserMessage(..., { deliverAs: "followUp" })`.
4. For loop-owned turns only, the extension injects loop-specific system instructions with `before_agent_start`.
5. At the end of the run, the assistant must emit:

```xml
<loop-state>{"status":"continue|complete|blocked","summary":"...","nextStep":"..."}</loop-state>
```

6. The extension parses that block on `agent_end`.
7. If the status is `continue`, the extension automatically dispatches the next iteration.
8. If the status is `complete` or `blocked`, the loop stops.

## Safety Rules

- Only one active loop is allowed per session.
- The default iteration cap is 25.
- The default consecutive-failure cap is 3.
- Missing or invalid `<loop-state>` output counts as a failure.
- Loop state is session-scoped and is cleared on shutdown or reload.

## Integration Points

- `extensions/defaults/loop/index.ts`
  Owns command handling and loop orchestration.
- `extensions/defaults/loop/loop-controller.ts`
  Tracks loop state, iteration count, failures, and terminal status.
- `extensions/defaults/loop/loop-parser.ts`
  Parses `/loop` commands.
- `core/runtime/agent-session.ts`
  Emits `agent_end` to extensions only after retry and compaction settle, so autonomous loops react to a stable post-run state.

## Important Behavior Notes

- This feature is not a durable background worker.
- Loop prompts are marked with a `[LOOP:<id>:<iteration>]` prefix so the extension can identify loop-owned turns.
- Stale queued loop prompts are filtered out if their owning loop is no longer active.
