Paste your draft ad into one command: a demographically weighted panel of 20 synthetic buyers reads it in character and returns a population-level favorability verdict, corrected by the measured error of your past campaigns.
Free on your own machine, forever — no credit card, no API key required. · Pricing
Built for founders of small, fast-launching brands
OVK started the way most small brands do: prescription glasses from $29, a monthly drop cadence, and a founder writing ad copy at midnight. Every headline was a guess. A real focus group meant weeks of lead time and an agency invoice — for a brand shipping a new collection every month, the answer would arrive after the campaign it was meant to save.
A/B testing wasn't the fix either. It tells you which of two guesses lost less, and it bills you for both. What we wanted was the thing agencies sell: sit twenty real buyers in a room, read them the ad, watch their faces. Just — tonight, and again tomorrow, and free.
So we built the room. Twenty personas, each assembled in three layers: real demographic strata drive who is in the room and how much their voice counts, a Jungian archetype gives each one instincts and a way of speaking, and a locality bundle — this week's weather, the local paper's front page — puts something on their mind before your ad ever reaches them.
Now every draft goes through the panel before it goes anywhere else. One command returns 20 in-character reactions and a favorability score weighted to a ~500K modeled population, broken down by archetype and locality — in about a minute, for $0 on the default local model. And when the real click-through comes back, we feed it to the same queue: the panel measures its own error and corrects its next prediction by exactly that much.
How it works
Your draft fans out to all twenty personas at once and comes back as a single weighted prediction, with the disagreements — by archetype, by locality — laid out underneath it.
Feature: panel-run.sh appends your copy as
content:query, collects all replies in one atomic batch, and
aggregates them with per-stratum population weights (panel/weights.tsv).
Frank in Rochdale reads your ad differently than Chloe in Austin — because he's a sceptic in a frugal town where it rained all week, and she's a trend-forward optimist in SXSW season.
Feature: each persona is three layers — census-style
demographics for counts, one of 12 archetype voices for character, and a
shared per-locality context bundle (panel/panel.json).
Append the real outcome — CTR, conversions — and the panel joins it to its own prior prediction, measures how far off it was per stratum, and subtracts that bias from the next verdict.
Feature: outcome-append.rb →
calibrate.rb builds the per-stratum error table;
PredictionCorrector applies it, flagging every corrected number
with the history that justified it.
Predictions are labeled directional until enough real cycles accrue; uncalibrated strata pass through unadjusted and say so. You always see the honest unweighted number next to the weighted one.
Feature: every claim rides one append-only, immutable queue — queries, replies, predictions, outcomes — so any number on any report can be replayed from source (AX-OVK-00001, 00017, 00019).
Features
One orchestrator walks the queue with a single durable cursor and lands all 20 replies as one atomic batch — a run never half-completes.
persona-orchestrator.sh · AX-00012Every model call goes through one seam that maps each role — reply, classify — to a free local SLM, Claude, or mock. Change a config line, not a script.
llm.sh · panel/llm.env · AX-00024The entire loop — replies, scoring, aggregation, calibration — runs with zero model calls, so you can prove and test the plumbing for free.
REPLY_ENGINE=mock · SENTIMENT_ENGINE=heuristicPopulation estimates come from stratum weights, never naive multiplication — and every report shows the raw unweighted figure for comparison.
panel-aggregate.sh · weights.tsv · AX-00016A long-running terminal view groups replies per persona as they arrive, so you can watch the room react in real time.
persona-dashboard.sh · AX-00010Queries, replies, predictions, and outcomes live on one append-only, immutable queue — any number on any report can be recomputed from source.
ground flow · AX-00001 · AX-00019No credit card, no API key required. · Pricing
Roadmap
Every open item below is a signed unknown on the project's axiom chain, not a hidden caveat.
| Date | Flight | Delivery | Status |
|---|---|---|---|
| Jul 14 | AX-00001 | Append-only flow queue — single source of truth | Landed |
| Jul 14 | AX-00010 | Live persona dashboard | Landed |
| Jul 15 | AX-00012 | Single-orchestrator atomic fan-out | Landed |
| Jul 20 | AX-00016 | Three-layer panel · 20 personas, stratum-weighted | Landed |
| Jul 20 | AX-00024 | Model seam llm.sh · local / Claude / mock | Landed |
| Jul 20 | AX-00018 | Calibration loop closed · error table applied | Landed |
| ETA TBD | OVK-001 | First real campaign outcomes — calibration cycles accrue | In Flight |
| ETA TBD | AX-00020 | Census source & load-bearing strata for eyewear buyers | In Flight |
| ETA TBD | AX-00021 | Archetype framework for the voice layer | In Flight |
| ETA TBD | AX-00022 | Cycles needed before error signature beats outcome noise | In Flight |
| ETA TBD | AX-00023 | Attribution model — net out spend, seasonality, platform | In Flight |
| ETA TBD | AX-00028 | Per-persona pools & filter predicates — decided, unbuilt | In Flight |
Glossary
ground flow daemon behind the rapids: entries are appended once and never modified, deleted, or consumed.llm.sh, the only place a model is ever called; routes each task to a free local SLM, Claude, or mock.Before you run it
No. The default routes are a deterministic mock engine and any local
OpenAI-compatible model; Claude is an optional per-task route you turn on
in panel/llm.env only if you want it.
$0 on the mock and local-model routes — the software is yours and runs entirely on your machine. If you point a task at a hosted model like Claude, you pay that provider's per-call price and nothing else.
Out of the box it's directional, not survey-grade — LLM personas drift toward the modal opinion, and the system says so on every prediction. Defensibility is earned by the calibration loop: real outcomes measure the panel's bias per stratum and the correction is applied automatically.
Yes — personas, localities, and population weights are plain data in
panel/panel.json. Edit them and run
panel-generate.sh to rebuild the panel.
Onto a local append-only queue on your own machine, and nowhere else. Nothing leaves your box unless you deliberately route a task to a hosted model.
Free on your own machine, forever — no credit card, no API key required. · Pricing