PatchLoop
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@PatchLoopThe tests are failing—find the bug, patch it, and rerun the suite."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Why
Coding agents are usually built on a framework, so the loop is a black box: how the agent recovers from errors, when it stops, what it costs and what it can touch are hidden. PatchLoop is the whole thing, small enough to read:
the agent loop is about 200 readable lines with no agent framework: budgets, retries, loop detection, context compaction and a trajectory log are all visible code;
model-written commands never touch the host: every tool call runs in a disposable container with no network, read-only tests and resource limits, and the boundary is tested;
every claim is measured on a benchmark built by injecting validated bugs into two real libraries, with confidence intervals and a paired significance test.
Everything runs locally for free: no API keys and no paid services.
Related MCP server: opencode-sandbox
Results
72 episodes (36 tasks × 2 toolsets), local qwen3:8b via Ollama with thinking off, on an Apple M5 laptop,
2026-10-23/24. 95% Wilson intervals in brackets. Full report: docs/EVAL_REPORT.md ·
annotated failures: docs/EVAL_ANALYSIS.md · raw data: results/.
Run | Toolset | Resolved | Edited the buggy file | Mean time / task | Cost |
E1 | structured: | 12/36 = 33.3% [20, 50] | 20/36 | 240 s | $0 |
E2 |
| 3/36 = 8.3% [3, 22] | 10/36 | 308 s | $0 |
oracle | reverse-applies each injected bug (harness check) | 36/36 = 100% | — | — | $0 |
What it shows
The interface matters for a small model. On the same 36 tasks, 11 were solved only with the structured toolset and 2 only with bash (exact McNemar test, p = 0.022).
Finding the bug isn't the bottleneck; committing to a fix is. Every episode reached the buggy file. With
str_replacethe model edited it in 20/36 episodes; with raw bash, in 10/36. Most failures end with an empty patch.Context resets hurt. Episodes that needed compaction resolved 4/22 versus 8/14 without (E1). One trajectory shows the model re-reading the same file after each reset. That's correlation, not proof.
Thinking mode is impractical on a laptop GPU: with qwen3's thinking on, 0/5 tasks resolved, and every episode ran out of its 15-minute budget after 6–17 steps.
These are results for an 8B local model, not a frontier model: absolute rates aren't comparable to published agent benchmarks, and the toolset effect is model-dependent (strong models often do fine with bash alone).
How it works
flowchart LR
T["issue + test command"] --> P["build request<br/>system + task + append-only history"]
P --> M["model adapter<br/>Ollama · OpenAI-compatible · Anthropic · fake"]
M -->|tool calls| X["Toolbox"]
X -->|"docker exec, timeout"| S[("episode container<br/>no network · tests :ro")]
S -->|"truncated observation<br/>(errors are data)"| P
M -->|"submit / budget / loop / refusal"| G["git diff → grader<br/>in a fresh container"]One readable loop.
agent/loop.pyis a singlefor step in range(max_steps)with every exit going through onefinish(). Stop reasons:submitted,step_limit,cost_limit,time_limit,model_refusal,loop_detected,error.Append-only history. The provider's raw assistant content is replayed byte-for-byte, which keeps prompt caches warm and thinking blocks valid. When the prompt nears its limit, the model writes a progress summary and the loop starts a fresh list; it never edits history.
Failure modes handled in code. Transient API errors are retried with backoff and jitter. Tool errors and malformed calls go back to the model as observations. The same action 3 times in a row gets a nudge, and 5 times stops the episode. Every observation is truncated with an explicit marker.
An interface designed for the model.
str_replacerequires a unique exact match. When it fails, it shows the most similar region of the file so the model can copy it instead of re-typing code from memory (ADR-012).
Line-by-line walkthrough: docs/learning/LOOP_WALKTHROUGH.md · diagrams: docs/ARCHITECTURE.md · design records: docs/DECISIONS.md.
Sandbox
Protection | What it prevents |
| exfiltration, downloads, calling home |
| persistent changes outside the workspace |
tests bind-mounted | "fixing" the bug by changing the tests |
| root, setuid and capability escalation |
| memory and fork bombs, zombie build-up |
| hung commands |
fresh | reading the answer from |
a single | agent commands ever running on the host |
All of it is tested against a real container in
tests/integration/test_sandbox_security.py.
Benchmark
Targets: toolz 1.2.0 and boltons 26.2.0 (both BSD-3), pinned by commit. Each full test suite runs in under 2 s (ADR-004).
Strategy A, syntax-tree mutations: flip a comparison, off-by-one, negate a condition, swap arguments, remove a guard, change a constant, swap
and/or. One site per bug, spliced into the original formatting.Validation: the original passes; the mutated repo fails specific tests (FAIL_TO_PASS) while the rest pass (PASS_TO_PASS), identically on two runs; duplicates and bugs breaking over 25% of the suite are rejected.
Bug reports are written from failing test names and assertion output only, never from the diff. A leak check rejects any report that names the file, the line or the changed code.
36 tasks (18 per library). Strategy B (a model rewrites a function with one subtle bug) produced 6 more validated tasks with the local model, in
bench/tasks_llm/. They aren't evaluated yet (ADR-013).
Quickstart
Requirements: Docker, uv, and Ollama for real-model runs.
git clone https://github.com/varad-oss/patchloop.git && cd patchloop
make setup && make images # Python env + sandbox images (a few minutes, once)
make demo # a scripted model fixes a toy bug in the sandbox; no model neededRun the real agent on the benchmark, for free:
make local-model # pulls qwen3:8b (~5 GB) and builds the 16K-context variant
make eval-local RUN=E1 # 36 tasks, about 2.5 h on an Apple M5
make progress # live progress bar, current step and time leftpatchloop commands below assume the environment is active (source .venv/bin/activate).
Then patchloop report --run-id E1 writes a summary and results/E1/viewer.html, a page with every step of every
episode. With an Anthropic key in .env, make eval-pilot RUN=E1 MODEL=claude-haiku-5-5 measures the cost on 3
tasks before anything larger runs.
Reproducing the numbers
Command | What it does | Time |
| 85 unit tests (no Docker, no model, no network) | seconds |
| 16 sandbox-security, end-to-end and MCP tests against real containers | ~20 s |
| regenerates and validates the 36 tasks (no model) | a few minutes |
| harness check: must resolve 36/36 | ~3 min |
| thinking-on check, then E1 and E2 on local qwen3 | ~7 h |
| regenerates docs/EVAL_REPORT.md, the chart, and the viewers from | seconds |
| renders a trajectory as the GIF above | seconds |
MCP server
The same sandboxed tools are available to any MCP client, such as Claude Code or Claude Desktop, built on the official Python SDK v2. Each session gets its own container, created lazily and removed when idle:
claude mcp add patchloop -- "$(pwd)/.venv/bin/python" -m patchloop.mcp_server.serverRecorded demo: docs/MCP_DEMO.md shows Claude Code, with all built-in tools disabled, fixing
the toy bug through the server in 8 turns, and being refused (Read-only file system) when it tries to edit a test.
Config for Claude Desktop, a risk analysis (tool poisoning, over-broad permissions) and the reproducible demo command:
docs/MCP.md.
Project structure
src/patchloop/
agent/ loop.py (the loop) · models.py (adapters, pricing) · tools.py (6 tools)
context.py (compaction) · prompts.py · trajectory.py (JSONL)
sandbox/ docker_env.py (one locked-down container per episode) · images/ (Dockerfiles)
benchgen/ mutators.py (strategy A) · llm_rewrite.py (strategy B) · validate.py · issues.py · build.py
evals/ runner.py · grader.py · metrics.py · report.py · replay.py · viewer/
mcp_server/ server.py
bench/tasks/ the 36 benchmark tasks bench/tasks_llm/ strategy-B tasks
results/ committed episodes and trajectories behind every number
docs/ report, analysis, architecture, decisions, MCP, learning notes (M0-M7)
tests/ unit/ (offline) and integration/ (Docker)Limitations
One small local model. Results are for qwen3:8b, one trial per task; intervals are wide.
Synthetic bugs. Mostly single-line mutations, easier to localize than real-world bugs.
Contamination. Both libraries are surely in the model's training data. The bugs are new, but the original code is familiar.
Template bug reports read like CI logs. A review of 10 found all reproducible and leak-free, but 6/10 titles name test functions rather than real APIs (review).
Docker is the isolation boundary. A kernel or container-runtime escape would defeat it; a microVM (gVisor, Firecracker) would be stronger.
Roadmap
Evaluate the strategy-B tasks, and grow them past 10 with a stronger model.
Best-of-k with test-based selection, reported as pass@k and pass^k (implemented, not run).
Repeat E1/E2 with a stronger model to test whether the interface effect shrinks.
Real-bug tasks mined from the libraries' own history.
More natural bug reports: titles from real API names, and LLM-written prose behind the same leak check.
Credits
Built by Varad Rajiv Pandare, with Claude Code as a pair programmer, from my specification and under my direction. Benchmark design, experiments and analysis are mine.
Ideas drawn from SWE-bench (FAIL_TO_PASS / PASS_TO_PASS grading), SWE-agent (agent-computer interface design), mini-SWE-agent (linear history, stateless bash) and SWE-smith (LLM-rewrite bug generation).
License
This server cannot be deployed
Maintenance
Related MCP Connectors
- briqOAuthcloud.briq
Give your agent its own cloud: Postgres, Redis, a sandbox or any Docker image, in one MCP call.
Persistent memory and cross-session learning for AI coding assistants (hosted remote MCP).
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Remote MCP learning coach for coding agents.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI clients to securely operate isolated coding workspaces with file, command, Git, and deployment tools via authenticated remote MCP.93MIT
- AlicenseNot gradedqualityAmaintenanceSpins up isolated opencode instances in Docker containers as MCP servers, providing 80 tools for file and shell operations within a scoped workspace without exposing the host filesystem.176 npmMIT
- AlicenseNot gradedqualityBmaintenanceGives any MCP-compatible AI chat or agent a safe, model-neutral coding runtime with file read/search, structured multi-file patches, command execution, interactive sessions, and git operations, all confined to a single workspace and gated by permission modes.Apache 2.0
- AlicenseAqualityBmaintenanceEnables AI agents to perform software engineering tasks inside an isolated, deterministic sandbox—exploring repositories, reproducing failures, applying patches, running tests, and verifying solutions against hidden suites through MCP tools.8MIT