ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-04-29Advanced

Teaching Antigravity Agents to Learn from Failure — A Solo Developer's Loop for Reusing Failure History

Antigravity agents repeat the same mistakes because each session starts blank. A solo developer's six-month run with a structured failure log, a separate observer agent, and the side-effect of overfitting.

Antigravity322Agents18Reliability3Solo Development3Operations8

Teaching Antigravity Agents to Learn from Failure — A Solo Developer's Loop for Reusing Failure History

After running Antigravity agents day after day, I started to feel a strange déjà vu. The agent would trip over the same thing it tripped over last week — a wrong shell path, the same provider's rate limit, the same dependency install glitch. Every Antigravity session is fresh. Without something to carry the past forward, the agent will keep stumbling on the same stones.

The biggest improvement to my solo development workflow was not making the agent smarter. It was building a small system around it that prevents the same failure from happening twice. This is not a wait-for-the-next-model story. It is an operations story. Below is the loop I have lived with for six months.

Why agents repeat themselves

Antigravity agents do not repeat mistakes because they are dim. They repeat mistakes because each new session starts with no memory of the last one. That blank slate is correct for safety: stale failure memory can corrupt fresh decisions. But for a solo developer running agents against a stable environment with the same API keys and the same machine, the past is mostly relevant. We just have to write it down where the next agent can read it.

If you skip this, your monthly bill creeps up. Every repeated stumble burns tokens, every retry burns API budget. For a solo developer those numbers add up fast.

Why I switched the failure log to JSON Lines

My first attempt was Markdown notes — "today the agent failed at X, root cause Y, fix Z." That works for a week. After a month the file is too big to feed back into a prompt without bloating context.

Switching to JSON Lines fixed three things at once.

{"ts":"2026-04-12T10:34","task":"deploy","tool":"wrangler","error":"Worker exceeded 62 MiB","fix":"split articles.json into per-article HTML","tags":["cloudflare","bundle-size"]}
{"ts":"2026-04-15T22:11","task":"test","tool":"npm","error":"ENOSPC","fix":"do not run npm install in scheduled tasks","tags":["disk","scheduled-task"]}
{"ts":"2026-04-21T09:02","task":"ingest","tool":"openai","error":"rate limit 429","fix":"use exponential backoff with jitter, base 2s","tags":["rate-limit","retry"]}

First, I can filter mechanically and feed only relevant lines to the next agent. Second, I can measure recurrence: a grep on tags tells me how many rate-limit failures I had this month. Third, the file stays human-readable, which means I learn from it too.

I keep failures.jsonl in the repo root. It is committed to git, so the history is searchable forever.

Don't let the executing agent write its own log

The trap most teams hit is asking the running agent to also record its own failures. If you do that, you get a log full of self-justification — failures conveniently rephrased, near-misses missing, sometimes phantom failures recorded for no reason. The log becomes unreliable, and so does the next decision based on it.

I split the work into two agents. The executor runs the task. After it finishes, an observer reads the trace and emits structured failure records. The executor has no write access to failures.jsonl. Only the observer appends.

The observer's prompt looks roughly like this.

You are reviewing the trace of an agent that just finished. Emit one JSONL
line for each event that matches one of:

- A tool call that failed and required a retry
- The same error appearing two or more times
- A halt caused by unexpected input

Fields: ts, task, tool, error, fix, tags
For "fix", write only what actually worked in the trace. Do not speculate.
If nothing qualifies, return an empty line.

The "do not speculate" instruction is load-bearing. Observers want to be helpful and write "next time you should…" — but unverified suggestions silently steer the next executor wrong. The observer records what worked. Hypotheses live elsewhere.

Feed the next session only what is relevant

Logging without retrieval is wasted effort. A small Python utility loads failures matching the keywords of the upcoming task.

# load_failures.py — pull only relevant failures from history
import json, sys
from pathlib import Path
 
def relevant(record: dict, keywords: list[str]) -> bool:
    blob = " ".join([
        record.get("task", ""),
        record.get("tool", ""),
        record.get("error", ""),
        " ".join(record.get("tags", [])),
    ]).lower()
    return any(k.lower() in blob for k in keywords)
 
def main(keywords: list[str], limit: int = 8) -> None:
    path = Path(__file__).parent / "failures.jsonl"
    out = []
    for line in path.read_text(encoding="utf-8").splitlines():
        if not line.strip():
            continue
        rec = json.loads(line)
        if relevant(rec, keywords):
            out.append(rec)
    out = sorted(out, key=lambda r: r["ts"], reverse=True)[:limit]
    for r in out:
        print(f"- {r['ts']} [{r['tool']}] {r['error']}{r['fix']}")
 
if __name__ == "__main__":
    main(sys.argv[1:])

When I launch a deploy task, I prepend its output to the prompt:

## Past relevant failures (max 8)
- 2026-04-12 [wrangler] Worker exceeded 62 MiB → split articles.json into per-article HTML
- 2026-04-15 [npm] ENOSPC → do not run npm install in scheduled tasks
- 2026-04-21 [openai] rate limit 429 → use exponential backoff with jitter, base 2s

## Today's task
(actual task instructions)

That alone cut my deploy-task failure rate to roughly a third of what it had been.

A side effect: the agent overfits to old failures

After a few months, the log started to misbehave in a new way. The agent had memorised so many specific failures that it began over-correcting in unrelated situations. A bad afternoon of rate-limit errors from one provider would, weeks later, push a different agent to apply aggressive backoff on a different provider. The system was being safe at the cost of speed.

I introduced two countermeasures. First, an expiry policy: failures older than 90 days move to archived.jsonl. Archived failures are not loaded by default. Second, deduplication: when many failures share the same tag set, only the most recent one represents that group.

# collapse_failures.py — compress old log entries
from collections import defaultdict
from datetime import datetime, timezone, timedelta
import json
from pathlib import Path
 
CUTOFF = datetime.now(timezone.utc) - timedelta(days=90)
 
active, archive = [], []
for line in Path("failures.jsonl").read_text().splitlines():
    if not line.strip():
        continue
    rec = json.loads(line)
    ts = datetime.fromisoformat(rec["ts"]).replace(tzinfo=timezone.utc)
    (active if ts >= CUTOFF else archive).append(rec)
 
seen = {}
collapsed = []
for rec in sorted(active, key=lambda r: r["ts"], reverse=True):
    key = ",".join(sorted(rec.get("tags", [])))
    if key in seen:
        continue
    seen[key] = True
    collapsed.append(rec)
 
Path("failures.jsonl").write_text(
    "\n".join(json.dumps(r, ensure_ascii=False) for r in collapsed) + "\n"
)
Path("archived.jsonl").write_text(
    "\n".join(json.dumps(r, ensure_ascii=False) for r in archive) + "\n"
)

I run this once a month. Noise dropped sharply, and the agent stopped over-applying past lessons to unrelated APIs.

Track recurrence, not raw success

Once a failure log is in place, the metric that matters quietly shifts. I used to watch agent success rate. Now I watch recurrence rate — the share of failures with a tag set that re-appeared inside the same month.

In the first month it sat near 38%. After six months it landed around 9%. Cutting recurrence is the single biggest cost lever for a long-running agent setup.

New, never-before-seen failures still happen. They will. The point is not to eliminate them, but to make sure the observer captures them so they never repeat.

Don't rush to share the failure log

A tempting next step is to make the failure log a shared artefact across teams or open source it. As a solo developer, I would slow that urge down for two reasons.

First, your failures.jsonl is shaped by your environment and habits. It tends to be noise to other people. Second, turning a personal log into a shared artefact carries real maintenance overhead — schema drift, redaction, governance — and the time has to come from somewhere. For a solo developer that "somewhere" is usually the time you would have spent improving your own loop.

Run a personal log for three months. Six months in, look back and pick out the few entries that genuinely transfer to other setups, and only then share that subset. Doing it the other way around tends to leave your own agent stuck while you build infrastructure for others.

The smallest next step

Tomorrow, before launching another Antigravity agent, drop an empty failures.jsonl into your project root. After the run, write one failure into it by hand. Use the schema from this article. Do this for a week. You will start to see your own pattern of failure before you build the observer or the cleanup script. Those come later, and they will be much easier to design once the data exists.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Agents & Manager2026-06-21
Keeping Unattended Agent Run Logs Long Enough to Debug — Without Filling the Disk
A scheduled agent is only fixable if you can reconstruct why it failed. Here is how to keep run logs around without filling the disk — tiered retention, schema-versioned records, and a compaction job — drawn from running four sites on autopilot as an indie developer.
Agents & Manager2026-06-20
Don't Lose Failed Agent Jobs: Designing a Dead-Letter and Requeue Path
Scheduled agents fail silently overnight and the work simply vanishes. Here is how to catch those failures with a dead-letter store and a staged requeue, drawn from running four sites on autopilot as an indie developer.
Agents & Manager2026-04-27
Letting Antigravity Be Your Night-Shift Engineer: A Solo Dev Operating Model
How to operate Antigravity agents as the second engineer who works while you sleep. Task hand-off, scope boundaries, and a five-minute morning review — the model I have refined while running multiple products solo.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →