# Quickstart

> First successful script: check connection state, print screen_info, run a short stdin Python block with pre-imported helpers, and read the success signal.

- Repository: ShawnPana/phone-harness
- GitHub: https://github.com/ShawnPana/phone-harness
- Human docs: https://grok-wiki.com/public/docs/shawnpana-phone-harness-bf80173a2a2e
- Complete Markdown: https://grok-wiki.com/public/docs/shawnpana-phone-harness-bf80173a2a2e/llms-full.txt

## Source Files

- `SKILL.md`
- `src/phone_harness/run.py`
- `src/phone_harness/helpers.py`
- `install.md`
- `phone-harness`
- `README.md`

---

---
title: "Quickstart"
description: "First successful script: check connection state, print screen_info, run a short stdin Python block with pre-imported helpers, and read the success signal."
---

`phone-harness` runs a one-shot stdin Python script with every public name from `src/phone_harness/helpers.py` already in scope—no imports, no daemon. The first successful path is: confirm session readiness with `connection_state()`, then print `screen_info()` and verify non-empty window bounds.

<Note>
Install and permissions must already pass `phone-harness --doctor` (or `./phone-harness --doctor` from a checkout). Pairing iPhone Mirroring and granting Accessibility + Screen Recording are user-only steps—see [Installation](/installation) and [Doctor diagnostics](/doctor-diagnostics).
</Note>

## Prerequisites

| Requirement | Notes |
|---|---|
| macOS Sequoia+ | iPhone Mirroring app available and paired once |
| `phone-harness` on PATH | From `pip install -e .` at `~/.phone-harness`, or `./phone-harness` in a checkout |
| Terminal permissions | Accessibility (input) and Screen Recording (capture); Screen Recording needs a terminal restart |
| Live session | iPhone Mirroring open with a connected phone (not the connect / “iPhone in Use” interstitial) |

## How the CLI runs a script

With no command args and a non-TTY stdin, `phone-harness` reads Python from stdin, builds a globals dict from every public name in `helpers` (names not starting with `_`), sets `__name__` to `"__main__"`, and `exec`s the code.

```bash
phone-harness <<'PY'
print(connection_state())
print(screen_info())
PY
```

From a git checkout without install:

```bash
./phone-harness <<'PY'
print(connection_state())
print(screen_info())
PY
```

| Invocation | Behavior |
|---|---|
| `phone-harness <<'PY' … PY` | Exec script with helpers pre-imported |
| `phone-harness --doctor` / `doctor` | Permission and session ladder; exits non-zero on hard FAIL |
| `phone-harness skill` | Prints `SKILL.md` to stdout |
| `phone-harness -h` / `--help` | Usage text |
| Args, empty stdin, or TTY stdin | Exits with usage (not a free-form Python REPL) |

Public helpers in scope for a first script include session and capture primitives such as `connection_state`, `ensure_mirroring`, `screen_info`, `screenshot`, `ocr`, `tap`, `tap_text`, `home`, `open_app`, `wait_stable`, plus re-exports (`tap`, `long_press`, `drag`, `press`, `type_text`, `activate`, `find_window`). Agent-editable names from `agent-workspace/agent_helpers.py` are auto-loaded into the same namespace at import time.

## First successful script

<Steps>
<Step title="Gate on connection state">
Call `connection_state()` before any gesture. Only `'ready'` means the mirrored phone content is usable.

```bash
phone-harness <<'PY'
state = connection_state()
print("state:", state)
if state != "ready":
    raise SystemExit(f"not ready: {state} — user must connect/lock the phone")
print(screen_info())
PY
```
</Step>
<Step title="Print screen_info">
`screen_info()` captures the mirroring window and returns bounds plus capture pixel size. This is the install.md success signal: if window bounds print, the capture path works.
</Step>
<Step title="Read the printed shape">
Success looks like a dict with non-zero `window` geometry and non-zero `img_px`. Failure is a raised error, empty usage exit, or a non-`ready` state string.
</Step>
</Steps>

### Expected success output

`connection_state()` returns one of:

| Value | Meaning |
|---|---|
| `ready` | App running, window present, OCR does not show a blocked interstitial |
| `blocked` | Connect / “iPhone in Use” / paused interstitial text detected |
| `no-window` | App running but no phone window |
| `not-running` | iPhone Mirroring process not running |

`screen_info()` return shape:

```python
{
  "window": {"x": float, "y": float, "w": float, "h": float, "id": int},
  "frontmost": bool,
  "img_px": [width_px, height_px],
}
```

| Field | Type | Meaning |
|---|---|---|
| `window` | dict | Screen-point bounds and CG window id (`x`, `y`, `w`, `h`, `id`) |
| `frontmost` | bool | Whether iPhone Mirroring is the frontmost app |
| `img_px` | `[int, int]` | Capture image width and height in pixels |

Example console shape (values vary by display layout):

```text
state: ready
{'window': {'x': 100.0, 'y': 80.0, 'w': 393.0, 'h': 852.0, 'id': 12345}, 'frontmost': True, 'img_px': [1179, 2556]}
```

<Check>
If `state` is `ready` and `screen_info()` prints a `window` with positive `w`/`h` and non-zero `img_px`, the harness can see the phone. That is the first successful script.
</Check>

## Optional gate: ensure_mirroring

`ensure_mirroring()` is the strict gate used before tasks: if state is `ready`, it activates the window and returns bounds; otherwise it raises `RuntimeError` with user-facing reconnect instructions. It never launches the app, taps Connect/Continue, or poll-waits for reconnect.

```bash
phone-harness <<'PY'
win = ensure_mirroring()
print("window:", win)
print(screen_info())
PY
```

| State | `ensure_mirroring()` |
|---|---|
| `ready` | Activates and returns window bounds |
| `not-running` | Raises — open iPhone Mirroring and connect |
| `no-window` | Raises — connect the phone in the app |
| `blocked` | Raises — user must connect / lock the phone; agent must not tap Connect |

<Warning>
Reconnecting is a physical user action. When state is not `ready`, stop and relay the error. Do not tap Connect/Continue and do not loop-poll; retry only after the user confirms they connected or locked the phone.
</Warning>

## Minimal script patterns

<CodeGroup>

```bash title="State + screen_info (first success)"
phone-harness <<'PY'
print(connection_state())
print(screen_info())
PY
```

```bash title="Strict gate then OCR sample"
phone-harness <<'PY'
ensure_mirroring()
info = screen_info()
print(info)
print([o["text"] for o in ocr()][:15])
PY
```

```bash title="Checkout launcher"
./phone-harness <<'PY'
print(connection_state())
print(screen_info())
PY
```

</CodeGroup>

## What counts as failure

| Symptom | Likely cause | Next action |
|---|---|---|
| Usage text only, non-zero exit | TTY stdin, empty script, or unexpected args | Use a heredoc; no extra CLI args on the script path |
| `not-running` | iPhone Mirroring not open | User opens the app |
| `no-window` | No phone window | User pairs/connects in the app |
| `blocked` | “iPhone in Use”, “lock your iphone”, “mirroring ended”, or “to connect” OCR | User locks phone / connects; do not tap interstitial |
| Capture errors / blank image | Screen Recording missing or terminal not restarted | Re-grant permission, restart terminal, re-run `--doctor` |
| Silent no-ops later on taps | Accessibility missing or focus lost | Grant Accessibility; re-activate if needed |

Blocked interstitial detection uses OCR over capture text matched case-insensitively against markers: `iphone in use`, `lock your iphone`, `mirroring ended`, `to connect`.

## Coordinates note for the next script

All helper coordinates are **global screen points**, not image pixels. `window` is in screen points; `img_px` is capture resolution. Convert unlabeled icon taps with image pixels ÷ scale + window origin. Do not cache coordinates across calls—window bounds are re-queried per capture/gesture.

## Consent boundary

This drives the user’s real phone. Navigating and reading for the user’s task is fine; stop and ask before outward-facing or hard-to-reverse actions (messages, posts, purchases, deletes, settings changes). Prefer Mac or web surfaces when the phone is not required.

## Next

<CardGroup>
  <Card title="Connection and session states" href="/connection-and-session">
    ready / blocked / no-window / not-running, ensure_mirroring gates, and user-only reconnect.
  </Card>
  <Card title="See, act, and verify" href="/see-act-verify">
    OCR-first loop: ocr, tap_text, wait_stable, screenshot as ground truth.
  </Card>
  <Card title="Helpers API" href="/helpers-api">
    Full pre-imported helper signatures, defaults, and return shapes.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Entry points, usage exits, skill output, and the checkout launcher.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Blank capture, window not found, silent taps, and blocked session recovery.
  </Card>
</CardGroup>
