Vect on your phone
Your agents run on your machine. The phone is a second screen onto them: see what they are doing, answer them, from wherever you are in the house.
Nothing is uploaded anywhere. The phone talks directly to your computer.
The way to use this today is the phone's browser: scan the code and the second screen opens, with nothing to install. There are iOS and Android builds of the same client in the source tree, but neither is released, so they are something you build yourself rather than something you can download.
Pair a device
- On the computer running Vect, open Settings and find Devices.
- Turn on Reachable on this network. Until you do, only that computer can connect to it.
- Press Pair a device. A QR code appears next to a six-digit code and an
address such as
192.168.0.14:9878. - Point the phone's camera at the QR code and open the link. That is the whole gesture: no typing, no button. Typing the address and code by hand works too, for a device with no camera.
The code lasts five minutes and pairs exactly one device. The phone is issued a token it keeps; it will not ask again. Revoke a device from the same panel and its token stops working immediately.
What the phone can do
- See which agents are running and in which project.
- Open one and read the conversation as it streams, including tool calls.
- Reply.
- Answer permission prompts. When an agent asks to run something, the phone shows what it wants and an Allow/Deny pair, and raises a notification.
Notifications only arrive while the app is open. iOS suspends the connection when the app goes to the background, so a phone in your pocket will not buzz. Real background delivery needs Apple's push service, which is not wired up yet.
Without installing the app
vect ui serves the same client at /remote, so any phone browser on the
network can be a second screen with nothing installed:
$ vect ui --host 0.0.0.0
Vect UI running at http://0.0.0.0:4321
Second screen at http://0.0.0.0:4321/remote
It accepts the same pairing payload as a query string, so a link works where a QR scan would.
The phone renders the same event stream the desktop does, from the same raw provider output, so it never drifts into showing you something different from what is on your screen at home.
Building the app
The mobile client lives in apps/mobile. It is the same React code as the rest
of Vect, wrapped as a Tauri 2 app.
pnpm --filter @vect/mobile ios:dev # run on a simulator or attached iPhone
pnpm --filter @vect/mobile ios:build # produce an .ipa
Android carries its own toolchain, which this repo does not install for you:
brew install openjdk@21 android-commandlinetools
export JAVA_HOME=/opt/homebrew/opt/openjdk@21
export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools
yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --licenses
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \
"platform-tools" "platforms;android-35" "build-tools;35.0.0" "ndk;27.1.12297006"
export NDK_HOME="$ANDROID_HOME/ndk/27.1.12297006"
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
pnpm --filter @vect/mobile android:dev # run on a device or emulator
pnpm --filter @vect/mobile android:build --debug --apk # produce an .apk
The generated Android project is committed, so tauri android init is only
needed for a fresh one. One line in its manifest is hand-written and would be
lost by re-running init: android:usesCleartextTraffic="true". Tauri turns
cleartext off for release builds, and a phone talking ws:// to a machine on
your own network is the entire feature. Android has no "local networking only"
switch the way iOS does, so this is all or nothing.
Why the deep link is declared by scheme
tauri.conf.json declares "mobile": [{ "scheme": ["vect"] }]. The plugin's
default is https/http app links, and it does not merely generate a manifest
entry from that: it also filters incoming URLs against the same config, so
a vect://pair?… link would launch the app and then be discarded before
reaching JavaScript. A QR code cannot carry an app link to a host nobody owns,
so the custom scheme is the only workable form and it has to be declared here.
The client reads the link with both getCurrent() and onOpenUrl(). Scanning
a code starts the app, so the link that matters arrives before any listener
exists; onOpenUrl alone only covers a phone that already had Vect open.
iOS needs two Info.plist keys before it will even attempt a ws:// connection
to a machine on your network: an App Transport Security exception for local
networking, and a stated purpose for local network access. Both live in
apps/mobile/src-tauri/Info.ios.plist and are merged into the generated
project, so they survive re-running tauri ios init. The CFBundleURLTypes
entry for the vect scheme is not merged (only scalar keys are), so it lives
directly in gen/apple/vect-mobile_iOS/Info.plist.
Ports
| Port | Surface |
|---|---|
| 9876 | Local IPC bridge (vect mcp serve talks to this) |
| 9877 | CRDT sync for Collab sessions |
| 9878 | Remote clients (this feature) |
9878 binds to 127.0.0.1 until you turn on network access, and rejects every
request that does not carry a paired device's token.