Your Pi coding agent, in your pocket. Run and steer coding sessions from Android anywhere over Tailscale.
Pi Mobile is an Android client for the Pi coding agent. It gives you live session control when you’re away from your laptop.
| Chat + tools | Sessions + controls |
|---|---|
![]() |
![]() |
Pi runs on your laptop. This app lets you:
- Browse and resume coding sessions from anywhere
- Chat with the agent: prompt, abort, steer, follow-up, compact, rename, export
- Discover slash commands from an in-app command palette (
/tree,/stats,/model,/new,/name, ...) - View streaming thinking/tool blocks with collapse/expand controls
- Open a built-in bash dialog (run/abort/history/copy output)
- Inspect session stats, context usage, and pick models from an advanced model picker
- Detect cross-device session drift and run Sync now for safe refresh
- Attach images to prompts
- Navigate session tree branches in-place (jump+continue), filter tree views, and fork from selected entries
- Switch between projects (different working directories)
- Handle extension dialogs/widgets/status updates (confirm/input/select/editor/setStatus/setWidget)
The connection goes over Tailscale, so it works anywhere without port forwarding.
flowchart LR
Phone["Android app\nPi Mobile"]
Bridge["Node.js bridge\nWebSocket ↔ pi stdio"]
Pi["pi --mode rpc\n(on laptop)"]
Sessions["Session files\n~/.pi/agent/sessions/*.jsonl"]
Phone <-->|"WebSocket + token auth\nover Tailscale"| Bridge
Bridge <-->|"JSON lines\nstdin/stdout RPC"| Pi
Pi <--> Sessions
Bridge -. "indexes sessions" .-> Sessions
The bridge is a small Node.js service that translates WebSocket to pi's stdin/stdout JSON protocol. The app connects to the bridge, not directly to pi. For deeper diagrams, see docs/architecture.md.
- Documentation index
- Architecture diagrams (Mermaid)
- Architecture Decision Records (ADRs)
- Codebase guide
- Custom extensions
- Bridge protocol reference
- Testing guide
Note:
docs/ai/contains planning/progress artifacts used during development. User-facing and maintenance docs live in the top-leveldocs/files above.
Install pi if you haven't:
npm install -g @mariozechner/pi-coding-agentClone and start the bridge:
git clone https://github.com/yourusername/pi-mobile.git
cd pi-mobile/bridge
pnpm install
# create .env and set BRIDGE_AUTH_TOKEN (see Configuration section below)
pnpm startThe bridge binds to 127.0.0.1:8787 by default. Set BRIDGE_HOST to your laptop Tailscale IP to allow phone access (avoid 0.0.0.0 unless you enforce firewall restrictions). It spawns pi processes on demand per working directory.
Install the APK or build from source:
./gradlew :app:assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk-
Add a host in the app:
- Host: your laptop's Tailscale MagicDNS hostname (
<device>.<tailnet>.ts.net) - Port:
8787(or whatever the bridge uses) - Use TLS: off for local/Tailscale bridge unless you've put TLS in front
- Token: set this in
bridge/.envasBRIDGE_AUTH_TOKEN
- Host: your laptop's Tailscale MagicDNS hostname (
-
The app will fetch your sessions from
~/.pi/agent/sessions/(orBRIDGE_SESSION_DIRif overridden) -
Tap a session to resume it
Sessions are grouped by working directory (cwd). Each session is a JSONL file in ~/.pi/agent/sessions/--path--/. The bridge reads these files directly since pi's RPC doesn't have a list-sessions command.
The bridge manages one pi process per cwd:
- First connection to a project spawns pi (with internal extensions for tree navigation + mobile workflow commands)
- Process stays alive with idle timeout (
BRIDGE_PROCESS_IDLE_TTL_MS) - Short disconnects keep control locks during reconnect grace (
BRIDGE_RECONNECT_GRACE_MS) - Reconnecting reuses the existing process
- Crash restart with exponential backoff
User types prompt
↓
App sends WebSocket → Bridge
↓
Bridge writes to pi stdin (JSON line)
↓
pi processes, writes events to stdout
↓
Bridge forwards events → App
↓
App renders streaming text/tools
- Thinking blocks: streaming reasoning appears separately and can be collapsed/expanded.
- Tool cards: tool args/output are grouped with icons and expandable output.
- Edit diff viewer:
edittool calls show before/after content. - Command palette: insert slash commands quickly from the prompt field menu, including bridge-backed mobile commands.
- Bash dialog: execute shell commands with timeout/truncation handling and history.
- Session stats sheet: token/cost/message/context counters and session path.
- Model picker: provider-aware searchable model selection.
- Tree navigator: inspect branch points, filter views, jump in-place, or fork from chosen entries.
- Session coherency guard: warns on cross-device edits and offers Sync now.
- Settings controls: auto-compaction, auto-retry, steer/follow-up delivery modes, theme, and status-strip visibility.
- Check Tailscale is running on both devices
- Verify the bridge is running:
curl http://100.x.x.x:8787/health(only ifBRIDGE_ENABLE_HEALTH_ENDPOINT=true) - Check the token matches exactly (BRIDGE_AUTH_TOKEN)
- Prefer the laptop's MagicDNS hostname (
*.ts.net) over raw IP literals
- Check
~/.pi/agent/sessions/exists on laptop - Verify the bridge has read permissions
- Check bridge logs for errors
- Check logcat for
PerfMetrics- see actual timing numbers - Look for
FrameMetricsjank warnings - Verify WiFi/cellular connection is stable
- Try closer to the laptop (same room)
- Check logcat for out-of-memory errors
- Large session histories can cause issues
- Try compacting the session first:
/compactin pi, then resume
app/ - Android app (Compose UI, ViewModels)
core-rpc/ - RPC protocol models and parsing
core-net/ - WebSocket transport and connection management
core-sessions/ - Session caching and repository
bridge/ - Node.js bridge service
benchmark/ - Macrobenchmark / baseline profile scaffolding
# Android tests
./gradlew test
# Bridge tests
cd bridge && pnpm test
# Bridge full checks (lint + typecheck + tests)
cd bridge && pnpm run check
# All Android quality checks
./gradlew ktlintCheck detekt test# Performance metrics
adb logcat | grep "PerfMetrics"
# Frame jank during streaming
adb logcat | grep "FrameMetrics"
# General app logs
adb logcat | grep "PiMobile"
# Bridge logs (on laptop)
pnpm start 2>&1 | tee bridge.logCreate bridge/.env:
BRIDGE_HOST=0.0.0.0 # Bind host (default: 127.0.0.1)
BRIDGE_PORT=8787 # Port to listen on
BRIDGE_AUTH_TOKEN=your-secret # Required authentication token
BRIDGE_PROCESS_IDLE_TTL_MS=300000 # Idle process eviction window (ms)
BRIDGE_RECONNECT_GRACE_MS=30000 # Keep control locks after disconnect (ms)
BRIDGE_SESSION_DIR=/absolute/path/to/.pi/agent/sessions # Override session index root (optional)
BRIDGE_LOG_LEVEL=info # fatal,error,warn,info,debug,trace,silent
BRIDGE_ENABLE_HEALTH_ENDPOINT=true # set false to disable /health endpointDebug builds include logging and assertions. Release builds (if you make them) strip these for smaller size.
- Token auth is required - don't expose the bridge without it
- Token comparison is hardened in the bridge (constant-time hash compare)
- The bridge binds to localhost by default; explicitly set
BRIDGE_HOSTto your Tailscale IP for remote access - Avoid
0.0.0.0unless you intentionally expose the service behind strict firewall/Tailscale policy /healthexposure is explicit viaBRIDGE_ENABLE_HEALTH_ENDPOINT(disable it for least exposure)- Android cleartext traffic is scoped to
localhostand Tailnet MagicDNS hosts (*.ts.net) - All traffic goes over Tailscale's encrypted mesh
- Session data stays on the laptop; the app only displays it
- No offline mode - requires live connection to laptop
- Session history is fetched via
get_messagesand rendered in a capped window (no true server-side pagination yet) - Tree navigation is MVP-level (functional, minimal rendering)
- Mobile keyboard shortcuts vary by device/IME
See docs/testing.md for emulator setup and testing procedures.
Quick start:
# Start emulator, build, install
./gradlew :app:installDebug
# Watch logs
adb logcat | grep -E "PiMobile|PerfMetrics"MIT

