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

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

init 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 the funnel family. 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. --fix inserts the suggested testIDs 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-run first; --sarif lands them as PR annotations on those lines; and --min-score is 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. --fix repairs what can be repaired; --bundle writes 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 run executes a program against the booted app. agent kit generates the harness; agent rules emits 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 --timeout budget 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 --json or --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_COLOR and CI. 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.
Terminal
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 --json

Config and profiles

.squiggle/config.jsonc
{  // 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.

Terminal
squiggle agent schema flow      # print the flow schema offlinesquiggle agent schema intent    # the intent-program schemasquiggle --schema-json          # the whole command tree, as data

Licensing and housekeeping

Terminal
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 fish

Activation 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. --fix applies the safe ones; --bundle writes 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. --history prints 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 .ips reports from DiagnosticReports, and symbolicate stored JS and native stacks.
export · gc
Chrome-trace export for chrome://tracing or Perfetto, and the retention sweep. reproject re-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.md fragment 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.