Prompt Optimize Loop
An evolutionary optimizer for a prompt (OpenEvolve / AlphaEvolve-style). The artifact is a prompt
that feeds the user's system; the feedback signal is a scalar metric printed by the user's own
evaluation command. Each iteration proposes one quality-focused edit, re-runs the eval, and keeps
the edit only if the metric improves — evolving the prompt toward higher scores. The eval is a
black-box oracle the loop runs but never edits, so the optimization tracks what actually matters
rather than gaming a number.
When to use
Use this when the user has a prompt and a command that scores the system using it, and wants the
prompt improved to raise that score. Default to diagnosing the prompt's biggest current weakness each
round and applying the one operator that addresses it; if the eval feedback points elsewhere, follow
the feedback. Not for authoring a prompt from nothing, tuning weights/hyperparameters, or making a
single manual edit with no score to compare against.
Setup
Resolve bindings interactively. If loop.run.yaml exists in the working dir, load it, confirm the
values in one line, and skip to the loop. Otherwise: on Claude Code (the AskUserQuestion tool is
available) infer a likely value for each binding and present it as the recommended option; on other
hosts ask each as a quoted plain-text prompt. Then write loop.run.yaml (format:
examples/run.example.yaml) and confirm the values before creating any other files.
| binding |
meaning |
default |
how to infer |
<prompt_file> |
the prompt to optimize — the artifact the loop evolves |
— |
scan the working dir for the prompt/template file the eval reads |
<eval_cmd> |
required. Command that scores the current <prompt_file>; prints the metric (see output convention below). Treated as a black box — never edited |
— |
ask the user; look for eval/score/bench scripts |
<objective> |
maximize or minimize, plus one line on what the metric measures |
maximize |
ask the user |
<target> |
optional score at which to stop early |
— |
ask the user; else leave unbound |
<sandbox_root> |
where prompt snapshots + ledger live |
./sandbox |
— |
<budget> |
max iterations |
10 |
— |
<patience> |
stop after N consecutive non-improving iterations (plateau) |
3 |
— |
Eval output convention. <eval_cmd> must print, on its last line, either a JSON object
{"score": <number>, "feedback": "<optional notes/errors>", ...any extra metrics...} or a bare
number. Higher is better unless <objective> is minimize. The feedback field, when present, is
the richest signal — read it like AlphaEvolve's artifacts side-channel to decide the next edit.
Eval runs in the user's environment. <eval_cmd> may call an inference endpoint or any tooling the
user has installed; the loop just shells out and reads the last line. If instead the prompt is executed
by you (interactive development with no separate endpoint), first run the current prompt over the
user's eval inputs to produce outputs, write them where <eval_cmd> reads, then run <eval_cmd> to
score them.
The loop
Copy this checklist and tick items off:
Iteration 0 — baseline. Run <eval_cmd>, record its score as the best, snapshot <prompt_file>
to <sandbox_root>/iter0/, and start the history ({iter, edit, score, feedback} per row).
Then, until stop (target, plateau, or budget):
Diagnose. From the latest score, the <eval_cmd> feedback, and recent history, name the
prompt's single biggest current weakness — the one thing most likely holding the metric back.
Make one targeted edit — pick the toolkit operator that addresses that weakness:
- Clarity — remove ambiguity, contradictions, and vague wording.
- Context — supply missing domain knowledge, definitions, or background the task needs.
- Specificity — make instructions concrete; pin down the output format; define what "good" is.
- Structure — order the prompt into steps/sections; add a short checklist.
- Examples — add one or two demonstrations of the desired input → output.
- Decomposition — split a complex instruction into explicit ordered sub-steps.
- Guardrails — state edge cases and what to avoid.
One change per iteration, so its effect on the metric is attributable.
Measure. Snapshot the edited prompt to <sandbox_root>/iter<N>/, run <eval_cmd>, and read the
new score off the last line.
Keep or revert. Keep if the metric improves per <objective> (if the eval is stochastic,
require a small margin so noise alone does not drive a keep); otherwise revert <prompt_file>
to the previous best snapshot. Append {edit, score, feedback} to the history either way.
Escape local optima. If the score has not improved for a couple of iterations, stop making tiny
tweaks — branch from an earlier high-scoring snapshot, or try a bolder restructuring (a different
decomposition, a fresh set of examples). Diversity beats grinding the same local hill.
When stopping, restore the best prompt to <prompt_file> and report the score trajectory, which
edits moved the metric (and which did not), and the final prompt.
Ledger
<sandbox_root>/ledger.tsv, tab-separated, never commas in the text. Header:
iter score status edit
status ∈ {baseline, keep, revert}. Example (metric = task accuracy, maximize):
iter score status edit
0 0.42 baseline original prompt
1 0.61 keep specificity: define each output label and the exact output format
2 0.61 revert examples: add 3 few-shot demos — no metric gain
3 0.78 keep context: add the domain rules the task assumes but never states
Report the best iteration, not necessarily the last.
Constraints
- The metric is the user's. Never edit
<eval_cmd>, its data, or its scoring — that games the
number instead of improving the prompt, and the eval is the only ground truth the loop has.
- Optimize the prompt only, and preserve the task's intent. Improve how the task is instructed,
not what is being asked; do not tailor the prompt to exploit eval quirks that would break real use.
- One edit per iteration, and compare the metric by re-running the full
<eval_cmd>, not a single
sample, so each score delta is attributable to that one edit.
- Report the best variant, not the last. The sandbox is self-contained — no
../ escapes.
- Do not pause the loop to ask whether to continue; run until target, plateau, or budget.
Stops
- Target — the score reaches
<target> (if set).
- Plateau — no iteration improved the best for
<patience> consecutive rounds (every non-improving
iteration counts toward patience; a keep resets it).
- Budget —
<budget> iterations reached.
1---2name: prompt-optimize3description: Use when the user has a prompt that feeds a system they can already score, and wants that prompt automatically improved to raise the score against their own evaluation command. Makes one targeted quality edit per iteration — clarity, context, specificity, structure, examples, decomposition, guardrails — re-runs the user's eval to measure the metric, and keeps the edit only if the metric improves, else reverts; loops to a target, plateau, or budget. The metric is whatever the user's eval command prints (task accuracy, an LLM-judge score, a pass rate, a tool-call success rate); the loop is metric-agnostic and never edits the eval. Not for writing a prompt from scratch, not for tuning model weights or hyperparameters, and not for one-off manual prompt edits without a score.4---5
6# Prompt Optimize Loop
7
8An **evolutionary optimizer for a prompt** (OpenEvolve / AlphaEvolve-style). The artifact is a prompt
9that feeds the user's system; the feedback signal is a **scalar metric printed by the user's own
10evaluation command**. Each iteration proposes one quality-focused edit, re-runs the eval, and keeps
11the edit only if the metric improves — evolving the prompt toward higher scores. The eval is a
12black-box oracle the loop runs but never edits, so the optimization tracks what actually matters
13rather than gaming a number.
14
15## When to use
16
17Use this when the user has a prompt and a command that scores the system using it, and wants the
18prompt improved to raise that score. Default to diagnosing the prompt's biggest current weakness each
19round and applying the one operator that addresses it; if the eval feedback points elsewhere, follow
20the feedback. Not for authoring a prompt from nothing, tuning weights/hyperparameters, or making a
21single manual edit with no score to compare against.
22
23## Setup
24
25Resolve bindings interactively. If `loop.run.yaml` exists in the working dir, load it, confirm the
26values in one line, and skip to the loop. Otherwise: on Claude Code (the `AskUserQuestion` tool is
27available) infer a likely value for each binding and present it as the recommended option; on other
28hosts ask each as a quoted plain-text prompt. Then write `loop.run.yaml` (format:
29`examples/run.example.yaml`) and confirm the values before creating any other files.
30
31| binding | meaning | default | how to infer |
32|---|---|---|---|
33| `<prompt_file>` | the prompt to optimize — the artifact the loop evolves | — | scan the working dir for the prompt/template file the eval reads |
34| `<eval_cmd>` | **required.** Command that scores the current `<prompt_file>`; prints the metric (see output convention below). Treated as a black box — never edited | — | ask the user; look for `eval`/`score`/`bench` scripts |
35| `<objective>` | `maximize` or `minimize`, plus one line on what the metric measures | `maximize` | ask the user |
36| `<target>` | optional score at which to stop early | — | ask the user; else leave unbound |
37| `<sandbox_root>` | where prompt snapshots + ledger live | `./sandbox` | — |
38| `<budget>` | max iterations | 10 | — |
39| `<patience>` | stop after N consecutive non-improving iterations (plateau) | 3 | — |
40
41**Eval output convention.** `<eval_cmd>` must print, on its **last line**, either a JSON object
42`{"score": <number>, "feedback": "<optional notes/errors>", ...any extra metrics...}` or a bare
43number. Higher is better unless `<objective>` is `minimize`. The `feedback` field, when present, is
44the richest signal — read it like AlphaEvolve's artifacts side-channel to decide the next edit.
45
46**Eval runs in the user's environment.** `<eval_cmd>` may call an inference endpoint or any tooling the
47user has installed; the loop just shells out and reads the last line. If instead the prompt is executed
48by *you* (interactive development with no separate endpoint), first run the current prompt over the
49user's eval inputs to produce outputs, write them where `<eval_cmd>` reads, then run `<eval_cmd>` to
50score them.
51
52## The loop
53
54Copy this checklist and tick items off:
55- [ ] Iteration 0 — baseline: run `<eval_cmd>` on `<prompt_file>`, record its score as the current best, snapshot the prompt.
56- [ ] Diagnose the prompt's single biggest weakness from the latest score, the eval feedback, and the history.
57- [ ] Apply one targeted edit (one operator from the toolkit) to `<prompt_file>`.
58- [ ] Measure: re-run `<eval_cmd>` and read the new score from its last line.
59- [ ] Keep if the metric improves (require a margin if the eval is stochastic), else revert to the best snapshot.
60- [ ] Append a ledger row; if stuck, branch from an earlier high-scoring variant; stop on `<target>`, plateau (`<patience>`), or `<budget>`.
61
62**Iteration 0 — baseline.** Run `<eval_cmd>`, record its score as the best, snapshot `<prompt_file>`
63to `<sandbox_root>/iter0/`, and start the history (`{iter, edit, score, feedback}` per row).
64
65**Then, until stop (target, plateau, or budget):**
66
671. **Diagnose.** From the latest score, the `<eval_cmd>` feedback, and recent history, name the
68 prompt's single biggest current weakness — the one thing most likely holding the metric back.
692. **Make one targeted edit** — pick the toolkit operator that addresses that weakness:
70 - **Clarity** — remove ambiguity, contradictions, and vague wording.
71 - **Context** — supply missing domain knowledge, definitions, or background the task needs.
72 - **Specificity** — make instructions concrete; pin down the output format; define what "good" is.
73 - **Structure** — order the prompt into steps/sections; add a short checklist.
74 - **Examples** — add one or two demonstrations of the desired input → output.
75 - **Decomposition** — split a complex instruction into explicit ordered sub-steps.
76 - **Guardrails** — state edge cases and what to avoid.
77
78 One change per iteration, so its effect on the metric is attributable.
793. **Measure.** Snapshot the edited prompt to `<sandbox_root>/iter<N>/`, run `<eval_cmd>`, and read the
80 new score off the last line.
814. **Keep or revert.** **Keep** if the metric improves per `<objective>` (if the eval is stochastic,
82 require a small margin so noise alone does not drive a keep); otherwise **revert** `<prompt_file>`
83 to the previous best snapshot. Append `{edit, score, feedback}` to the history either way.
845. **Escape local optima.** If the score has not improved for a couple of iterations, stop making tiny
85 tweaks — branch from an earlier high-scoring snapshot, or try a bolder restructuring (a different
86 decomposition, a fresh set of examples). Diversity beats grinding the same local hill.
87
88When stopping, restore the **best** prompt to `<prompt_file>` and report the score trajectory, which
89edits moved the metric (and which did not), and the final prompt.
90
91## Ledger
92
93`<sandbox_root>/ledger.tsv`, tab-separated, never commas in the text. Header:
94```
95iter score status edit
96```
97`status` ∈ {`baseline`, `keep`, `revert`}. Example (metric = task accuracy, maximize):
98```
99iter score status edit
1000 0.42 baseline original prompt
1011 0.61 keep specificity: define each output label and the exact output format
1022 0.61 revert examples: add 3 few-shot demos — no metric gain
1033 0.78 keep context: add the domain rules the task assumes but never states
104```
105Report the **best** iteration, not necessarily the last.
106
107## Constraints
108- **The metric is the user's.** Never edit `<eval_cmd>`, its data, or its scoring — that games the
109 number instead of improving the prompt, and the eval is the only ground truth the loop has.
110- **Optimize the prompt only, and preserve the task's intent.** Improve *how* the task is instructed,
111 not *what* is being asked; do not tailor the prompt to exploit eval quirks that would break real use.
112- **One edit per iteration**, and compare the *metric* by re-running the full `<eval_cmd>`, not a single
113 sample, so each score delta is attributable to that one edit.
114- **Report the best variant, not the last.** The sandbox is self-contained — no `../` escapes.
115- Do not pause the loop to ask whether to continue; run until target, plateau, or budget.
116
117## Stops
118- **Target** — the score reaches `<target>` (if set).
119- **Plateau** — no iteration improved the best for `<patience>` consecutive rounds (every non-improving
120 iteration counts toward patience; a keep resets it).
121- **Budget** — `<budget>` iterations reached.