Skip to content

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 action

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

Terminal window
luotsi help 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.

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-101530

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

  1. data.recommended_next_action_command when a check result exposes the direct continuation command; command-envelope data fields use snake_case.
  2. data.recommended_next_action.command when present.
  3. data.primary_failure.source_command or data.primaryFailure.sourceCommand when a packet/check result has focused failure evidence but no recommended action.
  4. data.triage_checklist[].command or data.triageChecklist[].command when a packet/check exposes a structured first-minute checklist.
  5. data.recommended_next_steps[], data.next_actions[], or data.suggested_commands[] for ordered handoffs.
  6. artifacts.artifact_root when no richer command field exists, then run luotsi replay packet --artifacts <artifact-root> first so the loop has run-summary.json and run-summary.md.
  7. data.commands[], data.artifact_commands[], or data.recommended_commands[] only when there is no artifact root to packetize. Use luotsi replay open --artifacts <artifact-root> --dry-run when a human needs the replay front door response, and use luotsi 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:

Terminal window
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.mjs

inspect is not one final object. It is a line-oriented control loop:

agent sends JSON command -> Luotsi emits JSONL event -> agent decides next command

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

  1. Wait for screen_snapshot.
  2. Send one command with a stable id.
  3. Wait for the matching command_result.
  4. If the command changes state, wait for the matching screen_delta.
  5. Capture artifacts before exiting or when a command fails.

When a scenario fails, do not start by rerunning blindly. Start from the artifact root:

Terminal window
luotsi run --file scenarios/smoke.json --device <serial> --artifacts ./artifacts/smoke-run
luotsi replay packet --last --artifacts ./artifacts/smoke-run
luotsi replay packet --last --artifacts ./artifacts/smoke-run --check
luotsi replay open --last --artifacts ./artifacts/smoke-run --dry-run
luotsi replay summarize --artifacts ./artifacts/smoke-run/<run-id>
luotsi replay graph --artifacts ./artifacts/smoke-run/<run-id> --failed --write-markdown

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

| 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? |

Start with these commands when you are oriented by output shape:

Terminal window
# Find a device and verify host/device readiness.
luotsi devices
luotsi 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-run
luotsi replay packet --last --artifacts ./artifacts/smoke-run --check
luotsi replay open --last --artifacts ./artifacts/smoke-run --dry-run
luotsi replay graph --artifacts ./artifacts/smoke-run/<run-id> --failed