Run an A/B test end-to-end with AgentHog as the source of truth — create a feature flag, wire the variant read into the app, verify exposure is flowing, open an experiment window with the right...
An experiment is an analysis window on a multivariate feature flag. The flag delivers
variants (deterministic per-user hashing in the SDK — no assignment service); the
experiment compares treatments against a control on a metric and reports each arm's
chance to beat it. Everything runs through the ah CLI; every mutation needs a
write-scope token.
Follow the phases in order. Each ends with a check — do not proceed past a failed check.
ah events). If not: stop and run the agenthog-integrate skill first.ah is authenticated with write scope: ah whoami shows the project and
scope: write. If read-only, ask the user to run ah login --write.ah events top) or a goal (ah goals list). If the metric event doesn't exist yet,
instrument it and verify it arrives before doing anything else.ah flags create checkout_cta --variants control:50,b:50 --desc "new checkout CTA copy"
[a-z0-9_-], ≤64 chars. Variant names the same. One arm should be
named control unless the user says otherwise.--variants control:34,b:33,c:33. Percentage rollout of a non-experiment
feature: ah flags create new_nav (boolean) then ah flags rollout new_nav 10.--traffic 100) unless the user wants a limited
blast radius; you can ramp up later — ramping up never reshuffles assignments.The pattern is identical on every platform: read the flag, branch, and make the
fallback path the control experience. undefined means "no ruleset yet / not
enrolled / killed" — the app must work when the flag system says nothing.
Web (window.agenthog), React Native (useAgentHog()), Capacitor (AgentHog):
await agenthog.flagsReady() // avoids the first-visit undefined window
const v = agenthog.flag('checkout_cta') // 'control' | 'b' | undefined
if (v === 'b') { /* treatment */ } else { /* control AND fallback */ }
Never emit $exposure events or $ff/* props yourself — the SDK does both on the
first flag() read. Never branch on anything except the flag() return value.
Check before continuing (exposure must flow BEFORE the window opens):
ah events --name '$exposure' --since 1h # rows appear as you exercise the app
ah events --by flag:checkout_cta --since 1h # events split by variant
Use agenthog.overrideFlag('checkout_cta', 'b') to force each arm during this check —
overrides never pollute experiment data. Clear with overrideFlag(key, null).
ah experiments start checkout_cta --metric checkout_completed \
[--min-days 1|7] [--secondary e1,e2] [--guardrail app_error:up] [--hypothesis "..."]
--min-days gates only the verdict badge. Choose by metric horizon: 1 when the
metric fires in the same session as exposure (onboarding, activation, checkout);
keep the default 7 for anything with weekly rhythm (retention, repeat usage).errors:up, activation:down.ah experiments results checkout_cta [--json]
collecting (n of 100; day d of N) — report progress, do NOT characterize which
arm is ahead. Small-sample rates mislead.readable, no ★ — report chance-to-beat and credible intervals with the caveats
printed. "68% likely better" is not a winner; say what would settle it (more users
or more days).★ likely winner — safe to recommend shipping. Quote the lift and chance-to-beat.caveat: lines verbatim (day-of-week coverage, excluded multi-variant
users). If a guardrail shows ⚠, lead with that — a primary-metric win that spikes
errors is not a win.--json field names are a stable contract for scripting.Do not stop a live experiment, change its weights, or declare winners the tool did
not declare, unless the user explicitly asks (weight edits require --force for
exactly this reason).
ah experiments stop checkout_cta --winner b --conclusion "..." then
ah flags weights checkout_cta b:100. The flag now serves the winner to everyone.ah experiments start again —
a fresh window on the same flag; results never mix across windows.ah flags disable checkout_cta is the kill switch — every
client falls back to code defaults within ~2 minutes.Weeks later, once the winner is the only path anyone gets:
flag() read from the code; the winner's code
becomes the only path.ah flags archive checkout_cta — leaves the SDK payload, keeps history.ah events --name '$exposure' --since 48h shows nothing for the key
after the archived deploy is live.ah flags show <key> matches what the user asked for (variants, traffic, state)$exposure events arrive and ah events --by flag:<key> splits by variant--min-days, and the
user knows the expected duration from the baseline hint--winner, and (when
retiring) the flag archived and its code path deletedTimeline of everything you did: ah changes list --kind experiment. Flags and
results are also visible at https://agenthog.io/flags. To write the results up as a shared
report the whole organization reads in the dashboard, use the agenthog-report skill, which ships alongside this one.