Skip to main content
All modules

AssistantAgent loops

Goal loop

A workspace that works on one goal continuously. Each turn runs in a fresh chat, does one task, logs what it verified, and hands off to a successor. You set the goal and the ground truth.

goal.mdMarkdown
# Goal

<!-- Locked so no agent can rewrite its own objective. Locks only stop agents: you can edit this file directly, or unlock it from the file tree if you want agent help writing it. -->

## What we are trying to achieve

One paragraph, written for someone with no context. Replace this.

## Ground truth

The check that decides whether a task actually worked. A command whose exit code is the verdict, a test suite, a number that has to move. Name it precisely. Agents will treat anything else as an unverified guess.

## Done means

The condition that ends the loop. When this is true, the agent writes a final entry in `attempts.md` and stops spawning successors.

## Out of bounds

Anything the loop must not touch or claim. Cost ceilings, files to leave alone, things only a human decides.
attempts.mdMarkdown
# Attempts

Log of every loop turn, newest first: new entries go directly under this heading, above the older ones. Each turn reads only the top of the file rather than the whole history, so turn 100 costs what turn 1 does.

No entries yet. `AGENTS.md` defines what an entry looks like.

This workspace runs a continuous loop. Fill in goal.md (what we're going for, the check that proves a task worked, and what "done" means), put a first task in tasks.md, then say "start the loop". From there each turn takes one task, logs the result in attempts.md, and spawns its own successor. AGENTS.md and goal.md are locked so I can never rewrite my own instructions (you can still edit them; locks only stop agents). You can also watch from your phone: ask me and I'll set up texting so you can check on the loop from iMessage. Tell me what you're trying to get done and I'll draft goal.md content for you to paste in.

What’s inside

  • Starter files
  • attempts.md287 B
    # Attempts
    
    Log of every loop turn, newest first: new entries go directly under this heading, above the older ones. Each turn reads only the top of the file rather than the whole history, so turn 100 costs what turn 1 does.
    
    No entries yet. `AGENTS.md` defines what an entry looks like.
    
  • goal.mdopens first · locked · 799 B
    # Goal
    
    <!-- Locked so no agent can rewrite its own objective. Locks only stop agents: you can edit this file directly, or unlock it from the file tree if you want agent help writing it. -->
    
    ## What we are trying to achieve
    
    One paragraph, written for someone with no context. Replace this.
    
    ## Ground truth
    
    The check that decides whether a task actually worked. A command whose exit code is the verdict, a test suite, a number that has to move. Name it precisely. Agents will treat anything else as an unverified guess.
    
    ## Done means
    
    The condition that ends the loop. When this is true, the agent writes a final entry in `attempts.md` and stops spawning successors.
    
    ## Out of bounds
    
    Anything the loop must not touch or claim. Cost ceilings, files to leave alone, things only a human decides.
    
  • tasks.md371 B
    # Tasks
    
    The work queue. Agents take the topmost unblocked task, one per turn, and keep this file current. Humans can reorder or add anything at any time.
    
    ## Ready
    
    - [ ] Fill in `goal.md`, then replace this task with the first real one.
    
    ## Blocked
    
    Move a task here with the reason it is stuck and who or what would unblock it.
    
    ## Done
    
    Completed tasks, newest last.
    
  • Libraries and docs
  • AGENTS.mdlocked · 5.4 KB
    # Loop protocol
    
    <!-- Locked so no agent can rewrite its own rules. Locks only stop agents: you can edit this file directly, or unlock it from the file tree if you want agent help writing it. -->
    
    This workspace runs a never-ending loop toward the goal in `goal.md`. Every turn is a fresh chat with no memory of the last one, so the files below are the only state that survives. Read them first, every time.
    
    `AGENTS.md` and `goal.md` are locked: you cannot edit them. Only a human can change the goal or these rules.
    
    ## The turn
    
    1. Read `goal.md`, then `tasks.md`, then `attempts.md` **with `limit: 60`**. That is your entire memory. `attempts.md` is newest-first, so the first 60 lines are the recent history; never read the whole file, it grows with every turn.
    2. If `goal.md`'s done condition is **already met**, write a final `attempts.md` entry explaining why, cancel this chat's schedules, and stop. Do not take a task and do not spawn. Confirming done is a whole turn's job.
    3. If your instructions say a heartbeat already exists, skip this step. Otherwise, if `attempts.md` has no `##` entries yet (the seeded file has none), you are the first turn: arm the workspace heartbeat with `schedule_create`: kind `every`, every 10 minutes (use a longer interval only if turns take longer than that), prompt: "Heartbeat. Read AGENTS.md. If goal.md's done condition is met, cancel this chat's schedules and stop. Otherwise call list_chats and judge liveness from OTHER CHATS ONLY: ignore this chat entirely, it is marked '(this chat)' and it is you running right now. The chain is alive if any OTHER chat is marked 'agent running' (whatever its timestamp - a turn can work for a long time without writing) OR shows activity within the last 10 minutes; then do nothing this firing and reply 'chain alive'. Only when no other chat is running and none has moved for 10 minutes is the chain dead: then spawn_chat a successor with the prompt 'Read AGENTS.md and run one loop turn. A heartbeat already exists - do not arm another.' (pass the model goal.md names, if any) - do not do loop work in this chat; it stays cheap." Later turns skip this step; the heartbeat already exists and restarts the chain if any turn dies.
    4. Pick exactly **one** task from `tasks.md`. Prefer the topmost unblocked one. If `attempts.md` or the files show it is already done, check it off and take the next one instead of redoing it. If a task has failed the same way twice in `attempts.md`, skip it and mark it blocked. If nothing is unblocked, add the follow-up tasks `goal.md` implies; if you truly cannot name one, write a final `attempts.md` entry saying the queue is empty and stop. Do not spawn.
    5. Do the task. Verify the result against the ground truth named in `goal.md`. An unverified change is a failed task.
    6. Add one entry to `attempts.md` **at the top**, directly under the `# Attempts` heading and above the previous entry. An entry is a `## <date> - <task>` heading followed by three short lines: **Tried:** what you did, **Verified:** what the ground-truth check reported, **Next:** what the following agent should know. At most a few lines; do not restate data the files already hold. Write the entry even when the task failed, especially then.
    7. Update `tasks.md`: check off what landed, add any follow-up work the attempt revealed, mark anything blocked with the reason.
    8. Hand off, last: `spawn_chat` with a self-contained prompt. The successor sees none of this conversation, so the prompt must be the instruction alone, e.g. "Read AGENTS.md and run one loop turn." If `goal.md` names a model for the loop and this chat is not on it, pass it as `model` (successors inherit, so this matters only when starting or reviving the chain). If `spawn_chat` returns an error, retry it once. If it still fails, stop; the heartbeat restarts the chain. Nothing else runs after this step.
    
    ## Rules
    
    - **One task per turn, even when the goal is one task from done.** Two tasks in one turn means the second one gets no fresh context and no review. After your one task, hand off; a turn that starts with the goal met is the one that declares done.
    - **State lives in files, never in chat.** If a fact matters to the next turn, it goes in `tasks.md` or `attempts.md` before you hand off.
    - **Never claim a result you did not verify.** "It should work" belongs in `attempts.md` as a failure.
    - **Never redo logged work.** If the newest `attempts.md` entry already covers the top task and the files agree, that work is done. Take the next task.
    - **Keep the log lean.** Long entries make every later turn slower, dearer, and likelier to fail mid-write. A few lines is plenty.
    - **One heartbeat per workspace, ever.** Two heartbeats can each mistake the other for a live chain and both stand down, leaving a dead loop unrevived. Only a genuine first turn arms one, and a turn the heartbeat started never does.
    - **Never run two branches at once.** If you were started by the heartbeat and another chat is running or has been active in the last 10 minutes, the chain is alive: stop immediately rather than starting a second branch. Two branches racing on the same files is worse than a paused loop. When judging that, never count your own chat as evidence of a live chain.
    - **Spawn exactly once, at the very end.** The tools are named exactly `spawn_chat`, `schedule_create`, `schedule_list`, `schedule_cancel`, `list_chats`, lowercase, as written.
    
    If the chain ever stalls, a human can restart it by sending "Read AGENTS.md and run one loop turn." in any chat here.