# Run everything locally

The whole loop — author, serve, render, collect events, experiment — runs on one machine with **no
Weir account, no hosted box, and no tokens**. This is the front door, not a footnote. The authoring
tools (`weir_dev`, `weir_walk`, `weir_conform`, `weir_embed`) are already pure local operations —
the npm package alone gives you all of these, right now, with no further setup.

## Local API + dashboard, no repo checkout

With only the shipped npm package, run:

```sh
weir dashboard
```

This starts a real local `@x/api` in dev mode plus the prebuilt dashboard SPA, signs the dashboard
in automatically, and prints both the local API URL and dashboard URL. It needs no repo checkout,
pnpm, account, signing key, or token. This is the npm-only integrator's front door to a real local
delivery origin: use the printed API URL for `WEIR_API_URL` when publishing locally.

It prefers API port `8787`; if that port is occupied, it chooses a free port and tells you which
one it used. `weir dashboard` requires Node.js 22+ because its local API uses the built-in
`node:sqlite` module, unflagged only from Node 22. Every other Weir command still works on Node 18+.

## Full vendor repo path: start the server in dev mode

The full `services/api` vendor repo remains for engineers with private-monorepo access who need
production deployment configuration, real signing keys, or to develop the API itself. It is not
published as a standalone npm package or image; npm-only integrators should use `weir dashboard`.

```
cd services/api && WEIR_API_DEV_MODE=true pnpm dev
```

That one command gives a fully working local delivery origin on `http://localhost:8787`. In dev
mode it makes two guarantees:

- **Ephemeral signing key.** The server generates a fresh Ed25519 keypair per process, so you never
  set `WEIR_API_SIGNING_KEY_B64` for local work. (A real deployment must set it or refuse to boot.)
- **Auth is optional.** With `WEIR_API_DEV_MODE=true` and no `WEIR_API_TOKENS` configured, every
  caller is treated as the default app — no bearer token needed. (Outside dev mode, zero tokens is
  a boot-time refusal.)

Dev mode is fail-closed: it refuses to start if it detects production signing-key markers, so you
cannot accidentally run it against real state.

## Point the MCP tools at localhost — they already do

The remote-touching tools (`weir_release`, `weir_funnel`, `weir_health`,
`weir_events`, `weir_app_status`, `weir_rollback`, `weir_experiment_*`) default `WEIR_API_URL` to
`http://localhost:8787`, and omit the auth header when `WEIR_API_TOKEN` is unset. So with the dev
server running, you set **no environment variables at all**:

```
weir release --appRoot . --flowId onboarding
weir app-status --appRoot .
```

The publish → manifest → OTA loop runs end to end against localhost: `weir_release` builds,
conforms, and publishes `config.json` (plus any `custom`-screen assets) to your local server; the
server validates and signs it, then updates `/manifest/:flowId`; an app pointed at that origin
promotes the config on its next update check;
and `weir_funnel`/`weir_health`/`weir_events` read the ingested result back. Zero network egress.

If the tools cannot reach the server they print `could not reach the Weir API at
http://localhost:8787/...` — start the dev server first.

## Point the dashboard at your local API

**The dashboard already defaults local.** Its API base falls back to `http://localhost:8787` unless
overridden, so a fresh checkout's `vite dev` points at your local dev server out of the box — a
production build sets `VITE_API_BASE` at build time to point at the live API instead. You only need
to override anything if you're running a local dev server on a different port, or want a dev build
to talk to the live API.

Two ways, both skipping Google/Firebase sign-in entirely:

1. **In the running app.** On the sign-in screen, open **"Advanced: sign in with a bearer token"**.
   Paste any per-app bearer token (any value works against a no-token dev server), and set the
   **"API base URL override (local dev only)"** field to `http://localhost:8787`. The base is
   stored in `localStorage` under `weir_dashboard_api_base`.
2. **At build time.** Set `VITE_API_BASE=http://localhost:8787` before `vite dev`/`vite build`.

Confirm the dashboard's reads (Overview, Funnel, Health, Events) show the flow you published
locally, not empty or production data.

## Render the local bundle on a device — plaintext caveats

Both SDKs take a caller-supplied server URL through their public init parameters, so you point them
at `http://localhost:8787` (or `http://10.0.2.2:8787` from an Android emulator) with no source
changes. But an `http://` (not `https://`) origin trips each platform's cleartext-traffic block:

- **iOS — App Transport Security.** The demo app's `Info.plist` has no
  `NSAppTransportSecurity` key, so default ATS blocks plaintext `http://localhost` and the fetch
  fails with no clear error. Add an `NSExceptionDomains` entry for `localhost` and `127.0.0.1`
  (with `NSExceptionAllowsInsecureHTTPLoads`) to the demo `Info.plist` before pointing it at a
  local server.
- **Android — already handled.** The demo's `res/xml/network_security_config.xml` already permits
  cleartext for `10.0.2.2`, `localhost`, and `127.0.0.1`, wired via the manifest. No change needed.

## The embedded-baseline path needs no server at all

`weir_embed` builds the flow into the app's own resources as a baseline bundle, so the app renders
a working onboarding flow with zero network and zero prior publish (see
[Concepts → Embedded baseline config](/docs/concepts/#embedded-baseline-config)). That is the
bottom rung of the resolve order and the strongest form of "runs locally" — it needs neither the
dev server nor a device network. Use it to prove the flow renders before you wire up delivery.

## What still needs a real toolchain

Real-device verification of the native SDKs — permission/purchase dialogs, app-lifecycle behavior,
actual rendering on a simulator or emulator — is Maestro (`sdk-ios/maestro/`,
`sdk-android/maestro/`), which needs a prior `xcodebuild` of `WeirDemo.app` (iOS) or a built and
installed `:demo` APK on a booted emulator (Android, needs JDK 17). Those suites are not runnable
without the mobile toolchain, and each one's own README states its current run status honestly —
check it before assuming a flow currently passes. The authoring, serving, ingest, and experiment
layers on this page do not need any of that toolchain.
