AI Agent Optimization With Claude Code Using Real Production Failures
AI agent optimization with Claude Code as the operator: pull real production failures over MCP, test one change per round, and keep it only if held-out holds.
Table of Contents
You ask Claude Code to make the shipping support agent better at address changes. In ten minutes it rewrites the system prompt, and the five examples you picked all pass. Two days later, address changes for international orders break, a path nobody tested.
This post is about tuning the agent itself: its prompt, tools, model, and config. Claude Code’s edit may even have been right for those five cases. The setup made it unsafe: five hand-picked examples, no held-out check, and write access to production config.
The fix is to give Claude Code real production failures to work from, a rule for keeping or reverting each change, and limits on what it can touch, from the first failure cluster to a pull request a human approves.
TL;DR
- Use Claude Code as the operator of the improvement loop, connected to your traces over MCP.
- Work from real failure clusters, and have a human confirm each case before it enters a dataset.
- Split the dataset into a working set and a held-out set the agent cannot read.
- Change one thing per round, run an experiment, and keep the change only if the working score rises past noise and the held-out score holds.
- Start read-only, gate every write, and hand the search to an optimizer when rounds plateau.
AI agent optimization when Claude Code is the operator
AI agent optimization means changing an agent’s prompt, tools, model, and configuration against measured failures, then keeping only the changes that hold up. The same phrase also gets used for making websites readable by AI agents, which is a separate topic. This guide covers improving the agent you ship.
Self-improving agents fit into this as a loop. The agent, or a coding agent working on it, proposes changes from what production shows, and a human approves each one before it ships. Our post on building a self-improving AI agent pipeline covers the wider architecture this loop sits inside.
Anthropic’s hillclimbing guidance for Claude covers the core discipline: a train and test split, a noise check, and one change per round. This guide starts one step earlier, from production failures a human has confirmed, and adds the permissions and optimizer handoff a live agent needs.
The loop works for any agent that leaves traces in production, such as a support or scheduling agent. You need three things before the first round. Those are traces with enough detail to see tool calls, a person who can judge whether a case is a real failure, and a way to run the agent against a dataset.
Why coding agents are good at agent optimization, and where they go wrong
Claude Code can read the system prompt, the tool code, and a stack of failing traces in one session, then connect them. It makes precise edits fast, and it can run many rounds in the time a person would take to run two.
Given five examples, a coding agent will tune the prompt until those five pass, whether or not the change generalizes. It will read a small score bump as progress when the difference is run-to-run noise. Both mistakes show up as passing scores in the session and only surface later in production.
It also tends to change several things at once, which makes it impossible to tell which edit helped. And with write access, it can touch things that ship, such as a production config, without anyone reviewing the change first. Our post on evaluating Claude Code tool use covers how to watch its tool calls.
The loop below answers each failure mode in turn. Real failures replace hand-picked examples, and a held-out set catches overfitting. A measured noise band stops chasing noise, one change per round keeps cause and effect clear, and permissions keep changes away from production until a human approves.
Connect Claude Code to your traces over MCP
Claude Code needs to see production before it can improve anything. One command adds a remote MCP server over HTTP, and the server signs you in with OAuth, so no API key gets pasted into the session. The docs show how to connect Claude Code to the Future AGI MCP server.
claude mcp add --transport http --scope project futureagi https://api.futureagi.com/mcp
Claude Code’s --scope flag decides where the server is available: local to you, shared with the project, or available across all your projects.
With project scope, the config lives in .mcp.json in the repository, and each teammate approves the server the first time it loads. Headless -p runs skip that approval, so the permission rules below matter more there.
The server exposes about a hundred tools, so set permission rules before the first session instead of reviewing them one by one. Let the trace and cluster readers run, make every create call ask first, and deny the tools the operator should never use.
{
"permissions": {
"allow": ["mcp__futureagi__search_traces", "mcp__futureagi__get_trace",
"mcp__futureagi__list_error_clusters", "mcp__futureagi__get_error_cluster"],
"ask": ["mcp__futureagi__create_*"],
"deny": ["mcp__futureagi__get_dataset", "mcp__futureagi__get_annotation_item_detail",
"mcp__futureagi__list_annotation_queue_items", "mcp__futureagi__submit_annotation",
"mcp__futureagi__delete_*", "mcp__futureagi__update_*"]
}
}
Denying get_dataset and the review-queue readers matters most, since they return case contents, including held-out cases. Denying update_* also stops the operator from editing eval templates, the scores it is graded on. Then run /mcp inside Claude Code to finish the sign-in in your browser.
Have Claude Code pull failure clusters as optimization targets
Start each session from failures your users already hit. Grouping them saves you from reading traces one by one. Ask Claude Code to list the failure clusters in Error Feed, which the docs call issues, and pull the production traces behind each one, then summarize what the traces in a cluster share.
You pick which cluster to work on first, based on how often it appears and what it costs users. Claude Code then writes down the shared pattern and a hypothesis before it proposes any fix. A hypothesis such as “the agent calls the address tool before checking whether the order has shipped” keeps the next round focused.
A good first prompt is plain and specific: list this week’s failure clusters for the support agent, open three traces from the largest address-change cluster, and describe the step where each one went wrong. Ask for the hypothesis in one sentence. Keeping the request narrow keeps the agent from proposing fixes before you have agreed on the problem.
The table below shows who does what across the whole loop. Claude Code does the hands-on work at each step. A human makes every decision that changes what the loop optimizes toward or what reaches production, and each step leaves an artifact you can review later.
| Step | Claude Code | Human | Platform artifact |
|---|---|---|---|
| Find failures | Lists clusters and reads their traces | Picks which cluster to fix first | Failure clusters |
| Confirm cases | Summarizes candidate cases | Confirms and labels each case | Review queue |
| Build dataset | Proposes the split | Exports confirmed cases into two datasets | Working dataset and held-out dataset |
| Propose change | One edit with a hypothesis | Reviews the diff | Branch |
| Test | Starts the experiment | Reads the results | Experiment |
| Decide | Applies the keep-or-revert rule | Approves the merge | Decision log |
| Plateau | Configures an optimization run | Picks the winner | Optimization run |
Put a human between the failure cluster and the dataset
A cluster of failed traces is a list of candidates, and some will be wrong. The user may have asked for something out of policy, or the trace may have failed for an infrastructure reason. If those cases reach the dataset, Claude Code will optimize the agent toward bad labels.
So a reviewer confirms each case in a review queue and writes the expected outcome. The reviewer then exports confirmed cases to a dataset from the review queue. The reviewer’s written outcome becomes the pass condition the experiments score against.
Export two platform datasets. The working set holds cluster cases Claude Code may read, and you give it a copy as a file in the repo.
The held-out set mixes confirmed cases from traces it never opened with passing cases from nearby paths, such as international address changes. With the dataset and review-queue readers denied, it starts experiments on held-out by ID and works from the score.
If the working score climbs while the held-out score drops, you are looking at overfitting. The working gain is also partly fit by construction, since the operator read those cases, so treat held-out as the real gate.
When two reviewers disagree on a case, leave it out until they settle it, since an ambiguous label teaches the loop nothing useful. A held-out set that only holds easy cases will pass every change and hide the overfitting you built it to catch.
The hill climbing rule Claude Code follows: one edit, keep or revert
Hill climbing here means a simple rule applied every round. Before the first change, run the baseline three to five times on the same sets and note which cases flip between runs. The widest spread you see is your noise band, and a gain inside it is no evidence the change helped.
Size the band to the set. With 50 cases, one case is 0.02, so a band smaller than that filters nothing. Compare per case too: count which cases a change fixed and which it broke, and ignore the flaky ones.
Then make one change per round and run an experiment on both sets. Keep the change only if the working score rises past the noise band and the held-out score stays within tolerance of the baseline. Measure held-out’s own noise and set the tolerance at least that wide.
Held-out works as a non-regression guard, so it must hold rather than rise. Our guide to turning traces into experiments covers the experiment side in more depth.
def keep_or_revert(baseline, before, after, noise=0.02, held_out_tolerance=0.02):
"""One change per round. Keep it only if the working set clears the noise band and held-out stays near the baseline."""
work_gain = round(after["working"] - before["working"], 4)
held_drop = round(baseline["held_out"] - after["held_out"], 4) # measured against the baseline, so drops cannot add up
if work_gain <= noise:
return "revert", f"working set moved {work_gain:+.3f}, inside the noise band of {noise}"
if held_drop > held_out_tolerance:
return "revert", f"held-out is {held_drop:.3f} below baseline: the change fits the working cases only"
return "keep", f"working {work_gain:+.3f}, held-out {after['held_out'] - baseline['held_out']:+.3f} vs baseline"
baseline = {"working": 0.71, "held_out": 0.70}
rounds = [
("add address check to system prompt", baseline, {"working": 0.78, "held_out": 0.71}),
("require order status before update", {"working": 0.78, "held_out": 0.71}, {"working": 0.86, "held_out": 0.64}),
("lower temperature to 0.2", {"working": 0.78, "held_out": 0.71}, {"working": 0.79, "held_out": 0.71}),
]
for change, before, after in rounds:
print(change, "->", *keep_or_revert(baseline, before, after))
# keep / revert (held-out 0.060 below baseline) / revert (inside the noise band)
The scores here are illustrative, and the noise band of 0.02 stands in for whatever your baseline runs showed. The first change is kept, because the working set rose 0.07 and held-out stayed above baseline. The second reverts: the new status rule lifted the working set but left held-out 0.06 below baseline.
The third change reverts too, because a gain of 0.01 sits inside the noise band. Each decision goes into a log with the hypothesis, the change, both scores, and the reason. After a few rounds, that log tells you which kinds of change help this agent and which ones keep landing inside the noise band.
Set a budget for each session too, such as a fixed number of rounds or experiments. Each experiment costs model calls on both sets, and a loop with no limit will keep trying small variations long after the useful changes are found. The budget also forces a review point, where a person reads the log before more rounds run.
Held-out also wears out, since each check picks winners partly by its noise. Refresh it from new production failures each session, re-run the baseline on the refreshed set, and keep a final test set nobody checks until the end.

What Claude Code is allowed to change
Give the operator agent a short list of levers: the system prompt, tool descriptions, the model with its parameters, and agent config (tool schemas, memory, framework settings). Each lever needs a check that would catch a bad change.
Keep some things out of scope by default. That includes the code behind tools that write data, anything involving authentication, and anything running in production.
A platform experiment compares prompt and model configs, so test schema and config changes through agent-learning-kit or your own harness. The table below lists each allowed lever with an example change, the risk it carries, and the check that guards it.
| Lever | Example change | Risk | Check that guards it |
|---|---|---|---|
| System prompt | Add an address-verification rule | Overfits to working cases | Held-out score |
| Tool descriptions | Clarify when to call update_address | Wrong-tool calls spike | Tool selection accuracy |
| Model and parameters | Lower temperature, smaller model | Quality drop on rare paths | Held-out score plus cost and latency |
| Agent config | Tool schemas, memory settings | Breaks integrations | Regression dataset plus schema checks |
Record which lever each round touched in the decision log. Over time the log shows where the gains come from for this agent, such as tool descriptions doing more than prompt rewrites. That pattern tells you where to point the next session, and which levers you can stop spending rounds on.
When hand-driven rounds plateau, hand the search to an agent optimizer
Hand-driven rounds stop paying off at some point. You see the signs in the log: several rounds in a row land inside the noise band, or changes that win on the working set keep failing on held-out. Claude Code has run out of evidence to propose from, and more manual rounds burn budget.
That is the moment to hand the search to an agent optimizer. Give it the working dataset and the same evals, let an algorithm search many prompt variants in one run, and score the winner on held-out afterward. Optimization offers six optimization algorithms for this, from simple random search to evolutionary methods.
Claude Code’s role shifts at this point. It configures the optimization run, then reads the results and summarizes the winning variant against the held-out set. A human still picks the winner. Our post on automated agent optimization compares the algorithms in more detail.
Guardrails for the operator agent
An agent that changes your agent needs its own limits. Start with the permission rules above, and approve each create call by hand rather than choosing “don’t ask again”. Widen access only after you have watched several rounds.
Keep every change in a branch and a pull request, so a human reviews the diff before it merges. Require human approval before any change reaches production, even when the experiment looks like a clear win. Pair each merge with regression tests for agent changes so a later round cannot quietly undo it.
Keep those deny rules in place for every session, including headless runs.

Running the loop with Claude Code and Future AGI
Over the hosted MCP server, Claude Code can call search_traces and list_error_clusters to read production, then create_dataset, create_experiment, and create_optimization_run to act. Those three write, so they sit behind your approval. Error Feed, on Cloud or Enterprise, supplies the clusters, and annotation queues hold the human review.
Experiments compare runs and let you choose a winner. Hosted Optimization tunes prompts with GEPA, PromptWizard, ProTeGi, Bayesian Search, Meta-Prompt, or Random Search.
For whole agent configs, the open-source agent-learning-kit’s fi.opt module treats tool schemas, memory settings, and framework config as the target, and builds regression datasets from observability windows.
It ships the same six algorithms plus agent-level optimizers such as evolutionary, Pareto, and bandit search, so you can run them locally after pip install agent-learning-kit. The Apache-2.0 core sits in the Future AGI repo, and the MCP server connects Claude Code to the hosted platform with one command.
Letting Claude Code fix the address-change flow without breaking the next one
Back to the shipping support agent. The next session starts from the top failure cluster, with cases a reviewer confirmed and a held-out set Claude Code cannot read. It makes one change per round, keeps only what clears the noise band without hurting held-out, and opens a pull request a human approves.
With international address changes in the held-out set, a change that breaks them fails its round before it ships, and the log shows which change fixed the first path and why.
Connect Claude Code to the Future AGI MCP server and list your top failure clusters read-only.
Frequently Asked Questions
What is AI agent optimization?
How do you optimize an AI agent?
What is an agent optimization loop?
How do you build self-improving AI agents?
Can Claude Code build self-improving agents?
A current inventory of 9 open-source self improving agent frameworks, grouped by mechanism, with runnable DSPy and TextGrad code and how to prove real gains.
Inside Future AGI open source in Q2 2026: the platform shipped under Apache 2.0, Error Feed and the Agent Command Center went live, traces hit billions.
Gemini 3.5 Flash dropped today at Google I/O 2026. The 8 benchmark numbers that matter, $1.50/$9 pricing breakdown, and what to instrument before you swap.