Weir docsv4
View as Markdown

Quickstart for agents

Permalink to Quickstart for agents

This 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 needs weir-toolkit >= 0.4.4 (the current published release). Run weir --version to check the installed version; do not copy a changing "latest" number from prose. The 0.4.0 release added weir experiment-ship-winner and the weir components-sync --check preflight; 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 that npx -y weir-toolkit init works without the -p flag. If validation demands specVersion: 3 or rejects specVersion: 4 or a custom screen type, your toolkit is pre-v4. Upgrade it with npm install -g weir-toolkit@latest.

1. Onboard the app

Permalink to 1. Onboard the app

Run 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:

FieldRule
versionmust be exactly 1 (the literal, not any other number)
appIdnon-empty string
appVersionoptional semantic marketing version in exact x.y.z form; generated configs include it
platformone of exactly "ios""android""reactNative"
runtimeAccessoptional "public" or "design-partner"; Android/RN doctor checks require the latter and still warn that package acquisition is unproven
flowsarray, must be non-empty — at least one flow is required
flows[].id, .spec, .placement, .baselineBundle, .featureFlag, .nativeFallbackall non-empty strings, all required
flows[].integrationFilenon-empty string, but optional
delivery.manifestBaseURLoptional, but if present must be a valid URL (z.string().url()) — never include a signing private key here
delivery.updateConfigone 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, .ingestConfiguredAtRuntimebooleans, 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 spec

A 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 it
weir dev --specPath weir/flows/onboarding.json --serve

weir_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, headlessly
One-time prerequisite: weir dev (step 3) needs no browser, but weir walk, weir conform, and weir release drive 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/walk

weir_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) baseline
weir embed --appRoot . --flowId onboarding
weir conform --bundleDir .eval-out/mcp/embed-build/onboarding

This 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 it

Validate 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 onboarding

weir_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 landed
weir 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 call

There 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.

Generated from this repo's source at build time — packages/mcp/src/tools/index.ts and packages/spec/src/events.ts are the ground truth for the tool and event tables above. llms-full.txt