# Installation

> Prerequisites, clone to ~/.phone-harness, pyobjc and editable pip install, PATH command, skill registration, and verification with phone-harness --doctor.

- 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

- `install.md`
- `pyproject.toml`
- `phone-harness`
- `src/phone_harness/run.py`
- `src/phone_harness/admin.py`
- `README.md`

---

---
title: "Installation"
description: "Prerequisites, clone to ~/.phone-harness, pyobjc and editable pip install, PATH command, skill registration, and verification with phone-harness --doctor."
---

Installation installs the `phone-harness` console script (`phone_harness.run:main`) from an editable checkout at `~/.phone-harness`, registers the agent skill body printed by `phone-harness skill`, and verifies the permission/session ladder with `phone-harness --doctor`.

## Prerequisites

| Requirement | Detail |
|---|---|
| OS | macOS Sequoia or later (ships **iPhone Mirroring** at `/System/Applications/iPhone Mirroring.app`) |
| Phone | Real iPhone paired to iPhone Mirroring (open the app once manually; pairing needs the physical device) |
| Python | Package metadata: `requires-python >= 3.10`. `install.md` documents **Python 3.12+** for the install path |
| pyobjc | `pyobjc-framework-Quartz`, `pyobjc-framework-Vision`, `pyobjc-framework-AppKit` (declared deps also include `pyobjc-framework-ApplicationServices`) |
| Permissions | **Accessibility** (taps/keystrokes) and **Screen Recording** (capture) for the terminal app that runs `phone-harness` |

User-only steps the harness cannot do for you:

1. Pair iPhone Mirroring with the phone.
2. Toggle Accessibility and Screen Recording in System Settings → Privacy & Security.

Open the privacy panes:

```bash
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
open "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"
```

| Permission | Effect timing | Failure if missing |
|---|---|---|
| Accessibility | Immediate | Taps/keystrokes fail or do nothing |
| Screen Recording | After terminal restart | Blank/black capture; doctor reports capture size too small |

<Warning>
Accessibility and Screen Recording are the permissions `--doctor` currently checks. A fresh Mac may still prompt for additional approvals the first time an action runs. If doctor passes but taps, typing, or capture silently do nothing, watch for a macOS prompt and re-check Privacy & Security for your terminal.
</Warning>

## Canonical install layout

`~/.phone-harness` is the canonical home: source, `SKILL.md`, `src/phone_harness/`, and `agent-workspace/` stay at a fixed path agents and editable installs can rely on.

:::files
~/.phone-harness/
├── phone-harness          # checkout launcher (PYTHONPATH=src)
├── pyproject.toml         # package + console_scripts entry
├── SKILL.md               # skill body for phone-harness skill
├── install.md
├── agent-workspace/
│   └── agent_helpers.py   # agent-editable helpers (auto-loaded)
└── src/phone_harness/
    ├── run.py             # CLI: stdin exec, --doctor, skill
    ├── admin.py           # doctor ladder
    ├── helpers.py         # pre-imported script namespace
    ├── mirror.py          # classic backend
    ├── background.py      # default no-focus backend
    └── ocr.py
:::

`pip install -e .` binds the `phone-harness` command to that checkout. Keep the folder at `~/.phone-harness`, or re-run `pip install -e .` after relocating.

## Install

<Steps>
<Step title="Clone to canonical home">
```bash
git clone https://github.com/ShawnPana/phone-harness ~/.phone-harness
cd ~/.phone-harness
```
</Step>
<Step title="Install pyobjc frameworks">
Install the frameworks first so `--no-deps` on the package install can skip network resolution if needed:

```bash
pip install pyobjc-framework-Quartz pyobjc-framework-Vision pyobjc-framework-AppKit
```

`pyproject.toml` also lists `pyobjc-framework-ApplicationServices` (used by doctor via `AXIsProcessTrusted`). Prefer a full editable install with deps when PyPI is reachable:

```bash
pip install -e .
```
</Step>
<Step title="Editable package install (PATH command)">
When pyobjc is already installed (or PyPI is unreachable for deps):

```bash
pip install -e . --no-deps
```

This registers the console script:

| Item | Value |
|---|---|
| Command | `phone-harness` |
| Entry | `phone_harness.run:main` |
| Build backend | hatchling; wheel packages `src/phone_harness` |

After install, `phone-harness` works from any directory (required for skill-driven use).
</Step>
<Step title="Grant terminal permissions">
Enable **Accessibility** and **Screen Recording** for the terminal (or IDE) that will run the command. Restart that app after granting Screen Recording.
</Step>
<Step title="Pair iPhone Mirroring">
Open **iPhone Mirroring** once manually and complete pairing. Connecting or resuming a session is a physical user action; the harness does not auto-connect past interstitials.
</Step>
<Step title="Register the agent skill">
```bash
mkdir -p ~/.claude/skills/phone-harness
phone-harness skill > ~/.claude/skills/phone-harness/SKILL.md

mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills/phone-harness"
phone-harness skill > "${CODEX_HOME:-$HOME/.codex}/skills/phone-harness/SKILL.md"
```

`phone-harness skill` prints repo-root `SKILL.md` (UTF-8) to stdout. Skill frontmatter name/description:

| Field | Value |
|---|---|
| `name` | `phone-harness` |
| `description` (trigger) | Control the user's iPhone through the Mac's iPhone Mirroring window: open apps, tap, type, swipe, read the screen. |

Re-run the redirect lines after `git pull` so registered copies stay current.
</Step>
<Step title="Verify">
```bash
phone-harness --doctor
```

Smoke test once doctor is clean:

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

Success: `screen_info()` prints window bounds (and image pixel size). That means the package, window discovery, and capture path are live.
</Step>
</Steps>

### Checkout launcher (no pip)

From a working tree without installing:

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

The `phone-harness` shell script sets `PYTHONPATH=<repo>/src` and runs `python3 -m phone_harness.run`. Day-to-day agent use still expects the PATH command from the editable install.

## CLI surfaces used at install time

| Invocation | Behavior |
|---|---|
| `phone-harness --doctor` / `phone-harness doctor` | Runs `admin.run_doctor()`; process exit `0` if required checks pass, else `1` |
| `phone-harness skill` | Prints `SKILL.md` from the installed package’s repo root |
| `phone-harness -h` / `--help` | Prints usage |
| `phone-harness` + stdin script | `exec` of Python with helpers from `phone_harness.helpers` in scope |
| No args on a TTY, empty stdin, or unexpected args | Exits with usage text |

## Doctor verification ladder

`phone-harness --doctor` prints `phone-harness doctor` then ordered checks. Fix the first `FAIL`; later steps depend on earlier ones.

| Order | Check | Notes |
|---|---|---|
| 1 | pyobjc frameworks (Quartz, Vision, AppKit) | Import failure → exit `1` immediately |
| 2 | Accessibility | `AXIsProcessTrusted()` |
| 3 | Screen Recording | `CGPreflightScreenCaptureAccess()` |
| 4 | iPhone Mirroring installed | Path exists at `/System/Applications/iPhone Mirroring.app` |
| 5 | iPhone Mirroring running | Non-fatal if not running (auto-launch path exists on first use for some backends) |
| 6 | Mirroring window found | Open app and pair if missing |
| 7 | Window capture works | `screencapture` of window id; size must be `> 20_000` bytes |
| 8 | Vision OCR works | Count of recognized text boxes when capture is large enough |

Output lines look like `  [PASS] …` or `  [FAIL] … — <hint>`. Closing line is `all clear` or `fix the FAILs above, then re-run`, plus a note that fresh machines may need extra permission prompts.

### Required vs informational checks

- **Required for exit 0** (when applicable): pyobjc, Accessibility, Screen Recording, app installed, non-blank capture when a window exists.
- **Reported but not always fatal**: app not running, window not found (no capture/OCR attempt without a window), OCR box count is informational once capture succeeds.

## Install failure modes

| Symptom | Likely cause | Recovery |
|---|---|---|
| `phone-harness: command not found` | Editable install missing or wrong env | `cd ~/.phone-harness && pip install -e .` (or `--no-deps` after pyobjc) |
| Doctor FAIL on pyobjc | Frameworks not installed in this Python | `pip install pyobjc-framework-Quartz pyobjc-framework-Vision pyobjc-framework-AppKit` |
| Capture blank / size FAIL | Screen Recording granted but terminal not restarted | Quit and reopen the terminal app, re-run doctor |
| Window not found | Not paired, out of range, or connect interstitial | Open iPhone Mirroring manually; user locks/connects phone if “iPhone in Use” |
| Taps do nothing | Accessibility off, or focus stolen (classic backend) | Grant Accessibility; see input-backends and troubleshooting if needed |
| Editable install broken after move | `pip install -e .` bound to old path | Keep `~/.phone-harness` or re-run `pip install -e .` |

## Related configuration (post-install)

Not required for install, but active after the package imports:

| Variable | Default | Role |
|---|---|---|
| `PHONE_HARNESS_BACKGROUND` | `"1"` (on) | Background/SkyLight backend unless `0`/`false`/`no`; falls back to classic `mirror` if load fails |
| `PH_AGENT_WORKSPACE` | `<repo>/agent-workspace` | Override path for agent-editable `agent_helpers.py` |

Temp captures land under the system temp dir in a `phone-harness` subdirectory.

## Next

<CardGroup>
  <Card title="Quickstart" href="/quickstart">
    First script: connection state, screen_info, and a short stdin Python block.
  </Card>
  <Card title="Doctor diagnostics" href="/doctor-diagnostics">
    Full doctor ladder, exit codes, and fresh-machine permission notes.
  </Card>
  <Card title="Register as an agent skill" href="/register-agent-skill">
    Claude Code / Codex install paths, trigger text, and re-sync after pulls.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Entry points, usage errors, and the checkout launcher.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Blank capture, window missing, silent taps, and blocked sessions.
  </Card>
  <Card title="Overview" href="/overview">
    What phone-harness exposes and runtime assumptions.
  </Card>
</CardGroup>
