Skip to main content
Loop.js is the framework for loop engineering. You state a Goal and what “done” means. The engine drives Rounds — an Execute agent works with fresh context, then a separate, skeptical Verify agent judges the result against the bar — until the Goal settles. Only that verdict, never the worker’s own claim, ends the loop. Run it from a terminal, put it on a schedule, or embed it in a product: same engine, same guarantees.
import { Loop } from "@loop.js/core"

const loop = Loop.define({
  goal: "Build a playable 2D platformer",
  verify: "It builds clean, `bun test` passes, and the game boots to a controllable character",
  limits: { rounds: 20, usd: 10 },
})

const run = loop.run()                        // self-drives; iterate to observe
for await (const e of run) {
  if (e.type === "verdict") console.log(e.round, e.ok, e.reason)
}

const exit = await run.done()
// { settled: true, verdict } — the judge said done, not the worker

What’s in the box

A judged loopstate a Goal, get Rounds driven to a settle — from the CLI, a schedule, or the typed API (Loop.define / loop.run / an event stream)
A separate judgea read-only Verify agent judges every Round; only its verdict settles the Loop
State on diskfresh context every Round, memory read back from disk — survives crashes and schedules
Declared guardsrounds / usd / timeout — tight by default; every ending is a typed Exit with its own exit code
One writerthe Lock (compare-and-set + heartbeat) makes any trigger cadence overlap-safe
Real schedulersloop cron installs into crontab / launchd / Task Scheduler — or Modal in the cloud; no daemon, ever

One Round, four beats

  1. Execute — an agent works toward the Goal inside the work tree (./workspace by default).
  2. Handoff — the agent leaves a note for the next Round: what it did, what it believes is left.
  3. Verify — a separate agent, read-only by default, judges the work against the bar. Its verdict is ok, or not-ok with a mandatory reason, or a give-up when the Goal can never pass.
  4. Persist — the verdict and the Round’s events land on disk (the Record and journal), so the next Round — or a crash, or next week’s scheduled run — picks up exactly here.
Only a Verify verdict settles a Loop. Limits — Rounds, dollars, wall clock — are runaway guards: they end a Run, they never mean “done”.

Why writer ≠ grader

An agent grading its own work passes it. loop.js separates the roles structurally: Verify runs with its own prompt, its own (cheaper, if you like) model, and read-only by default — the write tools are denied at the adapter, not by prompt discipline. It reads the Execute agent’s handoff digest first and escalates only when suspicious: inspecting the work tree, running the build, checking the transcript.

No daemon

loop.js runs nothing in the background. loop run drives Rounds in the foreground and exits; loop cron installs Entries into a real scheduler — crontab, launchd, Task Scheduler, or Modal — and a fired Entry simply runs loop run again. State lives on disk, so the loop is exactly as durable as your filesystem.

Quickstart

Scaffold a project and drive your first Goal to settled.

What is loop engineering

The practice loop.js is built for — and where it stands in it.