Skip to main content

The Potter PromptPotter

LLM-driven evolution of prompts and pipelines

Hand it a labeled dataset and a pipeline. It evolves the prompt and the pipeline's parameters together,
cuts a losing candidate the moment the evidence says it will not win, and shows you every measurement behind the winner.

PyPI Python License

Try it without installing: promptpotter.com — 10 free optimization runs on your own data, up to 10 rounds each, in the browser and on my key. Offer stands until 3 Dec 2026; bring-your-own-key is in the works.

What it does differently:   Losers cut early · Pipeline, not just prompt · Budget · No self-grading · Campaign on disk
Try it, then read on:   Quickstart · App tour · How the search works · vs GEPA / AlphaEvolve · The bench · Five ways in · Hack on it · Going deeper · Docs

The PromptPotter control plane: a finished campaign in the chat view, with its pipeline, its rounds, the trend, and the hard-sample ranking

The control plane on a real, finished campaign — seven rounds on JustLogic. Nothing here is staged: the thread itself reports that round 6 resolved nothing.
Every figure on this page is an in-campaign reading from a small run, not a benchmark result.

One round, replayed

Prompt optimization that stops paying for losers. Every measurement costs money, so the whole design is most fitness per dollar.

Replay of one real round: three candidates measured, the third eliminated after 7 of 34 samples, the first selected.

One round of a real campaign, replayed line for line from its readout.log — the gutter is the source line number. Candidate 3 is cut after 7 of 34 samples; the other 27 are never bought.

One round: a parent is mutated into three candidates, each is measured sample by sample, the third is cut after 7 of 34 samples, and the winner becomes the next parent.

Each generation, an LLM mutates the parent into a small population. Every individual walks the same samples, and after each one a posterior asks a single question: what is the probability this candidate ends up the round's best? Below the threshold, measurement stops — Posterior-of-Being-Best. The survivor is elected and breeds the next generation. The drawing is the replay above, read out of the same log.

Four more claims follow, each with the screen that backs it.

↑ map

It moves the pipeline, not just the words

The run card in the chat thread: trend per round, spend, which prompt fields and node parameters the best candidate changed, and how many samples flipped against the origin

Model, temperature, node thresholds, the output schema — whatever your pipeline.yaml declares tunable — are part of the individual, so they mutate and are selected jointly with the prompt fields. In the round replayed above, two of the three mutations were to a schema field description, not to the prompt. The run card says which prompt fields and which node parameters the best candidate changed, what it cost, and — on the cells both were measured on — how many samples it now gets right, and wrong, against the origin.

The budget goes where candidates separate

The hard-sample leaderboard: samples ranked by information gain, each with its fitted difficulty and how often it has been graded

Samples everyone aces or everyone fails are noise, and paying for them buys nothing. The hard-sample leaderboard orders the dataset by how much each sample tells you about which candidate is better, with a fitted difficulty δ beside it, and scoring goes preferentially to those. Measurements are content-addressed: a configuration already scored on a sample is replayed, never re-bought — and the replay still shows its full cost on the ledger.

One measured cell opened: prediction, ground truth, the exact prompt sent to the node, and whether it was replayed from the archive
Every number opens down to the call. One cell = one candidate on one sample: prediction, ground truth, the exact input each node received, tokens, seconds — and whether it was paid for or replayed from the archive.
The candidates chart: every candidate of the campaign with accuracy, ability and overlap, intervals drawn, and a served caveat above it
Every candidate, with its interval. Accuracy, ability θ and the shared-cell overlap for each individual across all generations, with the lineage beneath. The caveat above the chart is served by the backend, not decided in the browser.

It does not grade its own homework

Optimizer warnings: rounds 3 to 6 each resolved nothing, because every arm's lift interval spans zero

An optimizer that picks its own winner is the easiest thing in this field to fake: with three arms and no real difference between them, some arm scores above its parent most of the time. PromptPotter still promotes the best of what it saw — and tells you, per round, on screen and on disk, that the lift interval spans zero. The terminal replay does the same in its own words: its pick is printed with p=0.42 (ns) beside it.

Three guards sit behind that. Scores are a subset-invariant ability (Rasch θ), so a candidate that drifted onto easier samples cannot out-rank an honest one. Degenerate candidates — a constant answer, a shape that games the scorer — are caught before they count. And the layer that validates a fix is never the layer that proposed it. What a winner's number may claim.

A campaign is an object on disk

The files view: the cycle's round files on disk, with round 6 open as a scoreboard and its verdict

Not a script that has to finish. The file tree is the dashboard: each round is a JSON file you can open in an editor, and the app renders the same file as a scoreboard. Pause a campaign, resume it, rewind to any round, or fork a sibling and compare:

python -m promptpotter resume --from 3              # rewind in place
python -m promptpotter resume --fork-on-divergence  # sibling cycle at the divergence point

Changing the scoring formula loses no results — traces are facts, scores are policy — and every artifact stamps the ledger position it was written at, so any past moment is reconstructible (how).

The whole app in one walk

A walk through the app: the chat thread, the run card, the dashboard, the sample leaderboard, one opened cell

The thread, the run card, the optimizer's own loop, the sample leaderboard, one measured cell opened. 📺 Longer: Live #2 — a Swiss-invoice campaign, run raw.

↑ map

Quickstart

The Potter driving a failing pipeline through the loop into a verified one

Python 3.13+ and an OpenRouter key — the optimizer's default provider.

pip install "promptpotter[all]"
python -m promptpotter new tickets.csv --set task_description="classify support tickets by urgency"
python -m promptpotter resume

Bring a labeled dataset — input/output pairs as CSV, TSV, JSON, JSONL or .xlsx — and say what the job is. No key set yet? new offers to write one on first run. resume picks up wherever the last run stopped: Ctrl+C pauses a campaign rather than losing it.

To watch it in the app shown above:

python -X utf8 -m uvicorn promptpotter.main:app --port 8001    # then open http://localhost:8001/

Already in DSPy? It installs where you would reach for GEPA — what you keep and what you trade away that way is dspy-optimizer.md:

from promptpotter.presentation.teleprompter import PromptPotterOpt

optimizer = PromptPotterOpt(metric=my_metric, dataset_name="my-task")
compiled = optimizer.compile(my_program, trainset=trainset)

Six chapters from install to troubleshooting: the manual.

↑ map

How the search works

The loop: a task and a labeled dataset enter an optimizer setup, then generate, score and critique repeat until a stopping rule fires. L2 and L3 escalate lazily on a stall; a measurement archive replays instead of re-measuring.

One round is the unit; a campaign is rounds under three layers, and a higher layer constrains the lower one rather than replacing it:

Layer Fires What it does
🧬 L1 · generate, evaluate, critique every round Mutates a generation of individuals, measures each one's fitness on your dataset, and reads the raw per-sample misses to steer the next generation.
🔭 L2 · refine context when L1 stalls Rewrites how L1 searches: which evidence it sees and how hard it explores.
🧭 L3 · modify plan when L2 stalls Rewrites the strategic plan L1 works within.

The loop exits on a stopping rule — goal reached, budget spent, or a plateau — not on a fixed trial count. The critique-and-refine pattern is inspired by PromptWizard. Full mechanics: the-loop.md.

A search tree: origin, rounds 1 and 2, then a branch through rounds 3 and 4 that is spent. The search rewinds to round 2 and a second branch reaches the winner.

It searches a tree, not a trail. Each round's result flows back to every ancestor it descends from, and when a branch is spent a UCB rule picks the ancestor to re-expand — so the search climbs a different hill instead of stalling. An ancestor's score reflects what re-expanding from it actually yielded, including in branches it never ran itself. This is AlphaZero-shaped MCTS over the lineage, with deterministic evaluation on your dataset in place of rollouts: the four-phase mapping.

↑ map

Where it sits

PromptPotter belongs to the LLM-driven evolution family — an LLM proposes variants, a scorer ranks them, the winners breed. On the prompt side that family is GEPA, MIPROv2, PromptWizard and CAPO; on the code side AlphaEvolve and OpenEvolve. GEPA evolves the instruction text of a DSPy program, AlphaEvolve evolves source code, PromptPotter evolves a whole declared pipeline jointly with the prompt — a different target, not a missing feature.

The table is capability, not a benchmark result:

Capability GEPA AlphaEvolve PromptPotter
Tunes the whole pipeline — model, temperature and node thresholds evolve alongside the prompt 🟡 🟡 🟢
Stops losers early — scores share one scale, so nobody wins by drawing an easier set 🟡 🟡 🟢
Every measurement is priced — a cache-served result keeps its full cost on the ledger 🔴 — 🟢
Self-healing — an invalid proposal is caught and taught to a different layer, not just discarded 🟡 🟡 🟢
Carries knowledge across runs — parameter impact, sample difficulty and failure patterns survive the campaign 🟡 🟢 🟢
Open and inspectable — a browser control plane, and a campaign you pause, resume, rewind or fork 🟡 🔴 🟢
Runs in your editor — drive a whole campaign from the terminal (/potter-run) 🔴 🔴 🟢

🟡 is a partial version of the same capability; AlphaEvolve's are that capability at the code level; — is a closed service whose behaviour is not documented. GEPA keeps a candidate pool within a run — its 🟡 on knowledge is about what survives it. One documented exception to the pricing row: a DSPy call replayed from DSPy's own cache is not counted.

Where the others are ahead. GEPA has reach — it lives inside DSPy, with that ecosystem's adapters, tracing and audience, which is why PromptPotter also installs as a DSPy optimizer. AlphaEvolve optimizes code, which PromptPotter is not pointed at. Opik, the closest product rival, ships six optimizers behind one API today and tunes sampling parameters too. Langfuse has production telemetry.

The bench

Peers ship an algorithm. PromptPotter ships an algorithm and the interface around it — measurement, the content-addressed archive, one spend ledger, persistence, the control plane — and the direction of travel is to run other people's optimizers inside that interface, as manifests. A menu of optimizers makes them reachable; it does not make their numbers comparable. What has to be held equal before two methods' numbers may sit in one table:

Held equal What it rules out
One grader each method carrying its own metric function, which drifts
One budget meter a method's internal rollouts going unbilled, so cost-per-fitness is a claim rather than a quantity
One exam, chosen before anybody proposes a method picking the questions it is graded on
Ability, not accuracy (Rasch θ) a method out-ranking an honest one by drifting onto easier samples
A stopping rule (PoBB) a fixed trial count standing in for evidence

The compare view's verdict: what was held equal across the compared campaigns, and what stays confounded

Put campaigns side by side and the first thing served is that list — what was held equal, and what stays confounded. The numbers come after.

Status, exactly: manifests for potter, capo, levi and gepa are in the tree (promptpotter/assets/optimizers/). The milestone closes when one peer — CAPO first — has run end to end in a real campaign, in a head-to-head whose only difference is the optimizer. That has not happened yet, and no comparison number is published before it does. Design and status: roadmap.md § The optimizer plug point · the argument: a menu is not a bench.

↑ map

Five ways in

Webapp The browser control plane on this page, at the domain root — promptpotter.com hosted, http://localhost:8001/ local. Chat-first: talk to the Potter and watch it work inline, with a button whenever a decision is yours. Ships as a reusable chat-app template (spec).
/potter-run Claude Code skill — an agent launches, supervises and diagnoses a full campaign from your editor.
CLI python -m promptpotter new <name> / resume.
REST API Every control verb the webapp issues, for when another system drives the campaign.
Embedded in Python A host program drives one campaign inside its own event loop; the DSPy optimizer is the simple-case entry.

A sixth — PromptPotter as a tool another agent calls (MCP) — is open for discussion in #27. Opinions welcome.

Hack on it

The optimizer's own pipeline as the dashboard draws it: adaptive_queue, l1_generate, pobb, l1_score, with l2_context, l3_plan and escalation beneath

The optimizer is itself a pipeline of nodes — the same graph the dashboard draws — so it can be pointed at its own optimizer prompts (self-optimization, L4).

git clone https://github.com/PromptPotter/prompt-potter-optimizer && cd prompt-potter-optimizer
pip install -e ".[all,dev]"
python scripts/gate.py          # every check CI runs

The engine is four seams — prompt structure, dispatch, the scoring node, cross-run memory — and the developer guide draws them on one page. Every optimizer runs end to end at zero spend (offline-run.md), so a change can be proven before it costs anything. The shape every PR is measured against: architecture.md §0. A recipe per expansion point: adding-a-surface.md. House rules: conventions.md.

↑ map

Going deeper

Reading a run — what lands on disk, and what a number may claim

While a campaign runs, keep cycles/{cycle_id}/dashboard.json open in an auto-reloading editor beside the terminal: the file is live scalar state (phase, round, candidate, accuracy, in-flight query), the terminal prints HIT/MISS and per-round banners. Drill-down peers sit beside it — rounds/, log.md, index.json, and readout.log, the terminal mirrored to a file. Full guide: reading the output.

Every cycle writes a per-round digest to log.md. Verbatim, from the round replayed at the top — what the artifact looks like, not a result to read a number off:

- improved: **yes**
- samples: 34
- composite_fitness: `0.4237`
- ability θ: `+0.308` (ruler 5cd26f22e62708a4, 68 cells, 1PL)
- overlap: 34 shared cells, +16 measured: C0 41.2%  →  C1.2 44.1%  →  C4.1 52.9%
- verdict: C4.1 won on θ lift +0.216 = +0.072 over the parent + 0.144 parent selection bias (θ +0.293 vs parent +0.221, se 0.196); runner-up C4.2 at +0.149
- cost: **$0.0311** (optimizer $0.0048 c23% ·w4384 · backend $0.0137 c17% · bench $0.0127 c37%)

P(best) trajectory:
  f8356ad77a ▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅   50.0% [winner]
  6f7d643a1e ▇▆▅▅▅▅▅▅▅▄▅▄▅▄▅▅▅▅▅▅▅▅▅▅▅▅▅▅▄   49.7%
  a2169d009a ▂▂   15.8%

A percentage in a round banner is an in-campaign reading, computed on the rows that selected the winner — not a held-out result, and a level should never be compared across rounds. A round is won on θ, not on the accuracy column, and the verdict line keeps the lift over the parent apart from the parent's selection bias instead of adding them up quietly. Which figures are clean, which are biased upward, and what we do about it: benchmarks.md.

More that ships — self-optimization, block library, memory across runs
  • Optimizes itself — an outer campaign whose individuals are configurations of the inner optimizer. L4
  • Pick your block library mode — proven personas, thinking styles and answer formats (from PromptWizard and the Self-Discover modules it draws on, plus what our own runs turned up). Suggest from the library, restrict to it, or switch it off.
  • Memory across runs — parameter impact, sample difficulty and failure patterns survive the campaign that found them. scoring and memory
Common questions
  • What does L1 actually mutate? The prompt template's fields (persona, task instruction, …) plus whatever your pipeline.yaml declares as tunable. See the-loop.md.
  • My scoring formula was wrong — did I lose results? No. The optimizer rescores on load and replays decisions; on divergence, fork. See scoring-and-memory.md.
  • What if it stalls? Stall and failure are different triggers. Failures route back to the proposing layer (self-healing); stalls escalate L1 → L2 → L3 (the-loop). Stuck for other reasons: troubleshooting.
  • Why not search at request time instead? PromptPotter finds a configuration once; from then on it is an ordinary call with no search in the path. Test-time compute, moved out of the request.
  • Is this a model router? No. Live model selection per question is a gateway (OpenRouter, OmniRoute). PromptPotter tunes the thing a gateway ends up calling, so the two compose.

Benchmarks

PromptWizard BBEH DSPy CAPO

No head-to-head number is published yet, on purpose. The comparison is against DSPy's optimizers (GEPA, MIPROv2, BootstrapFewShot) and CAPO on BIG-Bench Extra Hard (BBEH), held to a standard this literature mostly does not hold itself to: every method scored on the same held-out rows, one published split seed, one export schema, no cross-paper number mixing. Numbers publish once the target model and the optimization budget are held constant across every method too — the budget in calls, reported beside tokens, dollars (priced at run date) and wall clock. Harness: bbeh-comparison/ · what we measure on, what we refuse to, and why: benchmarks.md.

Limitations

  • Parameter-based optimization only. It optimizes any pipeline that exposes tunable parameters — prompts, thresholds, model settings — but not model weights, neural architectures, or modality-specific representations.
  • Requires a labeled dataset. Input/output pairs are mandatory.
  • In-campaign figures are not held-out figures. The winner's own number is read off the rows that selected it, so it overstates deployment performance. A selection-clean partition is on the roadmap; published head-to-head numbers use a reserved split instead.

Documentation

🧠 Concepts ⚙ Operations 🔬 Methods & research 🔧 Contributing
Three-layer loop Install & env Related work Developer guide
Scoring and memory Persistence, state, recovery Benchmarks + metrics Architecture
Structured output Observability Verdict resolution Conventions
Nodes and pipelines Backend integration Candidate elimination Self-healing internals

Roadmap · docs index · stable API

Citation

@software{promptpotter,
  title  = {PromptPotter: LLM-Driven Evolution of Prompts and Pipelines},
  author = {Streuli, David},
  year   = {2026},
  url    = {https://github.com/PromptPotter/prompt-potter-optimizer}
}

Metadata

Release files for promptpotter 0.8.16

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for promptpotter 0.8.16
File Interpreter ABI Platform
promptpotter-0.8.16-py3-none-any.whl Python 3 none any Details

Release files / promptpotter-0.8.16-py3-none-any.whl

Download URL promptpotter-0.8.16-py3-none-any.whl
Size 2.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
3eda6f63745439bc37cdb2d75cfcd2492bc03edeeccefccc329995cf8e2df347
BLAKE2b-256 checksum
How to use checksums
726216c0272fa2305d44f6f85e5623b66541af4c73f606f25415e4b10865796c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.17

1 release file

This release

0.8.16 This release

1 release file

0.8.15

1 release file

0.8.14

1 release file

0.8.13

1 release file

0.8.12

1 release file

0.8.11

1 release file

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page