Authoring a dif experiment
SkillFiles & storageAuthoring and iterating on dif.sh experiments, drafting frontmatter, choosing variants and weights, declaring audiences, and validating the file. Use whenever the user wants to create, draft, edit, or fix a dif experiment, or mentions A/B test, variant, audience, hypothesis, surface, exclusion group, or the commands dif new, dif validate, or dif build.
Use Authoring a dif experiment in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Authoring a dif experiment and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Authoring a dif experiment skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
What this skill tells your AI
The instructions your AI receives, as published by dif-sh/dif in skills/dif-author-experiment/SKILL.md and read by Ahel’s review.
Use this skill when you're drafting, editing, fixing, or iterating on a .md file under dif/experiments/active/. It covers the loop from dif new through dif validate to dif build.
Start here — read the context
Before drafting:
- Read
dif/context.jsonto see what experiments are currently active, on which surface, and how long they've been running. Ifdif/context.jsondoesn't exist this is a fresh repo — rundif buildonce to generate it, or readdif/experiments/active/*.mddirectly. - Read
dif/surfaces/<your-surface>.md— the## Learningslog shows what's already been concluded on this surface. Build on those findings; don't re-test something already answered.dif newwill also embed the last 3 learnings into the draft as an HTML comment, so you'll see them again in the file. Ifdif/surfaces/is empty or only has the defaulthome.mdfromdif init, run thedif-generate-surfacesskill first to produce the surface set before drafting. - Read
dif/config.yamlto see what audience attributes are declared. You can only use predicates over attributes listed there (E006); anything else needs to be added to the config first.
This isn't ceremony — the experiment file you draft is downstream of these three reads. Skipping them produces lower-quality experiments.
The happy path
dif new <kebab-id> --surface <surface-name>
# edit dif/experiments/active/<kebab-id>.md
dif validate # collects all errors at once
# fix any errors (see references/validation-errors.md)
dif build # also runs validate
git add dif/ && git commit
dif new writes a frontmatter stub with status: draft, today's date, owner from git config, and two default variants (control / variant_a at 50/50). It also embeds the surface's last 3 learnings as an HTML comment inside ## Brief. Your job is to fill in the hypothesis:, the ## Brief, the ## Rationale, and (usually) audience: and metrics:.
You can also pass --from <existing-experiment-id> to copy variants, audience, and exclusion_group from a prior experiment — useful for follow-up tests on the same surface.
What to fill in
hypothesis:— one sentence, falsifiable, naming both the change and the expected primary-metric outcome for a named audience. Example: "Bolder CTA copy will lift checkout conversion on mobile by 1–3% over 14 days without regressing latency."variants:— at least two. Weights must sum to exactly 100 (E005). Keepcontrolas the literal first id; the SDK treats it as the no-change branch. Variant ids are kebab-case.audience:(optional but usually present) —include/excludelists of attribute predicates. Attributes must be declared indif/config.yaml'saudience_attributes. Seereferences/audiences.mdfor the predicate grammar.metrics: primary:— the single metric this is moving. One primary metric per experiment, full stop. Addmetrics: guardrails:for metrics that must not regress.exclusion_group:(optional) — string key that lets two experiments on the same surface coexist. The runtime picks the earlier-created:one per user. Required when E007 fires.
The body has three sections:
## Brief— what you're testing and why. Reference the prior learnings comment thatdif newembedded.## Rationale— what signal prompted this (funnel report, ticket cluster, user research). Why now, why this approach over the alternatives.## Decision— leave empty.dif concludefills this.
Anti-patterns
- A hypothesis like "see if changing the button helps" — not falsifiable, no metric direction, no audience.
- Three variants with weights
50 / 30 / 30— sums to 110, fails E005. - Audience predicate
country: USwhencountryisn't inaudience_attributes— fails E006. Add the attribute first. - Two active experiments on the same surface with overlapping audiences and no shared
exclusion_group— fails E007. Pick: shared group, or narrow one audience so they're provably disjoint (e.g.country: USvscountry: UK). - Listing 3 guardrails "just in case" — guardrails should be real things that would change your ship decision. Three speculative ones dilute the signal.
Iterating with dif validate
dif validate collects every error in one pass and points at the file + line. Fix top-to-bottom; rerun until clean. Common shapes:
- E001 frontmatter parse error → check YAML indentation, quoting, the
---fences. - E005 weights → distribute so they total 100.
- E006 undeclared attribute → either add it to
audience_attributes(and createdif/audiences/<name>.ts) or remove the predicate. - E007 exclusion conflict → add shared
exclusion_groupto both files, or narrow one audience.
See references/validation-errors.md for every code with its fix.
Autonomous experimentation
If you're proposing the experiment yourself (not implementing one a human specified): the input is dif/context.json + dif/surfaces/<surface>.md Learnings. The Learnings log is the surface's institutional memory — read all of it, not just the last three lines. Propose hypotheses that build on or contradict prior findings. Don't propose tests that re-litigate something already concluded unless the conditions have meaningfully changed.
References
references/frontmatter.md— full schema and a complete worked example.references/validation-errors.md— every error and warning code with the exact fix.references/audiences.md— predicate grammar, theconfig.yamlpairing, thedif/audiences/*.tsresolver contract, and how exclusion groups differ from audience filters.
Signals
- GitHub stars
- 27
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
dif-author-experiment- Source
- github.com/dif-sh/dif
Related picks
Skill · mattpocock
The pick for TypeScripttypescript-pro
Skill · jeffallan
The pick for TypeScriptpptx
Skill · anthropics
More in Files & storagedocx
Skill · anthropics
More in Files & storageresearch
Skill · mattpocock
More in Files & storagecavecrew
Skill · juliusbrussee
More in Files & storage