---
name: talkshell-setup
description: Install, pair, verify, and troubleshoot TalkShell — the iPhone app plus Mac server that lets you drive Claude Code by voice. Use when the user asks to set up TalkShell, start or restart the TalkShell server, install the app on their iPhone, pair the phone to the Mac, turn on screen mirroring, push notifications or remote access, or when TalkShell stops working.
---

# TalkShell setup

Two halves: a Python server on the Mac (`mac/server.py`, standard library only)
and a SwiftUI app on the iPhone (`ios/TalkShell.xcodeproj`). The phone talks to
the Mac over TLS on port 7777. No cloud account.

Read `talkshell.json` for paths, ports, and commands rather than parsing docs.

## Install

```bash
./setup.sh
```

Idempotent. Its last line is `READY`, `NEEDS_HUMAN`, or `FAILED`. Branch on it:

- `READY` → run `./verify.sh`, then build the app.
- `NEEDS_HUMAN` → the script printed a macOS permission deep link or a missing
  prerequisite. Relay it in one sentence and stop. TCC dialogs cannot be
  clicked from a script.
- `FAILED` → the failing step and its stderr are printed. Fix, re-run.

## Verify before claiming success

```bash
./verify.sh            # exits 0 only when the install works
./verify.sh --verbose  # adds raw responses
```

It checks the token, the TLS cert and its expiry, the LaunchAgent, `/ping`,
that a wrong token is rejected, that `/shells`, `/sessions` and `/vitals`
return JSON, that the host in `pairing.json` resolves, and that `claude` is on
PATH. Never report success without a zero exit.

## Build and install the app

Needs the user's own Apple signing, so it cannot be fully unattended.

1. `cat ~/.talk-shell/pairing.json` for host, port, token, LAN IP.
2. Find their team id: `security find-identity -v -p codesigning`. The
   10-character string in parentheses is it.
3. Set `DEVELOPMENT_TEAM` in `ios/TalkShell.xcodeproj/project.pbxproj`.
4. Change the bundle id off `v1.TalkShell`, which belongs to the original
   author and will not provision under another team.
5. `./tools/install-device.sh`
6. Pair the app with the values from step 1.

No codesigning identity means no paid Apple Developer account. Free signing
works and the install stops launching after 7 days. Say that plainly.

## Optional features

All off by default. Each is one env var in `~/.talk-shell/env`, then
`./setup.sh --restart`.

| Want | Set |
|---|---|
| Push notifications | `APNS_KEY_PATH`, `APNS_KEY_ID`, `APNS_TEAM_ID` (the user's own APNs key) |
| Local whisper | `WHISPER_BIN`, `WHISPER_MODEL` |
| Exact usage percentages | `COOKIE_JAR` |
| Screen mirroring | no env var; grant Screen Recording and Accessibility via `./setup.sh --permissions` |
| Access away from home | run `mac/setup-remote.sh` (needs a Cloudflare account) |

## Troubleshooting, in the order these actually happen

1. **Server not running.** `launchctl list | grep talkshell`, then
   `./setup.sh --restart`. Log at `/tmp/talk-shell.log`.
2. **Phone cannot reach the Mac.** Some networks block mDNS. Put `lan_ip` from
   `pairing.json` into the app's host field instead of the `.local` name.
3. **Mirror is black.** Screen Recording was never granted to whatever launches
   the server. `./setup.sh --permissions`.
4. **Certificate error in the app.** The cert was regenerated. Re-pair. Do not
   disable TLS validation.
5. **Empty shell list.** Automation → Terminal was denied, or no Claude Code
   session is open on the Mac.
6. **`claude` not found.** Set `CLAUDE_BIN` in `~/.talk-shell/env`.

## Never

- Generate an auth token. The server writes one to `~/.talk-shell-token`.
- Commit `~/.talk-shell/` or the token.
- Weaken TLS to work around a pinning failure.
- Install Homebrew packages without asking. The server needs none.
- Claim setup is finished before `./verify.sh` exits 0.
