An open API service indexing awesome lists of open source software.

https://github.com/ayagmar/pi-mobile

Android client for pi-rpc
https://github.com/ayagmar/pi-mobile

android kotlin mobile pi pi-mono

Last synced: 3 days ago
JSON representation

Android client for pi-rpc

Awesome Lists containing this project

README

          

# Pi Mobile

> **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](https://github.com/badlogic/pi-mono). It gives you live session control when you’re away from your laptop.

## Demo (WIP)

▶️ **Streamable demo:** https://streamable.com/jngtjp *(WIP)*

## Screenshots

| Chat + tools | Sessions + controls |
|---|---|
| ![Pi Mobile chat and tool streaming screenshot](https://i.imgur.com/sKXfkOe.png) | ![Pi Mobile session browsing screenshot](https://i.imgur.com/JBFchOQ.png) |

## What This Does

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, copy last response, export, import JSONL sessions
- Discover slash commands from an in-app command palette (`/tree`, `/stats`, `/model`, `/new`, `/name`, `/copy`, `/import`, ...)
- 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.

## High-Level Design

```mermaid
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](docs/architecture.md).

## Documentation

- [Documentation index](docs/README.md)
- [Architecture diagrams (Mermaid)](docs/architecture.md)
- [Architecture Decision Records (ADRs)](docs/adr/README.md)
- [Codebase guide](docs/codebase.md)
- [Custom extensions](docs/extensions.md)
- [Bridge protocol reference](docs/bridge-protocol.md)
- [Testing guide](docs/testing.md)

> Note: `docs/ai/` contains planning/progress artifacts used during development. User-facing and maintenance docs live in the top-level `docs/` files above.

## Setup

### 1. Laptop Setup

Install pi if you haven't:
```bash
npm install -g @mariozechner/pi-coding-agent
```

Clone and start the bridge:
```bash
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 start
```

The 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.

### 2. Phone Setup

Install the APK or build from source:
```bash
./gradlew :app:assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk
```

### 3. Connect

1. Add a host in the app:
- Host: your laptop's Tailscale MagicDNS hostname (`..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/.env` as `BRIDGE_AUTH_TOKEN`

2. The app will fetch your sessions from `~/.pi/agent/sessions/` (or `BRIDGE_SESSION_DIR` if overridden)

3. Tap a session to resume it

## How It Works

### Sessions

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.

### Process Management

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

### Message Flow

```
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
```

## Chat UX Highlights

- **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**: `edit` tool calls show before/after content.
- **Command palette**: insert slash commands quickly from the prompt field menu, including bridge-backed mobile commands.
- **Quick copy action**: copy the last assistant response from the chat header menu without typing `/copy`.
- **Bash dialog**: execute shell commands with timeout/truncation handling and history.
- **Session status in chat**: shows the active session name and queued message count from pi state.
- **Session names in session browser**: active named sessions are surfaced more clearly in the Sessions header, rename dialog, and cards.
- **Session stats sheet**: token/cost/message/context counters, queued-message summary, 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.

## Troubleshooting

### Can't connect

1. Check Tailscale is running on both devices
2. Verify the bridge is running: `curl http://100.x.x.x:8787/health` (only if `BRIDGE_ENABLE_HEALTH_ENDPOINT=true`)
3. Check the token matches exactly (BRIDGE_AUTH_TOKEN)
4. Prefer the laptop's MagicDNS hostname (`*.ts.net`) over raw IP literals

### Sessions don't appear

1. Check `~/.pi/agent/sessions/` exists on laptop
2. Verify the bridge has read permissions
3. Check bridge logs for errors

### Streaming is slow/choppy

1. Check logcat for `PerfMetrics` - see actual timing numbers
2. Look for `FrameMetrics` jank warnings
3. Verify WiFi/cellular connection is stable
4. Try closer to the laptop (same room)

### App crashes on resume

1. Check logcat for out-of-memory errors
2. Large session histories can cause issues
3. Try compacting the session first: `/compact` in pi, then resume

## Development

### Project Structure

```
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
```

### Running Tests

Use JDK 21 for Android and Gradle work in this repo.

```bash
# 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
```

### Logs to Watch

```bash
# 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.log
```

## Configuration

### Bridge Environment Variables

Create `bridge/.env`:

```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 the session dir used for indexing and spawned pi runtimes
BRIDGE_LOG_LEVEL=info # fatal,error,warn,info,debug,trace,silent
BRIDGE_ENABLE_HEALTH_ENDPOINT=true # set false to disable /health endpoint
```

### App Build Variants

Debug builds include logging and assertions. Release builds (if you make them) strip these for smaller size.

## Security Notes

- 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_HOST` to your Tailscale IP for remote access
- Avoid `0.0.0.0` unless you intentionally expose the service behind strict firewall/Tailscale policy
- `/health` exposure is explicit via `BRIDGE_ENABLE_HEALTH_ENDPOINT` (disable it for least exposure)
- Android cleartext traffic is scoped to `localhost` and Tailnet MagicDNS hosts (`*.ts.net`)
- All traffic goes over Tailscale's encrypted mesh
- Session data stays on the laptop; the app only displays it

## Limitations

- No offline mode - requires live connection to laptop
- Session history is fetched via `get_messages` and 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

## Testing

See [docs/testing.md](docs/testing.md) for emulator setup and testing procedures.

Quick start:
```bash
# Start emulator, build, install
./gradlew :app:installDebug

# Watch logs
adb logcat | grep -E "PiMobile|PerfMetrics"
```

## License

MIT