Documentation.
dif.sh is a handful of CLI commands and a markdown format. These docs walk through both.
The CLI lives in your repo. Experiments are .md files under dif/. dif build compiles the active ones into a typed runtime client, an audience module, and
a dif/context.json your coding agent reads on session start. Nothing about the system
needs to live outside git.
Start with install, then the quickstart. After that, the four cards below cover the rest.
init · new · validate · build · qa · conclude · scaffold-audiences. read → 04 — sdk @dif.sh/sdk Tiny JS runtime, plus the React and Svelte adapters. Buckets the user, fires exposure events,
and, on Cloud, tracks metrics through dif.track(). read →Install
Three paths. They produce the same binary; pick whichever fits the machine.
Shell installer
One-line, no Node required. macOS and Linux only. Drops the binary at ~/.local/bin/dif by default.
$curl -fsSL https://dif.sh/install.sh | sh
Pin a release, or point the install at a different directory with DIF_INSTALL_DIR:
$curl -fsSL https://dif.sh/install.sh | sh -s -- --version v0.4.3 $curl -fsSL https://dif.sh/install.sh | DIF_INSTALL_DIR="$HOME/bin" sh
Homebrew
macOS and Linux. Easiest if you're already using brew.
$brew install dif-sh/tap/dif
npm wrapper
Works anywhere Node 18+ runs, including Windows. The package's postinstall script downloads the matching binary for your platform. The SDK and framework packages need Node 20.6+.
$npm install -g @dif.sh/cli
Quickstart
From an empty repo to a tested experiment rendering in your app.
1. dif init
Scaffold the workspace. One dif/ directory holds everything.
$dif init ✓ wrote dif/config.yaml ✓ created dif/experiments/{active,concluded}/ ✓ created dif/surfaces/home.md ✓ created dif/audiences/{locale,device_type}.ts ✓ added dif guidance to CLAUDE.md, AGENTS.md
2. dif new
Draft a new experiment. Owner comes from git config user.email.
$dif new checkout-cta-v2 --surface home → reading dif/surfaces/home.md found 0 prior learnings → drafted dif/experiments/active/checkout-cta-v2.md status: draft, owner: ada@acme.dev
Open the file, fill in the hypothesis, set status: active.
3. dif validate
Every check, run in one pass. Errors include the source location.
$dif validate ✓ all checks passed
4. dif build
Compile the runtime artifacts your app imports and the context file your agent reads.
$dif build ✓ validated 1 active experiment ✓ client → dif/generated/client.ts ✓ audiences → dif/generated/audiences.ts ✓ context → dif/context.json
5. Render it
Install the SDK, import the generated client once at boot, and call dif() at the render
site. Full reference on the SDK page.
$npm install @dif.sh/sdk
import "./dif/generated/client"; import { attributes } from "./dif/generated/audiences"; import { dif } from "@dif.sh/sdk"; dif.init({ userId: () => currentUser?.id ?? null, attributes: () => attributes(), }); const cta = dif("checkout-cta-v2", { control: () => "Place order", variant_a: () => "Get it today", }); button.textContent = cta();
Workspace layout
dif init creates a single dif/ tree. The generated files appear after dif build.
dif/ config.yaml context.json # written by dif build audiences/ locale.ts # one resolver per audience attribute device_type.ts experiments/ active/ concluded/ generated/ # gitignored client.ts audiences.ts surfaces/ home.md
dif/generated/ is gitignored. dif/context.json lives outside it and is
meant to be checked in, so coding agents and other repo tooling can read the active-experiment
summary on session start. dif init also adds a managed dif block to CLAUDE.md, AGENTS.md, .cursorrules, and .claude/skills/; pass --no-agent-files to skip it.
What's where
- The
.mdformat (frontmatter, surfaces, audiences, exclusion groups): format. - Every CLI command, every flag, every exit code: cli.
- The three Claude Code skills
dif initinstalls for authoring, concluding, and generating surfaces: skills. - The JS SDK (
dif.init(),dif(), sinks, exposure events, server assignment, and the React and Svelte adapters): sdk. - The full
dif/config.yamlschema: config. - Diagnostic codes and FAQ: troubleshooting.