Skip to content

Run BoB from Your iPhone

By the end of this tutorial your iPhone is attached to a live warp-drive run on farm-01. You can watch it, type into it, put the phone away and come back to it, and you can drive a Claude Code session from the Claude app. More than that, you will know what each piece does, so when the connection breaks you can tell which piece broke.

The phone never runs BoB. Every run stays on the machine that started it, and the phone is a window onto it. Six pieces make that window. Each part below explains one piece first, then sets it up, then checks it.

You need:

  • An iPhone with nothing installed for this yet. An iPad works the same way; the differences are noted where they exist.
  • Your Mac with BoB on it, where you finished Where BoB Talks to You and A Night on the Farm.
  • farm-01 switched on.
  • About 45 minutes.

Commands in grey boxes are typed on the Mac unless a step says on the phone.


What it is. A tailnet is a private network made of your own devices. Tailscale builds it: each device signs in with the same account, and from then on they can reach each other by name, from anywhere, with the traffic encrypted end to end. Nothing is opened to the internet.

Why BoB needs it. farm-01 sits at home behind your router. The tailnet is how the phone reaches it from a café or a train, by the name farm-01, without port forwarding. Every machine in BoB’s fleet is reached this way, so the phone joins the same tailnet.

Steps.

  1. On the phone, install Tailscale from the App Store (Tailscale for iOS).
  2. Open it and tap Get Started. Allow the VPN configuration when iOS asks: that is how Tailscale carries the phone’s traffic to your machines. Allow notifications too; Tailscale uses them to warn you before your sign-in expires.
  3. Tap Log in and sign in with the same account your Mac and farm-01 use.

Check it worked. The Tailscale app lists your machines, farm-01 among them, with a green dot. On the Mac:

Terminal window
tailscale status

You should see a line for the phone (named after the device) next to farm-01 and your Mac. If the phone is missing, it signed in to a different account: log out in the app and sign in again with the right one.

What it is. SSH is how one machine opens a shell on another: you type on the phone, the commands run on farm-01, and the output comes back. mosh (“mobile shell”) starts the same way, over SSH, then hands the session to a small mosh-server on farm-01 and talks to it over UDP.

Why mosh, and not just ssh. A phone changes network all the time: Wi-Fi to cellular, asleep and awake. A plain SSH connection dies each time, and you have to log in again. A mosh session survives it: you lock the phone, ride the train, open the app, and the same screen is there. It also echoes your typing straight away on a slow link. SSH is the fallback when mosh cannot get through (see When it breaks).

Steps.

  1. On the phone, install an SSH app that speaks mosh. This tutorial uses Blink Shell, whose docs cover SSH keys and mosh. Any app that speaks mosh and keeps one key per device will do; the kit file records the one you chose.

  2. On farm-01, make sure mosh-server and tmux are installed. From the Mac:

    Terminal window
    ssh farm-01 'command -v mosh-server tmux'

Check it worked. The command prints two paths, such as /usr/bin/mosh-server and /usr/bin/tmux. A missing line means that program is not installed: ssh farm-01 'sudo apt install -y mosh tmux'.

What it is. An SSH key is a pair: a private key that never leaves the device, and a public key you hand out. A machine that has your public key in its ~/.ssh/authorized_keys lets in whoever holds the matching private key, with no password. A fingerprint (SHA256:…) is a short, unique name for a key, so you can check two machines are talking about the same one.

Why one key per device. If the phone is lost, you remove that one line from authorized_keys on each machine, and nothing else changes. The Mac’s key, the iPad’s key and the farm’s own keys keep working. The phone’s private key stays in the phone’s keychain; BoB never stores a key, only its name and fingerprint.

Steps.

  1. On the phone, open Blink Shell, type config and tap Keys. Tap +, then Generate New.

  2. Name it ibob-iphone (on an iPad, ibob-ipad). Choose Ed25519 as the key type, then save. (Not yet checked on a device: the exact label of Blink’s Ed25519 option may differ. Pick the Ed25519 type whatever it is called.)

  3. Open the new key and copy its public key (not yet checked on a device: the name of Blink’s copy action): one line that starts with ssh-ed25519 and ends with ibob-iphone. Send it to the Mac with AirDrop, Notes or Universal Clipboard. It is public, so sending it is safe.

  4. On the Mac, append it to farm-01’s authorized_keys. Paste the line in place of PASTE-THE-LINE-HERE, keeping the single quotes:

    Terminal window
    ssh farm-01 "cat >> ~/.ssh/authorized_keys" <<< 'PASTE-THE-LINE-HERE'

    Do the same on your Mac (cat >> ~/.ssh/authorized_keys) if you want to reach it from the phone too.

Check it worked.

Terminal window
ssh farm-01 'ssh-keygen -lf ~/.ssh/authorized_keys' | grep ibob-iphone

You should see 256 SHA256:… ibob-iphone (ED25519). Keep the SHA256:… part for the next step. No line means the paste did not land: run step 4 again.

What it is. Everything you just set up is written in one file, config/ibob-kit.json in your operator repo: the apps, each device and its key’s fingerprint, the machines that must let it in, and where to attach. One command, bob ibob check, reads that file and tests every machine it names, in the order a connection needs them: tailnet, SSH, the device key, mosh, tmux. It stops at the first gate that fails and prints the fix.

Why BoB needs it. You will not do this setup often enough to remember it. The file remembers it, and the check is the tool you reach for when the phone cannot connect: it tells you which piece is broken.

Steps.

  1. Copy the template into the operator repo:

    Terminal window
    mkdir -p ~/projects/bob-operator/config && cp ~/projects/bigbrain/templates/ibob/ibob-kit.json ~/projects/bob-operator/config/ibob-kit.json
  2. Open ~/projects/bob-operator/config/ibob-kit.json and replace every <…> value: the client name (Blink Shell), your iPhone’s label, and farm-01 in authorized_on and attach.default_targets. Then add the key’s fingerprint from part 3: the template has no line for it, so put one under "inventory_id" inside devices[0].key, with a comma after the line above it, and paste your own SHA256:… value in place of the example:

    "key": {
    "name": "ibob-iphone",
    "inventory_id": "ibob-iphone-ssh-key",
    "fingerprint": "SHA256:PASTE-YOUR-FINGERPRINT-FROM-PART-3"
    },

    With a fingerprint the check matches the exact key; without one it falls back to matching the ibob-iphone comment. The file’s fields are in the iBoB kit reference.

  3. Declare the key as a credential, so bob secrets check knows it exists: add ibob-iphone-ssh-key to secrets-inventory.json with an ssh-key location, and a secrets[] entry with the same inventory_id to operator.json (how-to step 4 shows the shape).

Check it worked.

Terminal window
bob ibob check

You should see iBoB terminal kit — converged, a ✓ on every row, and under farm-01 a · sessions: line. A ✗ row has a fix: line under it; do what it says and run the check again. When it breaks shows the common ones.

What it is. tmux keeps a terminal session alive on the machine, with nobody looking at it. A program running inside it keeps running when your connection drops. Attaching puts your screen on that session; detaching takes your screen away and leaves the session running. Many screens can attach to the same session at once.

Why BoB needs it. Every warp-drive run lives in a tmux session named warp-<project> (and every parallel fork in a cdfork-… session). That is what lets the phone join a run the Mac started, watch it, and leave without stopping it.

Steps.

  1. Make sure a run is live on farm-01. If you have none, start one in your tutorial project from A Night on the Farm:

    Terminal window
    ssh farm-01
    cd ~/projects/hello-links && bob warp start

    Type the two lines one at a time: the first opens a shell on the farm, the second runs there. (bob is only on the farm’s PATH in a shell you open, so putting both on one ssh farm-01 line answers bob: command not found.) Type exit to come back to the Mac; the run keeps going.

  2. Ask which sessions are live and what to type on the phone:

    Terminal window
    bob ibob attach farm-01

    You should see one line per session with its command, such as mosh farm-01 -- tmux attach -t warp-hello-links.

  3. On the phone, in Blink Shell, type that command exactly.

  4. Detach: press Ctrl-b, let go, then press d. On the iPhone, Ctrl is on the bar above the keyboard; on an iPad with a hardware keyboard, use its Control key.

  5. Type the same command again to come back.

Check it worked. After step 3 the phone shows the same run your Mac shows, moving. After step 4 the phone is back at Blink’s prompt and, on the Mac, bob warp status (run in the project on farm-01) still shows the run going. Lock the phone for a minute and unlock it while attached: mosh puts you back on the same screen without logging in again.

6. Drive a Claude Code session with Remote Control

Section titled “6. Drive a Claude Code session with Remote Control”

What it is. Remote Control is Claude’s own feature: a Claude Code session on a machine, opened in the Claude iOS app, so you can read and type in that session from the phone. The session still runs on the machine.

Why it is separate from tmux. tmux shows you the terminal, which is the right window for a warp run you want to watch. Remote Control is a chat window onto one Claude session, which is easier to type into on a phone. BoB builds no replacement; it records in the kit that this route is supported.

Steps.

  1. On the phone, install the Claude app and sign in with the same claude.ai account as the Mac.

  2. On the Mac (or attached to farm-01), start a session with Remote Control on (Remote Control docs):

    Terminal window
    claude --remote-control

    Inside a session that is already running, type /rc instead.

  3. On the phone, open the session from the Claude app’s session list and send one short prompt.

Check it worked. The terminal shows the Remote Control indicator, and the prompt you sent from the phone appears in the terminal with Claude’s answer, on both screens. An eligibility error means the machine is signed in with an API key: Remote Control needs a claude.ai login on a Pro, Max, Team or Enterprise plan.

Checkpoint. The phone is attached to a live warp run on farm-01, you can detach and come back, and you can drive a Claude session from the Claude app.


Start every diagnosis on the Mac with bob ibob check. It tests the same chain the phone uses, in order, and stops at the first broken link with its fix. Use --machine <id> to check one machine.

On the phone you see What broke The check says Fix
The connection hangs, then times out The phone or the machine is off the tailnet ✗ tailnet: offline Turn Tailscale on in the phone’s app; wake the machine or start Tailscale on it
Permission denied (publickey) The machine does not have this phone’s key ✗ key:iphone: … not in ~/.ssh/authorized_keys Append the phone’s public key again (part 3, step 4)
Connection refused to your Mac Remote Login is off on the Mac ✗ ssh: port 22 refused the connection Turn it on in System Settings; BoB never does that for you
can't find session or no sessions The run ended, so its tmux session is gone no live warp or cdfork session Start one with bob warp start, or attach to another machine
mosh hangs at “Connecting…” mosh-server is missing, or UDP cannot get through ✗ mosh: mosh-server not on PATH Install mosh on the machine; if the check passes, use ssh -t instead

If the phone’s own Tailscale is off, the check on the Mac still passes: it can only see the machines. So when the check is green and the phone still cannot connect, look at the phone first: open Tailscale and switch it on.

The machine is offline on the tailnet.

$ bob ibob check --machine farm-01
iBoB terminal kit — drift
✗ tailnet: offline
fix: wake farm-01 or start Tailscale on it

The check stops there: without the tailnet nothing else can be tested.

The key is rejected.

$ bob ibob check --machine farm-01
iBoB terminal kit — drift
✓ ssh: accepted
✗ key:iphone: ibob-iphone not in ~/.ssh/authorized_keys

The fix: line under it names the machine and the app to copy the key from. SSH itself works (the Mac got in with its own key); it is the phone’s key that is missing.

Remote Login is off on a Mac. <your-mac> stands for your Mac’s name in the fleet.

$ bob ibob check --machine <your-mac>
iBoB terminal kit — drift
✗ ssh: port 22 refused the connection
fix: turn on Remote Login on <your-mac>: System Settings → General → Sharing → Remote Login (BoB reports this, never enables it)

The tmux session is gone.

$ bob ibob attach farm-01
farm-01: no live warp or cdfork session on farm-01
fix: start one with bob warp start on farm-01, or pick another machine

A run that finished closes its session. Nothing is lost: its reports are on GitHub, and bob warp log on the machine shows what it did.

mosh is blocked.

$ bob ibob check --machine farm-01
iBoB terminal kit — drift
✗ mosh: mosh-server not on PATH
fix: sudo apt install mosh on farm-01

When mosh-server is installed and the check passes but the phone still hangs at “Connecting…”, the machine’s firewall is dropping mosh’s UDP ports (60000–61000). Attach over plain SSH instead, which needs only the SSH port:

Terminal window
ssh -t farm-01 tmux attach -t warp-hello-links

Coming soon. iBoB’s web app is not shipped yet. When it is, this part installs it on the phone’s home screen from Safari and turns on its notifications. Until then, the phone’s view of the fleet is bob viz --tailnet, opened in Safari on the phone (stop 6 of Where BoB Talks to You).