From growthbook
Launch a GrowthBook A/B test end-to-end via the REST API — create the experiment, prep the feature flag, wire the experiment-ref rule, and start the experiment. Use when the user says "launch this experiment", "create the experiment", "wire up the A/B test", "kick off the test", "set up X as an experiment in GrowthBook", "start the experiment for flag Y", or "I already have a flag and want to run an experiment on it". Works for both experiment-first (creates the flag) and flag-first (detects the existing flag via the reuse path and wires the experiment to it). For designing the spec first, use experiment-design. For stopping a running experiment, use experiment-stop. For interpreting results, use experiment-analyze.
How this skill is triggered — by the user, by Claude, or both
Slash command
/growthbook:experiment-launchThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Launch a GrowthBook A/B test end-to-end: create the experiment in draft, prep or reuse the feature flag, add the experiment-ref rule on a fresh draft revision, then call `/start` to publish the rule and flip the experiment to running. Handles the approval-required and pre-launch-checklist failure paths.
Launch a GrowthBook A/B test end-to-end: create the experiment in draft, prep or reuse the feature flag, add the experiment-ref rule on a fresh draft revision, then call /start to publish the rule and flip the experiment to running. Handles the approval-required and pre-launch-checklist failure paths.
All API calls go through the bundled helper: ${CLAUDE_PLUGIN_ROOT}/scripts/gb-call. It needs GB_API_KEY — set in your shell, or written to ~/.config/growthbook/.env by /growthbook:gb-setup. If it's missing or invalid, gb-call's error message points back at /growthbook:gb-setup.
Collect from the user (or earlier skill output) before starting. Prompt for what's missing.
[a-zA-Z0-9_-]{name, value}, length ≥ 2. The first entry is the control. Values are serialized as strings on the rule (booleans → "false"/"true", numbers → "42", JSON → JSON-encoded string).templateMetadata.name/description returned by /v1/experiment-templates. If omitted and templates exist, ask the user to pick one or skip.If no template is used, also collect (or resolve interactively in step 2):
id, device_id, etc.). Must equal the identifierType of the assignment query selected on the datasource.assignmentQueriesTrack progress with this checklist. Do not skip or reorder.
- [ ] 1. Pick a template (or skip)
- [ ] 2. Resolve hash attribute → datasource → assignment query → metrics (no-template path only)
- [ ] 3. Create the experiment in draft
- [ ] 4. Create or reuse the feature flag
- [ ] 5. Add the experiment-ref rule on a fresh draft revision
- [ ] 6. Prompt user to QA the experiment and feature flag config
- [ ] 7. POST /start; branch to 7a (approval) or 7b (checklist) on 400
- [ ] 8. Report links and state
gb-call GET /api/v1/experiment-templates
name — description plus a final "Skip" option. If a template description was provided, pre-select the best match by templateMetadata.name/description and confirm. Never invent a template.If chosen, capture: id (becomes templateId), datasource, exposureQueryId, hashAttribute, goalMetrics, statsEngine, targeting. Templates inject all of these; skip step 2 entirely.
If the template's type is "multi-armed-bandit", halt and confirm with the user. Bandits behave very differently from standard A/B tests (dynamic traffic allocation, per-arm probabilities instead of winner/loser, different analysis), and this skill's launch and analysis assumptions are written for type: "standard". Recommend they configure bandits in the UI for now.
No-template path only. Order matters — pick hash attribute first so you don't trap yourself on a datasource that can't randomize on it.
2a. Pick the hash attribute. Filter to attributes flagged as hashAttribute:
gb-call GET /api/v1/attributes
Surface attributes where hashAttribute === true and archived !== true. Ask the user to pick. If the filtered list is empty, halt — tell the user to mark at least one attribute as a hash attribute under Settings → Attributes in GrowthBook.
2b. Pick the datasource.
gb-call GET /api/v1/data-sources
Resolve English name or ID against dataSources[].name / id. Capture DATASOURCE_ID and keep the full object — 2c reads its assignmentQueries.
2c. Pick the assignment query. Filter dataSources[].assignmentQueries to entries where identifierType === HASH_ATTRIBUTE:
<HASH_ATTRIBUTE> in GrowthBook.name (identifierType=<value>) — <description> and let the user pick.If assignmentQueries is empty entirely, halt and tell the user to configure one in GrowthBook before re-running.
2d. Pick metrics, filtered by datasource. The API rejects metrics from a different datasource than the experiment's:
gb-call GET '/api/v1/fact-metrics?datasourceId=<DATASOURCE_ID>&limit=100'
gb-call GET '/api/v1/metrics?datasourceId=<DATASOURCE_ID>&limit=100'
Help the user pick:
GOAL_METRIC_IDS). Ideally one, two max — push back at three or more and demote the rest to secondary or guardrail.SECONDARY_METRIC_IDS) — supporting context.GUARDRAIL_METRIC_IDS) — defensive. Push back if they name none; every experiment needs at least one. Guardrails are excluded from multiple-comparison correction by design.Set trackingKey to the feature flag name so the SDK ties exposures to the flag. Each variation needs a stable string key ("0", "1", ...) and name. Variation values live on the flag rule (step 5), not on the experiment payload.
Template path — do NOT also send datasourceId / assignmentQueryId; the template provides them and the API rejects the combination.
{
"templateId": "<from step 1>",
"trackingKey": "<flag-name>",
"name": "<experiment name>",
"hypothesis": "<hypothesis>",
"variations": [
{ "key": "0", "name": "Control" },
{ "key": "1", "name": "Treatment" }
],
"project": "<project id, omit if org-wide>"
}
No-template path — send everything from step 2 explicitly:
{
"datasourceId": "<DATASOURCE_ID>",
"assignmentQueryId": "<ASSIGNMENT_QUERY_ID>",
"hashAttribute": "<HASH_ATTRIBUTE>",
"trackingKey": "<flag-name>",
"name": "<experiment name>",
"hypothesis": "<hypothesis>",
"variations": [
{"key": "0", "name": "Control"},
{"key": "1", "name": "Treatment"}
],
"metrics": ["<GOAL_METRIC_ID>"],
"secondaryMetrics": [<SECONDARY_METRIC_IDS as JSON array>],
"guardrailMetrics": [<GUARDRAIL_METRIC_IDS as JSON array>],
"project": "<project id, omit if org-wide>"
}
Notes:
metrics is the goal-metric array; with the one-goal rule it should always be length 1.secondaryMetrics / guardrailMetrics entirely if the user picked none. Don't send empty arrays.Then POST:
echo '<payload-json>' | gb-call POST /api/v1/experiments -
Capture from the response:
experiment.id — used in steps 5 and 6.experiment.variations[].variationId — the string ID for each variation (e.g. var_abc123). You need these in step 5; they are required on the experiment-ref rule.Try create first unless the user said the flag already exists. The flag must default to the control value (variation 0's value), serialized as a string. Default all environments to off as well.
{
"id": "<flag-name>",
"valueType": "<boolean|string|number|json>",
"defaultValue": "<control value as string>",
"description": "Drives experiment: <experiment name> (<exp_id>)",
"project": "<project id, omit if org-wide>"
}
echo '<payload-json>' | gb-call POST /api/v2/features -
Reuse path — fetch and validate:
gb-call GET /api/v2/features/<flag-name>
Run these compatibility checks against the response. Each row says what to do on failure:
| Check | Action on failure |
|---|---|
archived === false | Halt. Tell the user to un-archive the flag in the UI before re-running. |
valueType matches the experiment's <boolean|string|number|json> | Halt. Surface both values; do not silently change types. |
project matches the experiment's project (when set) | Halt. Reusing a flag from another project misroutes the experiment. |
defaultValue equals the control value (string-compared) | Warn, do not halt. The experiment rule supplies the variation values; the existing default applies only when the rule doesn't match. Ask "continue?" |
No existing rule with type === "experiment-ref" AND experimentId === <exp_id> already attached | If one exists → this experiment is already wired up. Skip step 5 and jump to step 6. |
No conflicting experiment-ref rule for another running experiment in the same environments | Warn, do not halt. Ask "this flag is currently driving experiment <other_id>; add another rule alongside it?" |
When all checks pass, capture the flag's identity and proceed to step 5. Do not mutate the existing flag here — all mutations go through the draft revision in step 5.
Use the literal version new to create a draft and add the rule in one call. The path segment new is a magic value that creates a draft branched off the live revision atomically. If the feature has multiple environments, prompt the user for which environments to go live in, and ensure this rule turns on the feature flag for those environments in addition to adding the rule to those environments.
{
"rule": {
"type": "experiment-ref",
"experimentId": "<exp_id from step 3>",
"enabled": true,
"allEnvironments": true,
"variations": [
{
"value": "<variation 0 value as string>",
"variationId": "<var_id from step 3, position 0>"
},
{
"value": "<variation 1 value as string>",
"variationId": "<var_id from step 3, position 1>"
}
],
"description": "Experiment: <experiment name>"
}
}
echo '<payload-json>' | gb-call POST /api/v2/features/<flag-name>/revisions/new/rules -
variations[] must have one entry per experiment variation, in the same order as step 3. Each entry needs both value (serialized as a string) and variationId (the string ID captured in step 3) — variationId is required by the v2 features validator and omitting it returns a 400. Capture the returned version for the draft revision.
Do not publish the revision here. Step 7's /start call auto-publishes the draft when it flips the experiment to running.
The draft revision and experiment are reversible up to this point; step 7's /start publishes the rule and flips the experiment to running.
If the user seems to want you to also embed the feature flag in the codebase, now is a good time to do that.
Stop and surface the UI links so the user can QA the flag default, the rule's variation values, and the experiment's targeting and metrics in the GrowthBook UI:
<host>/experiment/<exp_id><host>/features/<flag-name> (draft revision <version>)Derive <host> from GB_API_URL by swapping api. → app., as in step 8. Wait for the user's explicit go-ahead before proceeding to step 7.
gb-call POST /api/v1/experiments/<exp_id>/start '{}'
The /start endpoint does two things server-side:
publishPendingFeatureDraftsForExperiment).Either can fail with a 400. Branch:
2xx → step 8.The experiment and flag exist; only the rule revision is stuck in draft. Halt and offer the user three concrete paths:
Your org requires approval before this feature flag rule can go live, and
/startwill not flip the experiment to running until the rule is published. Revision<version>on<flag-name>is in draft state. Pick one:A. Standard review flow (recommended) — I'll request a review now. A teammate (not you, since you created the draft) approves it in the GrowthBook UI at
<host>/features/<flag-name>, then you re-run me and I'll resume from/start.B. Org-wide bypass — an admin enables "REST API always bypasses approval requirements" in Settings → General → Approvals. After that, re-run me.
C. Per-token bypass — use a Personal Access Token whose role grants
bypassApprovalCheckson this project (Admin or custom role). UpdateGB_API_KEY, then re-run me.
If the user picks A, request review on the draft and stop:
echo '{"comment":"Auto-requested by experiment-launch for <exp_id>"}' \
| gb-call POST /api/v2/features/<flag-name>/revisions/<version>/request-review -
Do not attempt submit-review yourself — the API rejects self-approval on a draft you created. Stop and tell the user to re-run after approval.
If the user picks B or C, stop with a one-line note. The existing draft will pick up the new permission and publish on retry.
Do not silently retry /start, ignore the error, or discard and recreate the draft to work around the policy.
The REST API does not expose a separate start-checklist endpoint — the failure body from /start is the canonical source. Parse it and surface the incomplete items verbatim:
The pre-launch checklist isn't complete. The
/startcall returned:
<full error body>Fix the listed items in the GrowthBook UI at
<host>/experiment/<exp_id>, then re-run me — I'll jump straight back to/start.
Only retry /start with {"skipChecklist": true} in the body if the user explicitly asks to bypass. Never default to bypassing; the checklist is intentional friction.
Print a summary:
idhashAttribute)allRequiredComplete=true)running after a clean /start)GB_API_URL by swapping api. → app.):
<host>/experiment/<exp_id><host>/features/<flag-name>hashAttribute and assignmentQuery.identifierType must match. Mismatch is a real and recoverable error; surface the fix paths in step 2c./v1/metrics and /v1/fact-metrics by datasourceId in step 2d.templateId with datasourceId/assignmentQueryId. The template path supplies those; the no-template path supplies them explicitly. Mixing yields a 400."false"/"true" for booleans, "42" for numbers, JSON-encoded text for json.valueType, wrong project, or a conflicting rule will break the experiment or step on a teammate's in-flight test./start in step 7. Do not call publish endpoints separately - Approval failures: do not self-approve. The API blocks approval on drafts you created. Walk the user through 6a instead.skipChecklist: true after the user explicitly opts in.GET /api/v1/experiment-templates — list templatesGET /api/v1/attributes — filter to hashAttribute=trueGET /api/v1/data-sources — pick datasource and assignment queryGET /api/v1/fact-metrics?datasourceId=…, GET /api/v1/metrics?datasourceId=… — pick goal / secondary / guardrailPOST /api/v1/experiments — create the draft experimentPOST /api/v2/features — create the linked feature flag (when not reusing)GET /api/v2/features/<id> — fetch the flag for the reuse compatibility checksPOST /api/v2/features/<id>/revisions/new/rules — atomic draft + add experiment-ref rulePOST /api/v2/features/<id>/revisions/<version>/request-review — used only in the 6a "request review" pathPOST /api/v1/experiments/<id>/start — publish the draft revision and start the experiment. Body accepts {"skipChecklist": true} to bypass the pre-launch checklist when the user explicitly opts in. Failure responses carry the canonical reason in the body — there's no separate start-checklist GET to query.experiment-design — if no spec exists, route back here first.flag-search — to find an existing flag ID when you only have a name or description.experiment-analyze — after the experiment is running and traffic accumulates.experiment-stop — when results are settled.<host>/metrics (or <host>/fact-tables for fact metrics) before re-running this skill. No skill for that yet.npx claudepluginhub growthbook/skills --plugin growthbookGuides you through designing, creating, and running A/B experiments in LaunchDarkly—configuring metrics, treatments, flag rules, starting iterations, swapping treatments, and declaring a winner.
Add an experiment-ref rule to a GrowthBook feature flag to run an A/B test through that flag. Use when the user says "run an experiment through this flag", "add an A/B test to flag X", "link experiment Y to this flag", "set up variations on this flag for an experiment", "add an experiment-ref rule", or "wire up this experiment to the flag". For launching a full new experiment end-to-end, use experiment-launch. For editing the targeting conditions or scope of an existing experiment rule, use flag-targeting. For stopping an experiment and cleaning up its rule, use experiment-stop then flag-rules.
Guides the 3-step experiment creation flow: hypothesis, rollout, and analytics. Delegates rollout and metric setup to specialized skills.