Architecture overview¶
An unattended agent loop has one structural enemy: I/O and vendor quirks leaking into the logic that decides when to run, wait, or stop. cursorloop keeps that decision logic pure by building as an onion:
domain ← application ← infrastructure ← cli
↑ composition root: bootstrap.py
- domain — pure decision logic: the run-loop state machine, the capacity ADT, the budget ledger, completion verdicts. No I/O, no SDK imports, fully unit-testable.
- application — use cases and ports: the orchestration that a CLI or any
other driver calls, expressed against
Protocolinterfaces inapplication/ports.py. - infrastructure — the adapters: Cursor agent transport, the generated Cloud Agents REST client, git savepoints, config, logging/audit, the state bus and stream UI.
- cli — Typer commands that translate flags into use-case calls; nothing else lives there.
- bootstrap.py — the only place concrete adapters meet ports.
An import-linter contract enforces the onion in CI: domain imports nothing above it, and only bootstrap wires the layers together.