Quickstart for agents
Permalink to Quickstart for agentsThis is the loop: onboard the app once, author a flow, verify it, ship it. Every step below is a real MCP tool or CLI verb — full field-level detail is in Reference.
Note: These docs describe the v4 toolkit, which needsweir-toolkit >= 0.4.4(the current published release). Runweir --versionto check the installed version; do not copy a changing "latest" number from prose. The 0.4.0 release addedweir experiment-ship-winnerand theweir components-sync --checkpreflight; a toolkit older than 0.4.0 cannot run them. 0.4.5 is pending publish and will fix the package's bin alias so thatnpx -y weir-toolkit initworks without the-pflag. If validation demandsspecVersion: 3or rejectsspecVersion: 4or acustomscreen type, your toolkit is pre-v4. Upgrade it withnpm install -g weir-toolkit@latest.
1. Onboard the app
Permalink to 1. Onboard the appRun weir init --appId <your-app-id> --platform ios. This offline command writes a valid weir/app.json, a starter flow, and its built baseline bundle. See weir init for its arguments and sample output.
Every host app owns a versioned weir/app.json. It is the source of truth for its app id, flows, baseline bundle locations, feature flag, native fallback, and telemetry intent. It deliberately holds no secrets; signing keys and ingest tokens stay in deployment config. platform is "ios" | "android" | "reactNative" and is required. Only iOS has a public runtime acquisition path. Android Compose and React Native/Expo are private design-partner runtimes: init refuses them by default. After Weir has granted runtime access, an integrator may explicitly pass --acknowledgePrivateRuntime; that acknowledgement scaffolds the contract but does not install the runtime. Do not treat either path as self-service.
weir init generates an app config with this shape. The example shows why the generated config uses these fields:
{
"version": 1,
"appId": "example-app",
"appVersion": "1.0.0",
"platform": "ios",
"runtimeAccess": "public",
"flows": [{
"id": "onboarding",
"spec": "weir/flows/onboarding.json",
"placement": "first_launch",
"baselineBundle": "App/Resources/Weir/Onboarding",
"featureFlag": "weir_onboarding_enabled",
"nativeFallback": "native_onboarding",
"integrationFile": "App/Weir/WeirIntegration.swift"
}],
"delivery": { "updateConfig": "remote-config" },
"telemetry": { "appAnalyticsForwarding": true, "ingestConfiguredAtRuntime": true }
}Validation rules (weirAppConfigSchema, the toolkit's app-config validator) — the shape a schema enforces beyond what the one example JSON shows, so adapting it (not just copying it) does not trip an opaque Zod error:
| Field | Rule | |||
|---|---|---|---|---|
version | must be exactly 1 (the literal, not any other number) | |||
appId | non-empty string | |||
appVersion | optional semantic marketing version in exact x.y.z form; generated configs include it | |||
platform | one of exactly "ios" | "android" | "reactNative" | |
runtimeAccess | optional "public" or "design-partner"; Android/RN doctor checks require the latter and still warn that package acquisition is unproven | |||
flows | array, must be non-empty — at least one flow is required | |||
flows[].id, .spec, .placement, .baselineBundle, .featureFlag, .nativeFallback | all non-empty strings, all required | |||
flows[].integrationFile | non-empty string, but optional | |||
delivery.manifestBaseURL | optional, but if present must be a valid URL (z.string().url()) — never include a signing private key here | |||
delivery.updateConfig | one of exactly "build-settings" | "remote-config" | "debug-launch-arguments" | "none" (four values only — no underscore variant like "remote_config"); defaults to "build-settings" if delivery is omitted entirely |
telemetry.appAnalyticsForwarding, .ingestConfiguredAtRuntime | booleans, both default true if telemetry is omitted |
A validation failure reports as invalid <path>: <field>: <message> for every failing field at once (not just the first) — the field there is the dotted path from the table above.
Use weir init for a new integration. Hand-author weir/app.json only when your existing app structure does not fit its scaffold. If you do, adapt the example for your app: its appId, flow spec path, baselineBundle location, featureFlag, and nativeFallback. Then validate it any time with:
weir app-doctor --appRoot .weir_app_doctor returns readinessKind: "source-contract-only" and sourceContractReady. It checks each flow spec, its embedded baseline bundle, the declared Swift integration file, the delivery-mode declaration, and telemetry/fallback config — read-only, never writes or reads secrets. Its legacy ready alias is not a runtime or ship-ready claim; only a built artifact checked by weir ship-ready plus a device journey can establish that.
2. Author a flow spec
Permalink to 2. Author a flow specA flow spec is JSON: a theme, a list of typed variables, and a list of screens — 13 stock types plus custom (see Reference → Node types), each with an id and an optional next branch. Screens read/write variables; later screens interpolate them with {{variableId}}. Put it at the path your app's weir/app.json declares (weir/flows/<flowId>.json). specVersion must be exactly 4.
If any screen is type: "custom", register that component once with the app before authoring against it — see weir components sync. A flow built only from the 13 stock types needs no sync step at all.
3. Preview it
Permalink to 3. Preview itweir dev --specPath weir/flows/onboarding.json --serveweir_dev serves the spec in-browser with mocked native behavior — fake permission/purchase dialogs, a mock localized product catalog, safe-area/notch overlay, keyboard-inset simulation — for every stock screen type. A custom screen has no browser preview (there is no way to preview a native SwiftUI view in a browser); weir dev shows a placeholder for it instead. Pass --persona "notifications=deny,purchase=cancel" to force a specific outcome while you look at it.
Warning: Expo Go cannot load the required third-party native module. Use a development or release build.
4. Walk every branch, headlessly
Permalink to 4. Walk every branch, headlesslyOne-time prerequisite:weir dev(step 3) needs no browser, butweir walk,weir conform, andweir releasedrive a real headless Chromium. Install it once before the first walk: ``bash npx playwright install chromium``
weir walk --specPath weir/flows/onboarding.json --outDir .eval-out/walkweir_walk drives the same mocked preview for one or more persona configs, screenshotting every screen each persona's path visits, and writes a walk-report.json (path, native-call events, final variables) per persona. This is how you verify branches and personalization actually resolve — read the screenshots, don't just check the tool exited 0.
5. Build the embedded (offline) baseline
Permalink to 5. Build the embedded (offline) baselineweir embed --appRoot . --flowId onboarding
weir conform --bundleDir .eval-out/mcp/embed-build/onboardingThis is a separate artifact from the remote publish path in step 6, not a prerequisite for it — weir embed builds the flow into the app's own resources as an offline fallback (see Concepts → Embedded baseline config), and weir_release builds and gates its own copy internally when you ship remotely. Build this whenever you want that fallback current, not on every iteration.
Pass --flowId (the flow id from weir/app.json, matching the example above), not --appResourcesDir/--bundleName: weir_embed then reads that flow's baselineBundle (and spec) straight out of weir/app.json and copies the built bundle exactly there, so there is nothing to keep in sync by hand. It also prints the exact scratch build directory to pass to weir_conform. weir_conform runs the full contract eval against that built bundle directory: a persona walk reaches complete(), the auto-emitted event stream matches the manifest byte-for-byte, every declared variable gets set, purchase/permission calls only go through the native call layer (never a literal currency string), no network on the paint path, and perf budgets hold. weir_release runs this exact gate for you before it publish (next step) — running it here separately is for proving the offline fallback itself works, not a required step before shipping.
6. Ship it
Permalink to 6. Ship itValidate the whole gate fully offline first, before any credential setup:
weir release --appRoot . --flowId onboarding --dryRun--dryRun resolves the flow from weir/app.json, runs the full conform gate, and stops there — every step except the call to the delivery API. It needs no WEIR_API_URL/WEIR_API_TOKEN, so run it before anything else in this step: it surfaces conform problems (a broken flow spec, a failed persona walk, a perf-budget breach) separately from credential problems, so you fix one kind of blocker at a time. Only when the dry run is green do you need a reachable server and a token.
For a real release, set the delivery origin and app token before the non-dry-run command:
export WEIR_API_URL="https://your-weir-delivery-origin" export WEIR_API_TOKEN="<token for example-app>"
Keep both outside weir/app.json and out of source control. WEIR_API_URL defaults to http://localhost:8787 for a local API. WEIR_API_TOKEN may be omitted only when that local server has no token authentication configured; a production service with WEIR_API_TOKENS requires the token matching this app's appId. If an operator has not issued one yet, stop after the dry run and request it — the current server configuration is the token-issuance authority.
weir release --appRoot . --flowId onboardingweir_release is the one command that does the whole gate correctly: it resolves the flow from weir/app.json, runs the full conform gate, and only publishes the signed config if conform passes — then fetches the returned manifest back and verifies its version and files. That is the same gate the dry run above exercised, minus the publish step. What actually gets published is config.json (the flow spec itself, RFC-010 §2) plus any customAssets[] files it references — never an HTML bundle.
The already-installed app picks the new config up on its next launch/foreground update check — no Xcode rebuild, no App Store review. See Concepts → Delivery model for what happens between "publish" and "the device renders it."
7. Check it landed
Permalink to 7. Check it landedweir funnel --flowId onboarding
weir health --flowId onboarding
weir app-status --appRoot .weir_funnel is the step-through funnel with drop-off per screen, completion rate, and time-to-paywall. weir_health is reliability: crash-free flow-session rate, render time percentiles, native-call error rate, fallback count. weir_app_status combines the currently published manifest with both reads for every flow declared in weir/app.json — the fastest single command to answer "is the flow I just shipped actually live and healthy."
What's deliberately not a tool call
Permalink to What's deliberately not a tool callThere is no automated compliance/App Review lint in the current toolkit (an earlier weir_compliance_lint was removed) — use manual judgment on paywall copy and permission priming before shipping. There is also no tool that clicks through a flow interactively for you beyond weir_walk's scripted personas; anything past that is a manual trace of every branch and interpolated variable downstream of a branch before you call a flow done.