# Artemis Control Artemis is the phone's **hands**. It drives the Pixel 8a screen from `.13` over Tailscale using **ADB wireless**, so the Hub can do things no deep link allows. The build spec is [`AGENTS.md`](AGENTS.md). Follow the phases in section 11 in order. ## Status | Phase | State | |---|---| | 1 — Prove the ADB link | ✅ proven — see [`docs/phase-1-adb-link.md`](docs/phase-1-adb-link.md) | | 2 — Act primitives | ✅ done — tap by text, type, scroll, back, home, launch | | 3 — Spotify recipe | ✅ done — `spotify_play` plays the right song end to end (13 steps, 35s), see [`docs/phase-3-spotify-recipe.md`](docs/phase-3-spotify-recipe.md) | | 4 — Song radio | not started | | 5 — Maps recipe | not started | | 6 — Action API | not started | | 7 — Resilience | not started | | 8 — Documentation | not started | ## Layout ``` cmd/artemis/ command line entry point internal/adb/ timeout-bounded wrapper around the adb binary internal/ui/ read the screen (uiautomator dump) and act on it (input) internal/recipe/ the recipes file format and its runner recipes/ one hand-editable file per task logs/ run log (JSON lines, not committed) docs/ phase evidence and notes ``` ## Build and test Go is not installed system-wide on `.13`; use a one-off nix shell. Nothing is added to `nixos-rebuild` and no system module changes. ```sh nix shell nixpkgs#go -c go build -o bin/artemis ./cmd/artemis nix shell nixpkgs#go -c go vet ./... nix shell nixpkgs#go -c go test ./... ``` ## Use The phone address defaults to `100.101.49.17`. Override with `ARTEMIS_PHONE`, pin a serial with `ARTEMIS_ADB_SERIAL`, point at a different adb with `ARTEMIS_ADB`, point at another recipes directory with `ARTEMIS_RECIPES`, and move the run log with `ARTEMIS_LOG`. ```sh ./bin/artemis connect # scan for the wireless-debugging port, then connect ./bin/artemis devices ./bin/artemis dump # text nodes and bounds ./bin/artemis keyguard # lock-screen state; exits 1 when locked ./bin/artemis launch com.spotify.music ./bin/artemis tap "Search" # find by text, tap its centre (FR-4) ./bin/artemis type "Rolling Stones Honky Tonk" ./bin/artemis scroll down ./bin/artemis back ./bin/artemis home ./bin/artemis demo # Phase 2 DoD: launch an app, tap a named element ``` ## Recipes A recipe is a plain-text file in `recipes/` that Sam edits by hand. Steps name what to find on screen; there are no coordinates anywhere. ```sh ./bin/artemis recipes # list them ./bin/artemis run spotify_play query="Rolling Stones Honky Tonk" ``` Read [`docs/phase-3-spotify-recipe.md`](docs/phase-3-spotify-recipe.md) for the file format, the verbs, and why list rows need their own step. ## Rules that the code enforces - **Find by text, never fixed coordinates.** `tap` resolves a text match to bounds and taps the centre; `tap_row` scores result rows against the query and taps the winning row's centre. - **Never tap blindly.** A missing or disabled element is a loud failure, not a guessed coordinate. A named bad screen (`guard`) fails with its own reason. - **Never touch a locked phone.** A secure keyguard stops Artemis with `phone is locked; unlock it and retry`. No PIN is stored, read or typed (AGENTS.md section 13 Q2). - **Confirm playback from the media session, not the screen.** Spotify's transport button keeps the label "Play" while music plays; the `playing` step asks Android what is actually playing and checks the track title. - **Wake first.** Every acting command wakes the screen before it acts (FR-7), and it checks the keyguard only after the screen is on. - **Bound every command.** No adb call runs without a timeout, and a recipe has a per-step and a whole-run timeout (FR-11). - **Log every run.** Each run appends a JSON line to `logs/runs.jsonl` (FR-10).