The CLI
One binary, twenty-eight command families, and a contract designed so that both a human and an agent can use it without either one guessing: a frozen exit taxonomy, a machine channel that owns stdout, and a schema you can print offline.
The first four commands
squiggle init # wire the SDK into an existing appsquiggle up # relaunch WITH the agent injected — and prove itsquiggle doctor # is the whole plane actually green?squiggle flow login # drive itinit detects Expo or bare RN, your package manager and your entry file, installs the SDK, plants the import, writes EXPO_PUBLIC_SQUIGGLE_WS_URL so the app dials this machine, scaffolds a first flow at .squiggle/flows/smoke.yaml, and names the adapters your package.json implies. It is idempotent — a second run is a no-op — and it makes conservative edits with a printed-instruction fallback for anything it does not recognise.
Driving the app
- flow · flows · watch · bench
- Run one flow, shard a directory across several simulators, re-run on every file save, or benchmark against the last comparable run. See Writing flows and Speed & delivery.
- record · replay · diff · reproject
- Capture a session, replay it (optionally asserting a flow against the recorded timeline), compare two recordings behaviourally, or re-fold recordings into the store. See Record & replay.
- crawl
- Autonomous exploration — prints a coverage and crash report plus a discovered-flow seed, and exits non-zero if it observed a crash.
- consumer
- The standalone interactive graph watcher, which also asserts that the consumer’s materialised graph equals the app’s.
Reading the data
- perf
- Thirteen subcommands:
sql,top,saved,report,gc,snapshot,diff,export,profile,heap,heapdiff,crashes,symbolicate. See Performance. - product
- Ten:
overview,screens,usage,affinity,releases,users,sessions,retention,friction, and thefunnelfamily. See Product analytics. - history
- Recent runs from any surface with their outcomes and durations, and
history rerun <id>to replay one from the argv recorded with it.
Making the app drivable
- legibility
- Scores how agent-drivable the app is and names the exact source lines to fix: interactive controls with no stable selector, screens addressable only by generated text, duplicated handles, missing roles, hit targets under the 44 pt minimum.
--fixinserts the suggestedtestIDs as a parser-driven byte-offset splice — not a regex — applied back-to-front per file so one insert cannot shift the next one’s offset.--dry-runfirst;--sariflands them as PR annotations on those lines; and--min-scoreis a floor a team raises over time rather than a demand for perfection, because a “must be 100” gate gets disabled in week one. - doctor
- Connectivity, handshake, graph health, route tracking — and injection, named capability by capability, because in-process delivery, direct scroll and settle-gated waits degrade silently rather than failing. It also compares the app’s SDK version against the CLI: a skew is a warning, a protocol mismatch is a failure.
--fixrepairs what can be repaired;--bundlewrites a redacted support bundle where every string that leaves is a version, a boolean, an enum, or a path rewritten relative to your project root.
Agents
- agent
- Fourteen subcommands, mostly the offline half — schema, briefings, deny-rail config, KPIs, corpus, gate-only
validate— so code review and CI need no device.agent runexecutes a program against the booted app.agent kitgenerates the harness;agent rulesemits an AGENTS.md fragment generated from the command catalogue, so it cannot describe a CLI that no longer exists. - mcp
- The stdio MCP server. See Agents & MCP.
- gate relaunch · gate mcp
- Device-level acceptance gates for the failure classes a unit suite structurally cannot see — because the bug is a process being replaced, or a server launched over real stdio.
The contract
Exit codes are frozen and published, which is what lets an agent or a CI script branch on an integer rather than parse prose:
- 0
- Success. Warnings allowed.
- 1
- The run under test failed — a flow, a suite, a gate, a diff.
- 2
- Usage error, or an expected failure with a human message.
- 3
- Licence required or expired.
- 4
- Timeout — the
--timeoutbudget elapsed. - 5
- Device unavailable, or held by another run.
squiggle explain E_NOT_INJECTED — or squiggle explain 5 — turns any of them into an explanation plus a runnable fix, which is what makes an error in a CI log self-serve.
Output rules
- A machine channel owns stdout
- With
--jsonor--events, stdout carries the payload alone and every human line moves to stderr. That is what makes piping safe. - Status is never colour alone
- Every verdict carries a glyph as well as a hue, with an ASCII fallback chosen by one degradation decision behind
--no-color,--no-unicode,NO_COLORandCI. One rule covers colourblind readers, terminals that mangle Unicode, and log files where colour is stripped. - Truncation announces itself
- Every capped list says what it elided and how to ask for the rest. A silently elided tail reads as “that is all there is”.
- Empty states name the next command
- Rather than printing
0 rows.
squiggle perf sql "select * from spans limit 5" --json | jq '.rows[]'squiggle flow checkout --json | jq '.steps[] | select(.status=="fail")'squiggle product funnel run checkout --jsonConfig and profiles
{ // the app under test, when this repo drives exactly one "bundleId": "com.acme.app", "flowsDir": ".squiggle/flows", "shards": 4, // named environments — --profile ci merges profiles.ci over everything above "profiles": { "ci": { "relay": false, "shards": 4 }, "local": { "relay": true, "udid": "…" } }}The config schema is generated from the config type, so a missing key is a compile error rather than a stale schema nobody notices. Same for the flow schema, which is generated from the parser’s own vocabulary — put a $schema header on your YAML and your editor autocompletes it, and an agent validates a flow before a run instead of failing after one.
squiggle agent schema flow # print the flow schema offlinesquiggle agent schema intent # the intent-program schemasquiggle --schema-json # the whole command tree, as dataLicensing and housekeeping
squiggle activate --trial # start a trialsquiggle activate <key> # activate a purchased seatsquiggle license # which of the four states you are in, and whysquiggle update --check # channels, and --to <version> to roll backsquiggle uninstall --dry-run # every path we wrote, with sizes, before deletingsquiggle telemetry status # off unless you turn it onsquiggle completions zsh --install # tab-completion for zsh, bash or fishActivation writes a signed grant to ~/.squiggle/license.json that the CLI, the MCP server and the desktop app all read — one activation, three surfaces. The grant is honoured offline until it expires, so a licence check never adds latency and never fails a run mid-flight. license and activate are never gated: they have to work when nothing else does.
Telemetry is off unless you turn it on, and squiggle telemetry prints the exact event that would be sent, built by the same code the dispatcher uses. A policy you can print is a fact where a paragraph is a claim.
Every command
Twenty-eight top-level commands, sixty-three leaves. The table below is the whole surface — but it is a copy, and the binary is the original: squiggle --schema-json prints this tree with every flag, type and default, offline and in milliseconds. If the two ever disagree, the binary is right.
Bring-up and health
up- Relaunch the app with the agent dylib injected, and prove it by round-tripping the dylib's Mach-O UUID. Run this first.
doctor- Connectivity and graph-health smoke test, with a named remedy per failure.
--fixapplies the safe ones;--bundlewrites a support archive. init- Wire Squiggle into an existing app — dependencies, the Babel plugin, the entry import, the environment, and a first flow.
consumer- The headless graph consumer in watch mode. Materialises the same graph the app holds and asserts parity; records perf until interrupted.
gate relaunch·gate mcp- The two device-level acceptance gates: that the SRP, AX and push planes all survive the app process being replaced, and that the MCP surface a client actually gets is the one we think we ship.
Driving
flow·flows- Run one semantic flow, or a whole suite sharded across every booted simulator. Both rewrite the file in place when self-healing repairs a selector, so the repair arrives as a reviewable diff.
watch- Re-run a flow on every file change, against the warm session — no reconnect, no relaunch, no cold start between iterations.
bench- Run a flow and compare its speed against the last benched run, with per-phase deltas.
--historyprints the recent trend. crawl- Autonomous, seeded, deny-filtered and bounded exploration. Returns coverage, crashes, and a flow seed for what it discovered.
record·replay·diff- Capture a live session to
.sqrec; replay it with no device attached; and diff two recordings behaviourally — render counts, route timeline, network, spans.
perf — thirteen leaves over one SQLite file
sql·saved·top·report- Read-only SQL over
perf.db; named queries shared with the desktop; the live current-readings strip; and a human summary of a session. snapshot·diff- Freeze a session's shape as a labelled baseline, then compare against it — with a comparability check, so two runs that are not alike say so instead of reporting a meaningless delta.
profile·heap·heapdiff- Hermes CPU profiles and heap snapshots over the Metro inspector, and a growth-by-constructor diff of two snapshots with the top retainers of the biggest grower.
crashes·symbolicate- Ingest native
.ipsreports from DiagnosticReports, and symbolicate stored JS and native stacks. export·gc- Chrome-trace export for
chrome://tracingor Perfetto, and the retention sweep.reprojectre-folds recordings and checks the store still agrees with the canonical log.
product — ten leaves
overview, screens, usage, affinity, releases, users, sessions, retention, friction and funnel — the same readers the desktop Product screen and the squiggle_product_* tools use, over the same event stream. Funnel definitions live in the project's config sidecar, so one definition serves all three surfaces.
agent — fourteen leaves
run·validate·branch- Run an intent program against the booted app, check one without running it, and explore alternative continuations from a point in the journal.
journal·watch·stats- What the agent did and why, live or after the fact, plus KPIs over the journal — turns, heals, escalations, cost.
briefing·amend·schema·kit·rules- The methodology as artefacts: the mode briefing with this app's learned amendments, the amendments alone so they can be diffed in a PR, the published JSON schemas, the full Claude Code harness, and an
AGENTS.mdfragment for the repo. config·eval·library- The deny rail and run budgets; the eval corpus replayed case by case; and the saved flow library — the app's learned verb vocabulary.
The rest
legibility scores how agent-drivable the app is and names the source lines to fix. mcp serves the tool surface over stdio. history lists recent runs and how to re-run one. explain decodes an error or exit code. license, activate, update, uninstall, licenses, telemetry and completions are the productization set above.