Sessions and targets

Own one target, the emulator or Simulator your agent drives, and keep a journal of every verb it runs. A verb is one Autonom command, such as ui tap.

Try it autonom session start

Needs Autonom installed · a booted emulator or Simulator

How it works

Start with autonom devices. It lists Android emulators and iOS Simulators together, each with a running flag. Then session start binds one of them. While that session is current, every verb that names no target goes to it.

Four steps in a column, autonom devices, session start, ui, logs and network, and session stop, with dashed arrows into a session folder that holds the journal, trees, shots and logs. Four steps in a column, autonom devices, session start, ui, logs and network, and session stop, with dashed arrows into a session folder that holds the journal, trees, shots and logs.
A session runs from choosing a target to stopping it, and everything in between lands in one folder.

Sessions are machine-global. A second shell in any directory sees the same run, and a second session start is refused while one is live.

The journal records every verb, whether it worked, and your notes, with secrets masked. A reviewer reads what happened, not a summary of it. The screenshots and trees it names are the raw material of the evidence a run brings back, and each verb is one of the commands that read and drive the screen.

Examples

Every output here comes from Autonom’s test device, so you can rerun it without an emulator. Reproduce these outputs, at the end of this section, has the exact commands.

Pick a target when two are ready

Goal: bind the device you mean, not a guess.

  1. List the targets.

    Android emulators and iOS Simulators come back in one list.

    autonom devices
  2. Start without naming one.

    With two ready, Autonom refuses and names the candidates.

    autonom session start

You should see two running emulators, a Simulator that is shut down, and a refusal.

autonom devices { "ok": true, "devices": [ {"serial": "emulator-5554", …, "running": true, "platform": "android", …}, {"serial": "emulator-5556", …, "running": true, "platform": "android", …}, {"platform": "ios", …, "state": "Shutdown", "running": false, "name": "iPhone 17 Pro", …} ], … } autonom session start {"ok": false, "error_code": "ambiguous_target", "error": "2 ready targets; pass --target (or --platform)", "hint": "Candidates: android:emulator-5554, android:emulator-5556", "candidates": [{"platform": "android", "target_id": "emulator-5554"}, {"platform": "android", "target_id": "emulator-5556"}]}

What to look at. Both emulators are running, so session start exits 2 with ambiguous_target, an error code your agent can branch on. Pass one of the candidates to --target or --serial, as the next example does.

Show full output
{ "ok": true, "devices": [ { "serial": "emulator-5554", "target_id": "emulator-5554", "state": "device", "running": true, "platform": "android", "name": "sdk_gphone64_arm64", "properties": { "product": "sdk_gphone64_arm64" } }, { "serial": "emulator-5556", "target_id": "emulator-5556", "state": "device", "running": true, "platform": "android", "name": "sdk_gphone64_arm64", "properties": { "product": "sdk_gphone64_arm64" } }, { "platform": "ios", "target_id": "AAAAAAAA-1111-2222-3333-BBBBBBBBBBBB", "udid": "AAAAAAAA-1111-2222-3333-BBBBBBBBBBBB", "state": "Shutdown", "running": false, "name": "iPhone 17 Pro", "runtime": "iOS 26.0", "properties": { "is_available": true } } ], "warnings": [], "avds": [ "Pixel_9" ], "avd_profiles": [ { "name": "Pixel_9", "device": null, "screen": null, "api": null, "abi": null, "path": null } ] }
session start branches three ways: a named target wins, a single ready device is used, and several ready devices stop with ambiguous_target. session start branches three ways: a named target wins, a single ready device is used, and several ready devices stop with ambiguous_target.
With several targets ready and none named, Autonom stops and lists them instead of guessing.

Own a session and keep a note

Goal: bind one emulator, write down what you learned, and read it back.

  1. Start the session.

    Name the target and the app under test.

    autonom session start --serial emulator-5554 --app-id com.example.app
  2. Write the finding down.

    A note sits in the journal between the verbs around it.

    autonom note add "login works; the 500 retry path is missing"
  3. Read the notes back.

    Filter the journal to notes only.

    autonom journal --kind note

You should see the session’s folder, then your note with its place in the timeline.

autonom session start --serial emulator-5554 --app-id com.example.app { "ok": true, "session": {…, "session_id": "s_226cd97cfa", …, "artifacts_dir": "/tmp/autonom-sessions/sessions/s_226cd97cfa", …}, … } autonom journal --kind note { "ok": true, "count": 1, … "entries": [{"seq": 2, "ts": "2026-09-28T21:45:15Z", "kind": "note", "author": "agent", "text": "login works; the 500 retry path is missing"}], "journal": "/tmp/autonom-sessions/sessions/s_226cd97cfa/journal.ndjson" }

What to look at. artifacts_dir is the folder that holds everything the session records. The note comes back as seq 2, right after session start.

Start over without losing the first run

Goal: stop the live session on purpose, because a second start never replaces it.

  1. Start a session.

    This one is live until you stop it.

    autonom session start --serial emulator-5554 --app-id com.example.app
  2. Start again.

    Autonom refuses and names the live session.

    autonom session start --serial emulator-5554 --app-id com.example.app
  3. Stop the first one.

    Teardown reports each action, and the session’s files stay.

    autonom session stop

You should see the refusal, then a stop that lists its teardown.

autonom session start --serial emulator-5554 --app-id com.example.app {"ok": false, "error_code": "session_already_active", "error": "session s_a758abf9d7 is still active on emulator-5554", "hint": "Stop it first with 'autonom session stop' (it clears the session on emulator-5554 even if that target is gone), then start the new one.", "session_id": "s_a758abf9d7", "target_id": "emulator-5554"} autonom session stop { "ok": true, "session": {"schema_version": 2, "session_id": "s_a758abf9d7", …, "stopped_at": "2026-09-28T21:45:16Z"}, "teardown": [ {"action": "log_stream", "ok": true, "detail": false}, {"action": "recorder", "ok": true, "detail": false}, … ] }

What to look at. The refusal, session_already_active, names the live session and its target. session stop reports every teardown action and never fails because one of them did.

Read a run back and hand it off

Goal: give a reviewer the whole timeline and the files to follow.

  1. Start the session.

    The first entry in the journal.

    autonom session start --serial emulator-5554 --app-id com.example.app
  2. Read the screen.

    The tree is saved with the run.

    autonom ui tree --format outline --interactable
  3. Note the finding.

    Tag it with the task it belongs to.

    autonom note add "login shows the generic error banner on 500; retry works" --task login
  4. Read the timeline.

    Every verb in order, whether it worked, and your notes.

    autonom journal
  5. List what can be followed.

    Paths and hints for a second terminal.

    autonom session outputs

You should see three entries in the order you ran them, and one stream to follow.

autonom journal { "ok": true, "count": 3, … "entries": [ {"seq": 1, …, "kind": "action", "verb": "session start", …, "ok": true, …}, {"seq": 2, …, "kind": "action", "verb": "ui tree", …, "ok": true, …, "result": {…, "saved": "/tmp/autonom-sessions/sessions/s_ec9ae751a5/trees/0001_214517.json", "count": 5}}, {"seq": 3, …, "kind": "note", "author": "agent", "text": "login shows the generic error banner on 500; retry works", "task": "login"} ], … } autonom session outputs {"ok": true, …, "streams": [{"id": "journal", …, "follow_hint": "autonom journal --follow", "shell_hint": "tail -f '/tmp/autonom-sessions/sessions/s_ec9ae751a5/journal.ndjson'"}]}

What to look at. The entries keep the order you ran them in, and the tree read names the file it saved under trees/. Paste shell_hint into a second terminal to follow the run live.

Show full output
{ "ok": true, "count": 3, "total_matched": 3, "truncated": false, "entries": [ { "seq": 1, "ts": "2026-09-28T21:45:16Z", "kind": "action", "verb": "session start", "argv": [ "--adb", "tests/fakes/fake_adb.py", "--simctl", "tests/fakes/fake_simctl.py", "--idb", "tests/fakes/fake_idb.py", "session", "start", "--serial", "emulator-5554", "--app-id", "com.example.app" ], "ok": true, "origin": "agent" }, { "seq": 2, "ts": "2026-09-28T21:45:17Z", "kind": "action", "verb": "ui tree", "argv": [ "--adb", "tests/fakes/fake_adb.py", "--simctl", "tests/fakes/fake_simctl.py", "--idb", "tests/fakes/fake_idb.py", "ui", "tree", "--format", "outline", "--interactable" ], "ok": true, "origin": "agent", "result": { "target_id": "emulator-5554", "platform": "android", "saved": "/tmp/autonom-sessions/sessions/s_ec9ae751a5/trees/0001_214517.json", "count": 5 } }, { "seq": 3, "ts": "2026-09-28T21:45:17Z", "kind": "note", "author": "agent", "text": "login shows the generic error banner on 500; retry works", "task": "login" } ], "journal": "/tmp/autonom-sessions/sessions/s_ec9ae751a5/journal.ndjson" }
Reproduce these outputs

From the root of an Autonom d0f7211 checkout, in bash or zsh. The autonom function runs that checkout against its test doubles, so no device is needed. Ids and times differ on every run.

# autonom below runs this checkout against Autonom's test doubles: two emulators and a shut-down Simulator. autonom() { python3 scripts/autonom.py --adb tests/fakes/fake_adb.py --simctl tests/fakes/fake_simctl.py --idb tests/fakes/fake_idb.py "$@"; } export AUTONOM_HOME=/tmp/autonom-sessions AUTONOM_EMULATOR=tests/fakes/fake_emulator.py AUTONOM_FAKE_STATE=/tmp/autonom-sessions.json export ANDROID_AVD_HOME=/tmp/autonom-sessions-avd rm -rf "$AUTONOM_HOME" && mkdir -p "$ANDROID_AVD_HOME" cat > "$AUTONOM_FAKE_STATE" <<'JSON' {"devices": [["emulator-5554", "device", "product:sdk_gphone64_arm64"], ["emulator-5556", "device", "product:sdk_gphone64_arm64"]], "ui_dump": "tests/fixtures/woolbox/android_sign_in.xml"} JSON # Pick a target when two are ready autonom devices autonom session start # Own a session and keep a note autonom session start --serial emulator-5554 --app-id com.example.app autonom note add "login works; the 500 retry path is missing" autonom journal --kind note autonom session stop # Start over without losing the first run autonom session start --serial emulator-5554 --app-id com.example.app autonom session start --serial emulator-5554 --app-id com.example.app autonom session stop # Read a run back and hand it off autonom session start --serial emulator-5554 --app-id com.example.app autonom ui tree --format outline --interactable autonom note add "login shows the generic error banner on 500; retry works" --task login autonom journal autonom session outputs autonom session stop

Good to know

  • Name the target whenever more than one is ready. Pass --target, --serial or --udid. Ambiguity is an error that lists the candidates, never a silent guess.
  • A live session is never replaced. session start refuses until you run session stop. journal --session-id still reads a finished run.
  • A failed install or launch never leaves a session current. The new session is stopped, and the error names it in its session_rolled_back field. The next command cannot drive a half-built session.
  • The journal keeps secrets out. Typed text, secret-bearing flag values and every KEY=VALUE option value are masked. A journal error never fails your command.
  • A flag that does nothing says so. --log-stream, --arg or --setenv on Android and --activity on iOS come back as a flag_ignored_on_platform warning.
  • Stop never kills what it did not start. An idb companion the session did not start is left alone, and a companion_left_running warning names it.
  • A session that died still gets found. autonom doctor lists orphaned processes and any device left pointing at a dead proxy. autonom cleanup reaps the processes from any directory. The network proxy is one of them.

Reference

Every command also takes --platform, --target, --serial and --udid, before or after the verb.

CommandWhat it does
autonom devices [list]Lists Android and iOS targets in one list, plus bootable emulator images and their hardware profiles. --platform narrows it to one platform.
autonom devices bootStarts an emulator by --avd and waits for boot, or boots a Simulator by --target.
autonom devices shutdown [--target ID]Shuts a target down. It refuses any serial that is not an emulator.
autonom session start [--app-id ID]Owns one target. --install and --launch install and open the app; a shut-down Simulator boots on its own.
autonom session show|stopShows the current session, or stops it and tears down what it started.
autonom session outputsLists every file you can follow, with a tail -f hint for a second terminal.
autonom session launch <app-id>Launches the app. --fresh starts it on a cleared task on Android, or after a terminate on iOS.
autonom session force-stop|uninstallStops or removes the app you name.
autonom session clear <app-id>Clears the app’s data; --strategy picks how. The differences below say how it varies by platform.
autonom note add <text> [--task T]Writes a note into the journal, tagged with its task.
autonom journal [--kind action|note]Reads the timeline back. --follow streams it; --session-id reads a finished session.
autonom processesLists what Autonom started, across the machine.
autonom cleanup [--dry-run] [--all]Reaps what Autonom started and left running, across the machine.

Android and iOS differences

One session per investigation. On iOS the target is the Simulator; a Simulator on another Mac is reachable through its idb companion.

CapabilityAndroidiOS Simulator
Clear app dataA full reset with pm clearUninstall and reinstall, which needs the app path from --install; the privacy strategy resets permissions only
Bootdevices boot waits until the emulator has bootedsession start boots a shut-down Simulator itself
Shut downEmulators only, never hardwareBy UDID
Launch options--activity; --fresh starts on a cleared task--arg and --setenv; --fresh terminates the app first; --log-stream on session start

Next steps

You own a session and can read every step back.