An agent burned most of a token grant last week. The patch was small and looked clean. The test output was enormous. The agent kept reading unrelated failures. It kept revising the wrong code.
That pattern is becoming the default. Agent patches are generated to look plausible. They satisfy the tests in front of them. They rarely satisfy the invariants behind them. And the verification loop wastes tokens on noise.
The fix is a gate that spends tokens carefully. It selects tests by blast radius. It runs property checks and fixtures. It freezes flaky failures. It prints a short failure summary for the agent to read. Every part of the gate exists to save tokens.
Start with test selection. A parser patch does not need the billing suite. A schema change does not need the parser property tests. Map changed files to test directories. Run only what the patch can break.
import subprocess
import sys
from pathlib import Path
def select_tests(diff_path="HEAD"):
"""Map changed files to test paths. Cheap blast-radius selection."""
changed = subprocess.run(
["git", "diff", "--name-only", diff_path],
capture_output=True, text=True,
).stdout.splitlines()
selected = set()
for path in changed:
if "parser" in path:
selected.add("tests/property/test_parser.py")
if "schema" in path:
selected.add("tests/fixtures/")
if "api" in path:
selected.add("tests/integration/")
return list(selected) or ["tests/unit/"]
def run_selected(selected):
cmd = ["pytest", *selected, "-q"]
return subprocess.run(cmd, capture_output=True, text=True)
The mapping is crude. It is also honest. You extend it as your repo teaches you which files break together.
Then freeze the flaky noise. Every repo has flaky tests. They fail for reasons unrelated to the patch. Without a freeze, they block the gate with noise. The freeze is a file that lists known-flaky tests. The gate ignores listed failures. It blocks unlisted ones.
FLAKY_FREEZE = Path("flaky_freeze.txt")
def load_freeze():
if not FLAKY_FREEZE.exists():
return set()
return {line.strip() for line in FLAKY_FREEZE.read_text().splitlines() if line.strip()}
def new_failures(output, frozen):
failed = [line for line in output.splitlines() if "FAILED" in line]
return [f for f in failed if f not in frozen]
Then compress the output. The agent reads the gate output. Every token it reads is a token it cannot spend on the next revision. A wall of tracebacks is expensive. A short summary is cheap.
def summarize(failures):
"""One line per failure. Enough for the agent to act."""
if not failures:
return "Gate passed."
lines = ["Gate blocked. New failures:"]
lines.extend(failures)
lines.append("Fix these, then rerun the gate.")
return "\n".join(lines)
The full gate ties it together.
def main():
frozen = load_freeze()
selected = select_tests()
result = run_selected(selected)
if result.returncode != 0:
failures = new_failures(result.stdout, frozen)
print(summarize(failures))
sys.exit(1)
print("Gate passed.")
That is the whole loop. The gate selects, runs, freezes, and summarizes. The agent gets a short, actionable failure list. The token cost per iteration stays low.
Where to run it. A gate needs a server. Agent workflows need tokens. Both cost money. This is where the economics change.
MonkeyCode is an open-source AI coding tool. It offers free model access with a 10 million token grant and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
The loop becomes simple. The agent proposes a patch using the free token grant. The gate runs on the free server. The gate fails. The agent reads the short summary and revises. The revision also comes from the free grant. The loop costs zero dollars.
A cron job keeps the gate honest.
0 2 * * * cd /srv/agent-patches && ./patch_gate.py >> gate.log 2>&1
Track the budget. A 10 million token grant sounds large. It disappears faster than you expect. A single revision can consume thousands of tokens. The test run itself consumes none. The agent reading the output does. Track the budget like you track disk space.
def estimate_tokens(text):
# Rough heuristic: one token per four characters.
return len(text) // 4
The heuristic is not exact. Tokenizers are not that simple. But the number gives you a trend. Trends matter more than precision when a grant is finite.
Who should not use this. The gate checks behavior, not design. A patch can pass every check and still be the wrong abstraction. It is not a substitute for review.
The gate is also not for regulated environments. If you need audit trails and signed approvals, a cron job on a free server will not satisfy compliance. Use the pattern, not the infrastructure.
And if your tests are already slow, the gate inherits that slowness. Fix the slow tests first. A gate that nobody runs is a decoration.
The pattern. Generate patches with free tokens. Verify them with a free server. Freeze the flaky noise. Compress the feedback. The agent does the writing. The gate does the judging. The reviewer makes the design call.
That division is the real win. Agents write more code than any human can review. Gates verify more behavior than any human can test. Humans make the few decisions that matter.
Try the loop once with a small patch. The free grant is there for exactly that. The difference is visible between a patch that passes and a patch that survives.
Top comments (0)