·
Last changedVersion:
No hardening report available.
You're using a skill that guides you through setting up and running experiments in LaunchDarkly. Your job is to design the experiment, create it with the right metrics, treatments, and flag config, start data collection, evolve the design between iterations when needed, and stop with a winner. Never create a metric or experiment until the user approves a complete design, never start an iteration until the user says to start, and never change a flag unless the user asks. See Before you create anything for required pieces, suggestions, and labels. See the workflow for gathering and approval, Step 1 for the event check, and Step 4 for starting.
This skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment. Configure that server with least privilege permissions. Limit it to the projects and environments this work needs and to experiment and metric actions. Grant flag write permission only if you want the agent to create or turn on flags.
Required MCP tools:
create-experiment — create a new experiment with its initial iteration (hypothesis, metrics, treatments, flag config).start-experiment-iteration — begin collecting data for an experiment's current draft iteration.get-experiment — check experiment status, treatments, metrics, and current iteration.Optional MCP tools:
list-experiments — browse existing experiments in the project.update-experiment — update fields on the experiment or its current iteration. Honours mutableFieldsByStatus, so what's editable depends on whether the iteration is not_started, running, or stopped. Returns rejected inputs under skipped.save-and-start-experiment-iteration — the API-recommended way to change locked fields on a running experiment. Stops the current iteration, creates a new draft with the supplied field updates, and starts it in one call.stop-experiment-iteration — stop the running iteration. You must declare a winner: pass the winningTreatmentId (and a winningReason). If no variation outperformed, pick the baseline/control as the winner.list-metrics, create-metric, list-metric-events — manage metrics referenced by the experiment.get-flag — read one flag's targeting in an environment: whether it is on, the variation a rule serves, its off variation, and whether that rule is a percentage rollout.list-flags — search flags in a project by name or key.create-flag — create a feature flag in a project. It is off in every environment until turned on.get-flag-status-across-envs — read a flag's status in each environment (new, active, launched, or inactive).search-contexts — find stored contexts in an environment by kind, to see which context kinds are in use.Experiments in LaunchDarkly measure the impact of feature flag variations on key metrics. An experiment consists of:
allocationPercent; the values across treatments should sum to 100.flagKey, ruleId, and flagConfigVersion of the targeting rule that drives the experiment.not_started status, becomes running when started, transitions to stopped when ended.holdoutId).create-experiment).start-experiment-iteration), only after the user explicitly says to start.get-experiment).treatments, metrics, or methodology by calling save-and-start-experiment-iteration, which stops the current iteration, creates a new draft with your changes, and starts it. That call starts data collection, so make it only after the user explicitly says to start.stop-experiment-iteration).hypothesis string from the user. See Before you create anything.baseline: true.These four must come from the user. Never fill them in:
If any of these four are missing, leave them blank until the user supplies them. They go in the gather message. See the workflow. Once the user names the flag, see Step 2.
Control variation: which of those variations is the baseline (baseline: true). If the user named it, use that. If they did not:
get-flag-status-across-envs reports that environment as inactive. A flag is brand new if you created it in this conversation, or get-flag-status-across-envs reports that environment as new: the flag was created fewer than seven days ago and has never been evaluated there. A percentage rollout is a targeted rule that splits traffic across variations instead of serving one. get-flag shows which. inactive means the flag has not been evaluated for at least seven days, so no one is currently being served the off variation.Randomization unit: the context kind the experiment randomizes on. If the user named it, use that. If they did not, call search-contexts for this project and environment. Request as few contexts as the tool allows. Use the result only to learn which context kinds exist and their counts. Report only those kinds and counts, and keep context keys, names, and other attributes out of your replies. Suggest user only when a kind of user returns contexts and filter kind notEquals "user" returns totalCount 0, so user is the only context kind in use. If search-contexts is unavailable, returns no contexts, or any other kind is stored, ask and leave it blank.
Label every suggested value in the design as suggested, with a one-line reason, for example Control (suggested, what users see today): Start free trial. The user can change any suggestion before approving. Approving the design accepts the suggestions still shown in it.
Settings the user did not mention can stay on LaunchDarkly's defaults. List each default you are using in the design:
allocationPercent across the variations the user named (two variations is 50/50). The values must sum to 100.methodology unless the user chooses one. If they choose one, send that value and show it here instead of this default. A Bayesian choice is methodology "bayesian".dataSource "launchdarkly".canReshuffleTraffic true.Leave analysisConfig unset unless the user set it, and say that in the design. The randomization unit is never one of these defaults.
If nothing is missing, skip the gather message and go straight to the design. Otherwise gather every missing piece in one message before you show any design, then wait:
get-flag cannot find it: say so and offer three choices in one message: correct the key (list similar flags from list-flags); create the flag themselves, then tell you to continue; or have you create it. For that last choice, propose the project, key, name, type, and variations from their design, say it will be created off, and wait for an explicit yes before calling create-flag. If launchdarkly-flag-create is installed, follow it for that step. That skill must still follow this skill's approval gate. Create only the project, key, name, type, and variations the user approved, create the flag off, and leave it and every other flag otherwise unchanged. If it asks for anything beyond that, stop and ask the user. After the flag exists, continue setup. Never create a flag unless they pick that choice and approve the details.custom, pageview, or click), what it is based on (event key, URL match, or click selector), and how it is measured (share of units who converted, a total count, or an average), when the user has not already made that clearlist-metrics and get-flag are fine while you gather this. create-metric and create-experiment are not.
If the user's wording already makes one of these clear, do not ask about it. "The share of users who sent the cta-clicked event" already names the measure, the kind, and the event key.
Show the design only when nothing is blank. Never show a design with a missing value. Include every piece gathered above, the environment, the other treatments, flag config (flagKey, ruleId, flagConfigVersion), and every default you are applying. Statistics reads LaunchDarkly default (frequentist, sequential testing) unless the user chose a methodology, in which case show their choice. Label each suggested value. See Before you create anything.
STOP HERE until the user approves the design.
Create the metric and the experiment only after the user explicitly approves a complete design they have seen. If the user changes anything after seeing it, show the updated design and ask once more.
list-metrics to find existing metrics. The user names the primary metric.list-metric-events.pageview or click.custom and named its event key, call list-metric-events for that event key. Either way, the metric goes in the design once nothing else is blank. If the event is not reaching LaunchDarkly, include a warning in that design: the event has not arrived in that environment yet. List at most 10 custom event keys list-metric-events returns for that environment, preferring keys similar to the one the user gave, so a typo is easy to spot. Say the user can correct the event key, or approve as is if the tracking is not deployed yet. If they correct the event key, that is a change: call list-metric-events again for the new key and show the updated design, per the approval rule. On approval, create the metric and the experiment as normal, even if the event has not arrived.list-metric-events only after the user has said the kind is pageview or click.primarySingleMetricKey or primaryFunnelKey.| Goal | Metric type | Example key |
|---|---|---|
Conversion | Custom conversion |
|
Performance | Custom numeric |
|
Engagement | Custom conversion |
|
Revenue | Custom numeric |
|
You need the ruleId and current flagConfigVersion of the flag rule that will drive the experiment. Use get-flag on the flag (or its environment-scoped status) to find them. The fallthrough rule's id is the string "fallthrough".
See the gather and approval rule above, then call create-metric for a new metric and create-experiment. See Step 1 for the event check.
Call create-experiment. The top-level fields describe the experiment; the nested iteration object describes the first data-collection window. The values in the example below are the shape of the call, not values to copy. This includes environmentKey. Always use the environment the user named. See Before you create anything for the randomization unit.
Omit methodology unless the user chose one. When they did, set it to that value ("bayesian", "frequentist", or "export_only").
Useful optional top-level fields:
holdoutId — attach an existing holdout.dataSource — "launchdarkly" (default), "snowflake", or "databricks".methodology — send only when the user chooses one: "bayesian", "frequentist", or "export_only". Omit it otherwise. LaunchDarkly's default is frequentist with sequential testing.analysisConfig — set only the fields the user set. Leave it unset to keep sequential testing on.Useful optional iteration fields:
attributes — array of context attribute keys to slice results by (e.g. ["country", "device"]).covariateId — covariate CSV id for stratified sampling.canReshuffleTraffic — defaults to true; set false to lock users to their initial variation when allocations change.Creating the experiment leaves the iteration in not_started. Call start-experiment-iteration only after the user explicitly says to start. That same wait applies to any other call that starts an iteration.
Before starting, the API requires that:
randomizationUnit, andallocationPercent.If the primary metric is a custom event, call list-metric-events again right before starting. If the event is arriving, start as normal once the flag is on. If it still is not arriving, the experiment can start but results will stay empty until the event arrives, so ask whether to start anyway.
If the flag is off in that environment when the user says to start, don't change the flag. Tell the user the flag must be on in that environment, and that turning it on starts serving its variations to users there. Ask whether they want to turn it on themselves or have you do it, and wait for an explicit answer before calling any tool that changes the flag. Offer to do it yourself only when the LaunchDarkly MCP server already provides a tool that changes the flag. Otherwise ask the user to turn it on themselves and wait for them to tell you to continue. Before you change the flag, restate the project, the flag key, the environment key, and the variations it will serve to users there. Proceed only after the user gives an explicit yes for that exact environment. An earlier or general yes does not count, and production needs this confirmation every time. Once the flag is on, call get-flag again to get the current flagConfigVersion, tell the user the old and new versions, and update the draft to use the new one only after they confirm, then start.
If the flag is off and the custom event still is not arriving, raise both in one message, the flag question and whether to start anyway, and wait for that one answer. Do not ask them separately.
Pass changeJustification if you're restarting after a prior iteration was stopped.
get-experiment and confirm currentIteration.status === "running".Most structural fields (treatments, metrics, methodology, hypothesis, …) are locked while an iteration is running. Two ways to change them:
update-experiment will let through anything mutableFieldsByStatus permits in the running state (typically just metadata like name, description, maintainerId, tags, plus appending metrics/attributes). It surfaces rejected fields under skipped with a reason. Before any update-experiment call, show the fields and values you will change and get the user's explicit approval.save-and-start-experiment-iteration. It stops the current iteration, creates a new draft with the supplied field updates applied, and starts it in one call. Inputs match update-experiment, plus changeJustification. Mutability is checked against not_started since updates land on the new draft.save-and-start-experiment-iteration ends the current iteration and starts the new one. Before calling it, show the current and new treatments, allocations, metrics, and other changed fields side by side. State that the current iteration ends now and cannot be resumed, and that the new iteration starts serving the new allocation to users in the named environment right away. Call it only after the user explicitly confirms that change and says to start.
Example: swap the treatment allocation and add a metric in a single call. The values below show the shape of the call, not values to copy.
When the results support a decision, tell the user and recommend stopping. Stop the iteration only after the user explicitly says to stop. Before calling stop-experiment-iteration, show the proposed winning treatment name, its winningTreatmentId, and the full winningReason, labeling an inconclusive result as inconclusive. Call it only after the user approves those values. For a frequentist experiment that decision is statistical significance. For a Bayesian experiment it is the probability to beat baseline or the probability to be best. Quote only the statistic for the methodology in use. A winning treatment is required to stop — LaunchDarkly does not let you end an iteration without declaring a winner. Pass the winning treatment's id (returned in get-experiment as _id on each treatment) plus a winningReason.
If the experiment was inconclusive or no variation beat the control, declare the baseline/control treatment as the winner and say so in winningReason (e.g. "Inconclusive — keeping control"). There is no "stop without a winner" path.
Name the decision statistic in winningReason. Frequentist: significance, or that it was not significant. Bayesian: probability to beat baseline or probability to be best. Do not quote a Bayesian probability, or a prior, on a frequentist experiment.
Report results:
winningTreatmentId (the control/baseline if inconclusive).| Situation | Action |
|---|---|
A new primary metric's kind or event key is unknown | Gather them before the event check. See Step 1. |
The new metric is a custom event and the user named its event key | Warn in the design if it has not arrived; still create on approval. See Step 1. |
Flag, variations, environment, hypothesis, or primary metric is missing | Ask, and leave them blank. See Before you create anything. |
The named flag does not exist in the project | Offer to correct the key, have them create it, or create it after they approve the details. Never create a flag otherwise. See the gather rule. |
User did not name the control, and the rules say to ask | Ask for the control; don't suggest one. See Before you create anything. |
User did not name the control, and the rules say to suggest | Suggest the control and label it. See Before you create anything. |
User did not name the randomization unit | Suggest or ask for the randomization unit. See Before you create anything. |
Design not approved | Leave |
User has not said to start | Leave the iteration in |
User has not said to stop | Leave the iteration running. |
A field change through | Show the change and get explicit approval first. See Step 6. |
Flag is off when the user says to start | Don't change the flag; ask first. See Step 4. |
Flag has no variations to compare | Add variations only when the user explicitly asks and confirms the restated flag key, environment, and variations to add. Otherwise say which variations exist and ask. |
You don't know the flag's | Use |
Experiment already exists | Use |
Need to change locked fields mid-experiment | Use |
| Inspect the |
list-metric-events before Step 1 says to, or block creation because an event has not arrived. See Step 1.create-metric or create-experiment before the approval rule above is satisfied.start-experiment-iteration or save-and-start-experiment-iteration until the user explicitly says to start.stop-experiment-iteration only after the user explicitly says to stop and approves the winner and reason.iteration on create-experiment — it's required.baseline: true on more than one treatment.allocationPercent values fail to sum to 100 across treatments.update-experiment while the iteration is running — reach for save-and-start-experiment-iteration instead.Bring Chainguard's hardening pipeline to your first-party skills — custom rulesets, automated remediation, full audit trail.
skills.cgr.dev/public/github.com/launchdarkly/skills/experiments/launchdarkly-experiment-setup:latest
Apache-2.0
HARDENING.md
LICENSE
SKILL.md