Harness-agnostic, self-verifying autonomy wrapper for coding agents
Project description
Stop paying for agents that never finish.
AgentLoop makes your coding agent actually complete tasks correctly — or it keeps going. No false "DONE." No wasted API calls.
agentloop "build a JSON linter" --verify "bash verify.sh"
Free. MIT licensed. Free models. No API key needed. Works with OpenCode, Claude Code, Aider, Goose, and more.
You already know the pain.
Coding agents are famous for stopping halfway and claiming they're done.
OpenCode issue #24685. The "stopped halfway" essays. You've been there:
- The agent writes 80% of the code, then quits. Your loop thinks it won.
- You bake test cases into your check script — now the agent overfits, passing those exact cases but failing on everything else. (This is the SWE-bench false-green bug, and it's real.)
- Your API bill keeps climbing while nothing ships.
You've probably thought: "I'll just write a 20-line bash loop."
That doesn't work either. A naive loop can't tell the difference between "the agent said DONE" and "the agent actually solved the problem." You need a verification oracle — a correctness gate the agent can't fake, edit, or overfit to.
That's what AgentLoop is.
The verification oracle is the product.
AgentLoop is not a coding agent and not another BYOK wrapper. It's a thin, harness-agnostic layer that wraps the agent you already use:
goal + feedback ──► your agent edits the sandbox ──► verification oracle
▲ │
└────────────── (fail) ◄───────────────────────────┘
(pass) ──► DONE (and a sealed oracle agrees)
Three things it adds that people keep rebuilding by hand:
- Continuity — loops until the goal is proven correct, not "please clarify"
- The verification oracle — a correctness gate, not "it runs and prints"
- Safety — your API key never reaches the agent; work is git-checkpointed and crash-resumable
"Wait — a naive loop can't tell if the work is correct."
Correct. That's why AgentLoop exists.
The held-out oracle (your moat against overfitting)
A plain verifier can still be gamed if the agent reverse-engineers the test cases. AgentLoop's sealed, held-out grading defeats that:
# 1) Auto-generate fresh test inputs from a reference program
python oracle.py gen --reference "python ref.py" --n 200 --out cases.txt --seed 42
# 2) Record the reference's behavior — split into visible + held-out (sealed)
python oracle.py record \
--reference "python ref.py" --inputs cases.txt --visible 3 \
--out .agentloop/oracle_sealed/oracle.json --seal "$ORACLE_SEAL"
# 3) The verifier grades the candidate against ALL inputs
# The candidate only PASSES if it's correct on inputs it has NEVER seen
python oracle.py grade \
--candidate "python sandbox/solution.py" \
--oracle .agentloop/oracle_sealed/oracle.json --seal "$ORACLE_SEAL"
A wrong --seal makes grading report TAMPERED. The held-out file lives outside the sandbox — the agent can't read it, can't overfit to it. This is the feature that makes AgentLoop worth using over a hand-rolled loop.
Install in 5 seconds.
From PyPI (recommended):
pip install agentloop-cli
agentloop --init
./launch.sh
Or from source:
git clone https://github.com/instax-dutta/agentloop.git && cd agentloop
pip install -e "."
agentloop --init
./launch.sh
That's it. No API key. No .env to copy. No config to edit.
agentloop --init creates everything you need:
goal.txt— a hello-world taskverify.sh— a working verifier, ready to run.env— zero-config defaults
Need Windows?
.\launch.ps1 # start the loop (background job)
.\stop.ps1 # stop gracefully
Try a real example instead:
agentloop --init --example tax-demo
# Seeds: goal.txt + verify.sh from the tax-demo example
Or jump straight in:
agentloop "build a JSON linter" --verify "bash verify.sh"
Preview your setup before running:
agentloop --dry-run
# Shows: mode, agent command, verify command, goal, limits, version — no loop starts
Run multiple tasks at once:
agentloop --run plan.md
Parses any markdown plan — checklists, bullets, headings — and spawns one loop per task.
Check your version:
agentloop --version
# agentloop 0.3.0
It survives crashes.
Your laptop dies mid-run. Your SSH session drops. Your CI runner gets recycled.
AgentLoop resumes exactly where it stopped.
# Same command, same goal:
agentloop --verify "bash verify.sh"
# Output:
# resuming from iter 2 (cost so far: $0.10)
Every iteration is written atomically to agentloop.state.json. A crash leaves zero torn state. The wall clock tracks from the original start — not the resume time — so timeouts are fair.
Don't let a runaway API bill surprise you.
Set a hard cost cap in dollars. If the agent exceeds it, the loop stops with status=over-budget:
MAX_COST_USD=5 agentloop "my task" --verify "bash verify.sh"
Tracks running cost in agentloop.state.json. In CLI mode, set ESTIMATED_COST_PER_ITER ($0.10 default). In direct mode, actual token counts are used automatically.
Logs rotate automatically.
Set LOG_MAX_MB in .env (default 10 MB) with 3 backup files via Python's RotatingFileHandler. No more gigabyte log files.
Know exactly what's happening.
agentloop --status # terminal display: status, iters, elapsed, cost, PID
agentloop --serve # web UI at http://localhost:8080 (auto-refresh 5s)
agentloop --serve --port 9090 # custom port
Get notified when it finishes.
Send terminal-state summaries wherever you work:
# Telegram
NOTIFY_TELEGRAM_BOT_TOKEN=123456:ABC-DEF
NOTIFY_TELEGRAM_CHAT_ID=-1001234567890
# Discord (webhook URL)
NOTIFY_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
# Slack (webhook URL)
NOTIFY_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
# Or any shell command
NOTIFY_CMD='curl -s -X POST https://hooks.example.com -d "{kind}: {msg}"'
Supports: completed, blocked, stopped, timeout, over-budget — each routed through your preferred channel.
Works with whatever agent you use.
| Preset | Command |
|---|---|
| opencode | opencode run "$AGENTLOOP_PROMPT" --auto |
| kilocode | kilocode run "$AGENTLOOP_PROMPT" |
| claude | claude -p "$AGENTLOOP_PROMPT" --dangerously-skip-permissions |
| aider | aider --message "$AGENTLOOP_PROMPT" --yes |
| codex | codex exec "$AGENTLOOP_PROMPT" |
| goose | goose run "$AGENTLOOP_PROMPT" |
No preset matching yours? Set AGENT_CMD to any command. The prompt is injected via $AGENTLOOP_PROMPT.
AGENT_CMD='my-agent run "$AGENTLOOP_PROMPT"'
If no preset is set, AgentLoop auto-detects an installed CLI with a version check — and warns you if it finds a broken binary.
Hidden strength: Because AgentLoop re-invokes the harness every iteration, a harness that "stops halfway" just becomes one failed iteration. The loop absorbs it and keeps going.
What's in the box.
| File | What it does |
|---|---|
agentloop.py |
Orchestrator — CLI mode, direct mode, resume, notifications, web UI |
oracle.py |
Verification oracle — sealed held-out grading, input generation |
verify.sh / verify_template.sh |
Example verifier + scaffold template |
mock_agent.sh |
Deterministic agent stand-in (for tests) |
launch.sh / stop.sh |
Linux/Mac launcher scripts |
launch.ps1 / stop.ps1 |
Windows PowerShell launchers |
examples/ |
3 working verifier samples — tax-demo, JSON linter, refactor-regression |
.pre-commit-config.yaml |
Ruff linting + formatting hooks for contributors |
Real examples. Real verifiers.
The examples/ directory shows three different approaches:
| Example | What it teaches |
|---|---|
tax-demo/ |
Fixed test cases in bash — a simple, effective oracle |
json-linter/ |
Temporary test files generated per iteration |
refactor-regression/ |
Held-out oracle — gen + record + grade workflow (the moat) |
Each has a goal.txt (the task) and verify.sh (the oracle). Run ./verify.sh to see how the oracle works without the loop.
Exit codes (for CI / scripting).
| Status | Code | Meaning |
|---|---|---|
| completed | 0 | Goal met, verification passed |
| blocked | 1 | Agent gave up |
| config / missing agent | 2 | Something isn't set up |
| timeout | 3 | Wall-clock limit hit |
| exhausted | 4 | Max iterations reached |
| over-budget | 5 | Cost cap exceeded |
| stopped | 130 | SIGTERM/SIGINT / STOP file |
The fine print.
- The wrapped agent runs with
cwd=sandbox. For hard isolation, use a container (see ISSUES.md). - Without
VERIFY_CMD, the loop falls back on aDONE/BLOCKEDsignal from the agent — use a real verifier. - Each CLI iteration is a fresh agent invocation. Continuity is maintained by feeding the goal + last failure back.
- Keep the held-out case file outside the sandbox. The seal is a tamper signal, not absolute security.
- API keys and
ORACLE_SEALare stripped from the agent environment. Never put secrets inside the sandbox.
Tests (deterministic, no LLM required)
python3 test_oracle.py # verification gate + held-out oracle
python3 test_loop.py # full loop with mock agent + cost cap + status
Both pass on every commit. CI runs them on Linux (Python 3.10/3.12/3.13).
Pre-commit hooks (for contributors)
pip install -e '.[dev]'
pre-commit install
AgentLoop is 0.3.0. MIT licensed. One file. One purpose: make your agent actually finish.
agentloop "build a JSON linter" --verify "bash verify.sh"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentloop_cli-0.4.0.tar.gz.
File metadata
- Download URL: agentloop_cli-0.4.0.tar.gz
- Upload date:
- Size: 42.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f4efb61d6a439f25f115da401a5da74c44a457d145a5d2fdd31797a002e454c
|
|
| MD5 |
ce0ccbdb0e3d0590133614fe4cc5fa64
|
|
| BLAKE2b-256 |
6f3a8f3a8ef164ac3f62197b03cc251bfb25de1b37b2f3e7159101e6a2e4160a
|
File details
Details for the file agentloop_cli-0.4.0-py3-none-any.whl.
File metadata
- Download URL: agentloop_cli-0.4.0-py3-none-any.whl
- Upload date:
- Size: 40.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7172ef9ee14915e153045d90f71e4b700d3e69dbeb54ceae1d87addc6e128abc
|
|
| MD5 |
0ec979b70471dffbc2f52bc814e9405d
|
|
| BLAKE2b-256 |
a292d0dd00ef2f79bf4479f2873959b489a7fa0147d6a30f5ddc338c04d02b67
|