First Five Minutes
Luotsi is easiest to reason about when you treat every workflow as a loop:
command -> structured output -> artifact root -> replay command -> next actionThe first minute is about identifying which output contract you are looking at. The next few minutes are about following the evidence to the next command.
From the CLI, run the same primer with:
luotsi help outputMinute 1: Identify The Output
Section titled “Minute 1: Identify The Output”Luotsi has three main output shapes.
| Shape | Where You See It | How To Read It |
|---|---|---|
| One JSON envelope | Most commands, including devices, doctor, screen-state, and normal run output | Check ok, then inspect data, artifacts, provenance, and error. |
| JSONL session stream | inspect, and view --json / view -o jsonl | Read each line as an event. Match command responses by id. |
| Replay artifact root | Scenario runs, inspect sessions, view sessions, and captured failure bundles | Packet it later with replay packet, validate it with replay packet --check, then move into replay open, replay summarize, replay timeline, or replay graph. |
If you are not sure what to do next, look for an artifact path first. Luotsi is designed so live device work can turn into replayable evidence.
One-Shot Commands
Section titled “One-Shot Commands”Most commands return one final JSON object:
{ "schema": "luotsi-command.v1", "ok": true, "command": "screen-state", "started_at": "2026-06-08T10:15:30Z", "ended_at": "2026-06-08T10:15:31Z", "data": { "focused_package": "com.example.app", "element_count": 12 }, "artifacts": { "artifact_root": "artifacts/screen-state/20260608-101530", "poll_artifacts": "final" }, "provenance": { "device": "emulator-5554" }, "error": null}For humans, read:
ok: did the command succeed?data: what did Luotsi learn or do?artifacts.artifact_root: where is the durable evidence?error: what failed, and which category does it belong to?
If you run with --human, the same loop is compressed into terminal text:
OK screen-state completed in 1000 ms. artifacts: artifacts/screen-state/20260608-101530 guide: artifact root is durable evidence; replay packet writes run-summary.json and run-summary.md next: luotsi replay packet --artifacts artifacts/screen-state/20260608-101530For scripts and CI, treat ok plus the process exit code as the first gate, then consume the command-specific data contract.
To find the next command in structured output, check these fields in order:
data.recommended_next_action_commandwhen a check result exposes the direct continuation command; command-envelopedatafields use snake_case.data.recommended_next_action.commandwhen present.data.primary_failure.source_commandordata.primaryFailure.sourceCommandwhen a packet/check result has focused failure evidence but no recommended action.data.triage_checklist[].commandordata.triageChecklist[].commandwhen a packet/check exposes a structured first-minute checklist.data.recommended_next_steps[],data.next_actions[], ordata.suggested_commands[]for ordered handoffs.artifacts.artifact_rootwhen no richer command field exists, then runluotsi replay packet --artifacts <artifact-root>first so the loop hasrun-summary.jsonandrun-summary.md.data.commands[],data.artifact_commands[], ordata.recommended_commands[]only when there is no artifact root to packetize. Useluotsi replay open --artifacts <artifact-root> --dry-runwhen a human needs the replay front door response, and useluotsi artifacts open <artifact-root>only when you specifically need the generic artifact browser.
From source, the agent examples include tiny parsers that implement this same order:
luotsi run --file scenarios/smoke.json --device <serial> --artifacts ./artifacts/smoke-run \ | python3 examples/agents/extract-next-command.py
luotsi run --file scenarios/smoke.json --device <serial> --artifacts ./artifacts/smoke-run \ | node examples/agents/extract-next-command.mjsAgent Sessions
Section titled “Agent Sessions”inspect is not one final object. It is a line-oriented control loop:
agent sends JSON command -> Luotsi emits JSONL event -> agent decides next commandInput commands are one JSON object per line:
{"id":"1","command":"wait_visible","text":"Sign in","text_match":"exact","timeout_sec":15}{"id":"2","command":"tap_text","text":"Sign in","text_match":"exact","timeout_sec":5}{"id":"3","command":"screenshot","label":"after-sign-in"}{"id":"4","command":"exit"}Output events are also one JSON object per line:
{"type":"session_started","session_id":"...","started_at":"..."}{"type":"screen_snapshot","session_id":"...","state":{"element_count":12,"elements":[...]}}{"type":"command_result","id":"1","command":"wait_visible","ok":true}{"type":"screen_delta","id":"2","delta":{"added_count":1,"removed_count":0},"state":{...}}{"type":"session_ended","id":"4","reason":"client_exit"}For agents, the practical loop is:
- Wait for
screen_snapshot. - Send one command with a stable
id. - Wait for the matching
command_result. - If the command changes state, wait for the matching
screen_delta. - Capture artifacts before exiting or when a command fails.
Failed Runs
Section titled “Failed Runs”When a scenario fails, do not start by rerunning blindly. Start from the artifact root:
luotsi run --file scenarios/smoke.json --device <serial> --artifacts ./artifacts/smoke-runluotsi replay packet --last --artifacts ./artifacts/smoke-runluotsi replay packet --last --artifacts ./artifacts/smoke-run --checkluotsi replay open --last --artifacts ./artifacts/smoke-run --dry-runluotsi replay summarize --artifacts ./artifacts/smoke-run/<run-id>luotsi replay graph --artifacts ./artifacts/smoke-run/<run-id> --failed --write-markdownUse this sequence to answer:
- What failed?
- What changed or was observed around the failure?
- Which screenshot, hierarchy, logcat, telemetry, or timeline event proves it?
- Which command should run next?
replay packet writes the production handoff files first. Use replay open --dry-run when a human also wants the browser-free replay front door with primary failure, recommended next action, and follow-up commands without launching the local artifact browser.
Pick The Reader
Section titled “Pick The Reader”| Reader | Preferred Surface | First Question |
|---|---|---|
| Human debugging live | view, screen-state, human summaries, artifact browser | What do I see, and where are the artifacts? |
| AI agent exploring | inspect JSONL and artifact roots | What event arrived, and what command should I send next? |
| CI job | JSON envelopes, JUnit, policy fields, replay summaries | Did the run pass, and what evidence should be uploaded? |
| Reviewer after failure | replay packet, replay open, graphs, capsules, timelines | What proof explains the failure without reconnecting the device? |
Command Map
Section titled “Command Map”Start with these commands when you are oriented by output shape:
# Find a device and verify host/device readiness.luotsi devicesluotsi doctor --device <serial>
# Inspect current state once.luotsi screen-state --device <serial>
# Open an agent-readable live loop.luotsi inspect --device <serial> --artifacts artifacts/inspect
# Run a repeatable scenario.luotsi run --file scenarios/smoke.json --device <serial> --artifacts ./artifacts/smoke-run
# Reopen saved evidence.luotsi replay packet --last --artifacts ./artifacts/smoke-runluotsi replay packet --last --artifacts ./artifacts/smoke-run --checkluotsi replay open --last --artifacts ./artifacts/smoke-run --dry-runluotsi replay graph --artifacts ./artifacts/smoke-run/<run-id> --failed