Platform and SaaS: the agent that runs the next experiment
Track: Platform and SaaS · In the room: pre-assigned teams · Seed use case: experiment-analysis agent that designs its own follow-up test.
Who this is for
Teams from an experimentation/A-B-testing platform, with Workers and KV already in production, running a business built on other companies' experiments. An experiment result is not an endpoint — it's a fork: ship it, kill it, or run the obvious next test — and today that fork is a human staring at a dashboard deciding which. The pain isn't running experiments, that's solved and it's your product; it's the gap after a result lands, where someone has to read it, understand the implication, and decide what's next — usually the busiest analyst on the team, which is why the backlog of "obvious" follow-up tests that never got run keeps growing.
Invented experiments, metrics, and conversion numbers. Nothing resembling a real customer's experiment data or business result goes into a shared account today.
Three agent use cases
1. Experiment-analysis agent — the seed use case
- Trigger. Experiment reaches statistical readiness — enough samples, or a time box elapsed. The agent notices on its own; no dashboard check needed.
- Decides. Whether the result is significant or inconclusive, what it implies about the hypothesis, and the natural next test — same win on a different surface, same null result with a different lever, or a segment worth splitting out.
- Tools.
analyze_experimentinterprets the result and drafts the implication in plain language;design_followupproposes the next experiment's hypothesis, variant, and target metric, grounded in this experiment and its predecessors. - Human in the loop? Reading and interpreting needs no approval — pure analysis. Launching the follow-up always does: it spends real traffic and time against a metric the business watches, and a bad hypothesis costs weeks, not minutes.
2. Under-powered-test flagger
- Trigger. An experiment is running, partway through its planned duration.
- Decides. Whether current traffic allocation and effect size make a real answer likely, or the test is quietly heading for an inconclusive result that wastes its time box.
- Tool.
check_powerestimates whether the test is on track and, if not, proposes a fix — more traffic, a longer window, or a bigger minimum detectable effect. - Human in the loop? Only on the fix. Flagging is informational and safe; changing a live experiment's allocation or duration is the experiment owner's call — it affects everyone sharing the traffic pool.
3. Cross-experiment conflict detector
- Trigger. A new experiment targets a page or flow another experiment already runs against.
- Decides. Whether the two would interact — same page, overlapping audience, metrics that could contaminate each other — and how serious the overlap is.
- Tool.
check_conflictscompares the proposal against every running experiment and lists what overlaps and why it matters. - Human in the loop? Yes, a launch reviewer's decision. The agent never blocks a launch — it ensures the reviewer sees the overlap before go-live, not after the data is contaminated.
The 60-minute cut
Build use case 1: notice on a clock, analyse with memory, gate the launch.
In scope:
- Four synthetic experiments (id, hypothesis, variant description, target metric, control/variant samples and conversions) — one clear win, one clear loss, one inconclusive, one segment-specific win.
- Scheduled check via
this.schedule()for experiments whose sample count crosses a threshold you pick, every 60 seconds so it fires on stage (say "production would check hourly"). - One tool interpreting the result, one drafting a follow-up proposal, stored together as the experiment's analysis.
- A Workflow proposing the follow-up, pausing on
step.waitForEvent()before it's "launched." - A one-page view of every experiment: verdict, proposed follow-up, approval state.
Out of scope, and say so: a real statistics engine, real traffic splitting, integration with an actual experimentation platform, authentication, multi-armed bandits.
The demo that wins. Let the schedule fire on stage and watch an experiment cross the
readiness threshold on its own — show the interpretation citing a prior iteration ("the
last test on this flow showed X, this confirms it for mobile"), then the follow-up sitting
in PENDING APPROVAL until you launch it live.
Primitives — exactly three
- Schedules (
this.schedule()). An experiment becomes ready on its own clock — samples or a time box — not a pushed event. Keeps the readiness check next to the experiment history it needs to interpret the result. - AI Search over your own documents. A follow-up is only useful if it isn't a test you
already ran. Grounding
design_followupin an indexed archive of past write-ups stops it confidently re-proposing something the team already rejected — a larger model can't cite a test it was never shown. - Workflows. Launching a follow-up spends real traffic and time, and must be
exactly-once — a retry must not launch the same test twice.
step.waitForEvent()holds the proposal open until an experiment owner approves it, at no cost while waiting.
Skip Browser Rendering — nothing external to render, the loop reasons over your own
numbers and document archive. Skip Durable Object state as a named choice — you get it
free from the Agent class holding each experiment's history.
Paste-ready starter prompt
Scaffold the starter first:
npm create cloudflare@latest -- team-platform-experiment-followup --template cloudflare/agents-starter
cd team-platform-experiment-followup
Then paste this into your coding agent:
I'm working in a fresh clone of Cloudflare's agents-starter template. The agent code is in
src/server.ts and the React client is in src/client.tsx. I have 60 minutes. Keep the
existing chat agent working — extend it, don't replace it.
Build an experiment-analysis agent that designs its own follow-up test and never launches
one without approval.
1. Add a hardcoded array of 4 synthetic experiments to src/server.ts. Each has: experimentId,
hypothesis, variantDescription, targetMetric, controlSamples, controlConversions,
variantSamples, variantConversions, and a readySampleThreshold. Make one a clear win, one
a clear loss, one inconclusive (samples below threshold), and one a win with a note that
it is segment-specific. Invented data only.
2. Add a hardcoded array in a separate file of 3 synthetic "past experiment" summaries — id,
hypothesis, and outcome — that a real archive would hold. Invented content only.
3. Add a tool called analyze_experiment. Given an experimentId, if combined samples are below
readySampleThreshold, return status "not_ready" and stop. Otherwise use a Workers AI model
to return JSON: verdict (win, loss, inconclusive), liftPercent, confidence (low, medium,
high), and a two-sentence plain-language interpretation.
4. Add a tool called design_followup. Given an experimentId and its analysis, compare against
the past-experiment archive and use a Workers AI model to return JSON: proposedHypothesis,
proposedVariant, targetMetric, and a citation naming which past experiment (if any)
informed the choice, or null if none did. Never fabricate a citation to an experiment not
in the archive.
5. Use this.schedule() to run a sweep every 60 seconds. For each experiment not yet analysed
whose combined samples exceed readySampleThreshold, run analyze_experiment then
design_followup, and store both keyed by experimentId in the Agent's SQLite storage via
this.sql, updating rather than duplicating on re-runs.
6. Add a Cloudflare Workflow called FollowupLaunch in a new file, with steps as step.do():
a) propose — record the proposed follow-up
b) await_approval — step.waitForEvent() with a generous timeout, waiting for an event of
type "followup-decision"
c) record — record whether the follow-up was launched or declined, and by whom
Import WorkflowEntrypoint, WorkflowStep and WorkflowEvent from "cloudflare:workers", and
add the workflow binding to wrangler.jsonc.
7. Add routes:
POST /launch/:experimentId starts a FollowupLaunch workflow for that experiment's
proposal
POST /decide/:experimentId sends the "followup-decision" event with approved true or
false
GET /experiments HTML page: every experiment, its verdict, its proposed
follow-up and citation, and its launch approval state
Requirements: TypeScript. Route every Workers AI call through AI Gateway by passing
{ gateway: { id: "agenthack" } } as the options argument. Run `npx wrangler types` after
changing wrangler.jsonc. Then deploy with `npx wrangler deploy` and give me curl commands
that show the schedule firing and one experiment going through propose, decide, and record.
The Worker name team-platform-experiment-followup follows the shared-account rule
<team_prefix>-<slug>. Eight teams deploy into one account today, so if the Scoping agent
issued you a different prefix, use that one instead.
What "production" looks like
- Replace the hardcoded numbers with a real statistics engine. Sequential testing and confidence intervals are solved elsewhere — the agent interprets and proposes, not computes significance, so wire it to whatever engine backs your platform's real results.
- Index your actual experiment archive, not three invented entries.
design_followup's value scales with how much real history it can cite — start with a year of write-ups and measure how often engineers accept the proposal as-is versus rewrite it. - Track the acceptance rate of proposed follow-ups over time. That number shows how much of the analyst's job the agent is doing versus how much noise it generates — and it's the number that justifies widening its autonomy, or doesn't.
Next: Level Up explains each primitive, the cheat sheet has the snippets.