← Back to Timeline

🔨 The Agent That Forges Its Own Tools: What Happened When I Stopped Adding Features and Let My Agent Grow a Library

Every agent framework ships with a fixed toolbox. FORGE ships with a forge. When it hits a capability gap, it doesn't fail; it writes a new tool, tests it in a sandbox, and registers it forever. Then I ran the experiment every skeptic would demand: does the growing library actually make it better?

Here is an uncomfortable question I kept avoiding for months: if you took away my agent's prompt engineering, its clever orchestration, its carefully tuned system message, what would actually be left?

The answer, for most agent frameworks I had built before, was: a very articulate caller of the same ten tools. Every framework in this space ships the same fixed toolbox: read file, write file, run command, search web. We argue about models and prompts while the toolset stays frozen. It's as if we built interns with perfect memory and never let them learn where anything is kept.

"A model gets smarter with every release. An agent's toolset gets smarter never, unless you build the mechanism that lets it grow itself."

FORGE is my attempt to build that mechanism: an autonomous coding agent whose defining feature is not what it can do today, but that when it discovers something it can't do, it forges a new tool. It writes it, tests it in a sandbox, and registers it permanently in a searchable skill library. Think Voyager's skill library, but pointed at general software and data tasks instead of Minecraft.

This is the story of building it and, more importantly, of the ablation experiment I ran to find out whether any of it is real.

⚙️ The Core Loop: Failure Is Just an Unwritten Skill

Most agent architectures treat task failure as an endpoint: retry, give up, or hallucinate confidence. FORGE treats failure as raw material. Every task runs through one loop:

🔍Searchskill library first
♻️Reuseexisting proven tools
🔧Repairfix broken skills
🔨Synthesizebrand-new tool
🧪Sandbox Testprove it works
📜Registerforever, versioned

A Skill is not a prompt snippet. It's a versioned Python module with a JSON schema, a docstring, unit tests, and provenance recording which task spawned it. Skills that pass their own tests become permanent, searchable citizens of the library, callable by this run, or by any future run, months later, on a problem nobody anticipated.

Skills that fail their tests are simply never registered. The library cannot rot with untested code, because untested code has no path inside.

🪄 What Today's Agent World Gets Wrong

FORGE exists because four failure modes keep repeating across agent frameworks:

Failure Mode What We See Today What FORGE Does Instead
Frozen toolsets The same ten tools ship forever; capability is capped at launch day. Growing library: every capability gap becomes a new permanent tool.
Prompt-as-memory Lessons live in chat history; a new session forgets everything. Disk-backed memory: skills persist across runs, sessions, and restarts.
Trusting generated code Agent-written code executes directly; failures discovered in production. Test-gated registration: a skill exists only after passing its own tests in an isolated sandbox.
Unmeasured "improvement" Demos feel smarter; nobody runs the control experiment. Cold vs warm ablation: identical suite, empty library vs grown library, measured.

That last row is the whole point of this post. Self-improvement claims are cheap. The interesting question is falsifiable: run the same benchmark twice, once with a library that persists and once with amnesia, and see if the library earns its keep.

🏆 The Money Experiment: Warm vs Cold

I built a 12-task benchmark suite across three domains (data wrangling, file/OS operations, API/parsing), each with a deterministic success checker. Before trusting any of those checkers, I validated all twelve against hand-written reference solutions run through the real sandbox (scripts/validate_checkers.py → 12/12 PASS). If the oracle is broken, the science is theater.

Then I ran the suite twice against a live LLM (Mistral codestral-latest, temperature 0.2): once warm (the skill library persists across tasks) and once cold (empty library, every run).

58.3%
Warm Success Rate
(7/12 tasks)
50.0%
Cold Success Rate
(6/12 tasks)
+8.3pp
Library Delta
Warm − Cold
13
Skills Forged Across
Both Arms

The warm arm's extra solve came from exactly the mechanism the hypothesis predicts: during synthesis, the planner sees "similar skills already in the library" and stands on accumulated shoulders instead of starting from zero. Cold-arm telemetry confirmed clean isolation: first retrievals returned zero hits, and the two arms' skill directories were completely disjoint. The delta wasn't leakage. It was learning.

And here is the part I'm proudest of, because almost nobody in this space prints it:

🤔 Read the Fine Print

n = 1 seed. One model family. Temperature 0.2 makes runs near-deterministic, so both arms largely re-measure the same capability set. Reuse rate measured zero on this deliberately diverse suite (it shows up on repeat-task suites instead). The direction of the delta matches the hypothesis; the magnitude needs multi-seed confirmation, and the tooling for that (SEEDS=N bash scripts/run_ablation.sh) already ships in the repo. Full threats-to-validity analysis lives in RESULTS.md.

"An uncontrolled demo is marketing. A controlled ablation with printed limitations is science. I wanted the second thing, even though the first photographs better."

🔑 The Night the Infrastructure Fought Back

No blog post about autonomous agents should sound like the run was smooth. My first full ablation attempt nearly died in a storm of HTTP 429s.

The original provider's free tier starved the experiment mid-run: 123 of 205 LLM calls errored under rate-limit thrashing. The early numbers from that throttled run (warm 1/12 vs cold 0/12) were measuring quota exhaustion, not intelligence. Most people would hide those numbers. They're still in the repo's git history, relabeled honestly as an infrastructure stress test.

That failure forced two features that made the final experiment possible:

The lesson generalizes far beyond this project: agent benchmarks without error taxonomies measure your API plan as much as your agent.

🧪 Under the Hood: Five Decisions That Define FORGE

📜 Filesystem Over Database
The skill library is plain files plus a JSON manifest covering name, path, schema, embedding reference, provenance, test status. No DB server, no migration debt. You can cat the entire memory of the agent. Versioning means library/csv_dedupe/v3.py sits next to its ancestors.
🪓 Sandboxed Execution, Always
Every skill, synthesized or reused, runs in an isolated subprocess with timeouts and resource caps, no network unless the task allows it. Self-improvement without containment is how agents earn headlines for the wrong reasons.
🔧 Deterministic Repair Before Regeneration
Before asking the model for another attempt, a deterministic repair layer fixes the mechanical failure modes LLMs produce constantly: labeled-fenced-section parsing with balanced-brace JSON fallback, AST schema↔signature reconciliation, SCHEMA injection into module source, entrypoint renaming, fixture aliasing. Cheap fixes stay deterministic; expensive retries stay rare.
🔍 Search Before You Synthesize
The router searches the library (semantic embeddings with TF-IDF fallback, plus keyword grep) before generating anything. Synthesis is the expensive path; reuse is the goal. The system is biased toward remembering, not rewriting.
✎️ Test-Gated Registration
The synthesizer generates implementation + schema + unit tests together. Only a skill whose own tests pass gets registered. This single gate is what separates a compounding library from an accumulating junk drawer.
📊 Telemetry From Day One
Attempts, tokens, skills created vs reused, pass/fail, growth curves: every run writes JSONL telemetry. The ablation wasn't retrofitted; the experiment harness was part of the architecture from Day 4.

💡 What Building It Taught Me

🤝 Who Gets What

🤖 Agent Framework Builders
A working reference for the piece everyone skips: the grow-your-toolset loop, with test-gated registration, sandbox isolation, and an ablation harness you can copy wholesale.
🔬 Researchers & Skeptics
A cold-vs-warm protocol with a validated oracle, disjoint-arm isolation checks, an honest n=1 caveat, and one-command multi-seed replication. Break it, extend it, cite it, disprove it.
🛠️ Practitioners Shipping Agents
A pattern for making yesterday's failures into tomorrow's tools: capture the gap, synthesize the module, gate it behind tests, register it forever. Your agent's worst day becomes reusable infrastructure.
🌱 The Curious
A small enough codebase to read in an afternoon: ~71 tests, filesystem storage, no magic. Watch a skill be born in the logs and you'll never look at a fixed-toolset agent the same way again.

🚀 Where This Goes Next

The current delta of +8.3 percentage points across one seed and one model family is a directional result, and I've labeled it as such everywhere it appears. The next milestones are already tooled: multi-seed ablations, higher-temperature variance, a repeat-task suite to exercise reuse properly, and digging into the six consistent failures to understand whether the ceiling is the model or the checkers.

But the deeper bet is unchanged: the frameworks that win won't be the ones with the best launch-day toolbox. They'll be the ones with a forge. Every task an agent fails is either a dead end or a blueprint, and the difference between those two futures is a library that keeps receipts, gates itself with tests, and grows a little harder to beat every single day.

⚡ Try FORGE

The full loop, from synthesis through sandbox testing and registration to the warm-vs-cold ablation, is one clone away:

git clone https://github.com/mailtotanvir/forge.git
cd forge

# install (Python 3.11+)
uv venv .venv --python 3.11 && source .venv/bin/activate
uv pip install -e '.[dev]'

# configure any supported provider
cp forge.toml.example forge.toml   # add your key(s)

# run a task and watch skills get forged
forge run ap_001            # single task (add --cold for an empty library)
forge bench --seed 0        # full 12-task suite

# reproduce the ablation yourself
SEEDS=1 bash scripts/run_ablation.sh

Star the repo, break the test gate (please, I want to know how), and watch the library grow. Every skill it registers is one it will never have to learn twice.

Self-Improving Agents Skill Library Voyager-Inspired Cold vs Warm Ablation Sandbox Execution Test-Gated Registration LLM Benchmarks Python 3.11 Local-First