{"id":45507819,"url":"https://github.com/ayagmar/pi-mobile","last_synced_at":"2026-06-14T11:03:07.674Z","repository":{"id":338517901,"uuid":"1158028544","full_name":"ayagmar/pi-mobile","owner":"ayagmar","description":"Android client for pi-rpc","archived":false,"fork":false,"pushed_at":"2026-03-21T03:18:05.000Z","size":871,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-21T19:02:07.636Z","etag":null,"topics":["android","kotlin","mobile","pi","pi-mono"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ayagmar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-14T17:24:22.000Z","updated_at":"2026-03-21T03:18:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ayagmar/pi-mobile","commit_stats":null,"previous_names":["ayagmar/pi-mobile"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ayagmar/pi-mobile","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayagmar%2Fpi-mobile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayagmar%2Fpi-mobile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayagmar%2Fpi-mobile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayagmar%2Fpi-mobile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ayagmar","download_url":"https://codeload.github.com/ayagmar/pi-mobile/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayagmar%2Fpi-mobile/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34318525,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","kotlin","mobile","pi","pi-mono"],"created_at":"2026-02-22T19:00:32.933Z","updated_at":"2026-06-14T11:03:07.669Z","avatar_url":"https://github.com/ayagmar.png","language":"Kotlin","funding_links":[],"categories":["Tools \u0026 Utilities"],"sub_categories":[],"readme":"# Pi Mobile\n\n\u003e **Your Pi coding agent, in your pocket.**\n\u003e Run and steer coding sessions from Android anywhere over Tailscale.\n\nPi 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.\n\n## Demo (WIP)\n\n▶️ **Streamable demo:** https://streamable.com/jngtjp *(WIP)*\n\n## Screenshots\n\n| Chat + tools | Sessions + controls |\n|---|---|\n| ![Pi Mobile chat and tool streaming screenshot](https://i.imgur.com/sKXfkOe.png) | ![Pi Mobile session browsing screenshot](https://i.imgur.com/JBFchOQ.png) |\n\n## What This Does\n\nPi runs on your laptop. This app lets you:\n- Browse and resume coding sessions from anywhere\n- Chat with the agent: prompt, abort, steer, follow-up, compact, rename, copy last response, export, import JSONL sessions\n- Discover slash commands from an in-app command palette (`/tree`, `/stats`, `/model`, `/new`, `/name`, `/copy`, `/import`, ...)\n- View streaming thinking/tool blocks with collapse/expand controls\n- Open a built-in bash dialog (run/abort/history/copy output)\n- Inspect session stats, context usage, and pick models from an advanced model picker\n- Detect cross-device session drift and run **Sync now** for safe refresh\n- Attach images to prompts\n- Navigate session tree branches in-place (jump+continue), filter tree views, and fork from selected entries\n- Switch between projects (different working directories)\n- Handle extension dialogs/widgets/status updates (confirm/input/select/editor/setStatus/setWidget)\n\nThe connection goes over Tailscale, so it works anywhere without port forwarding.\n\n## High-Level Design\n\n```mermaid\nflowchart LR\n    Phone[\"Android app\\nPi Mobile\"]\n    Bridge[\"Node.js bridge\\nWebSocket ↔ pi stdio\"]\n    Pi[\"pi --mode rpc\\n(on laptop)\"]\n    Sessions[\"Session files\\n~/.pi/agent/sessions/*.jsonl\"]\n\n    Phone \u003c--\u003e|\"WebSocket + token auth\\nover Tailscale\"| Bridge\n    Bridge \u003c--\u003e|\"JSON lines\\nstdin/stdout RPC\"| Pi\n    Pi \u003c--\u003e Sessions\n    Bridge -. \"indexes sessions\" .-\u003e Sessions\n```\n\nThe 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).\n\n## Documentation\n\n- [Documentation index](docs/README.md)\n- [Architecture diagrams (Mermaid)](docs/architecture.md)\n- [Architecture Decision Records (ADRs)](docs/adr/README.md)\n- [Codebase guide](docs/codebase.md)\n- [Custom extensions](docs/extensions.md)\n- [Bridge protocol reference](docs/bridge-protocol.md)\n- [Testing guide](docs/testing.md)\n\n\u003e Note: `docs/ai/` contains planning/progress artifacts used during development. User-facing and maintenance docs live in the top-level `docs/` files above.\n\n## Setup\n\n### 1. Laptop Setup\n\nInstall pi if you haven't:\n```bash\nnpm install -g @mariozechner/pi-coding-agent\n```\n\nClone and start the bridge:\n```bash\ngit clone https://github.com/yourusername/pi-mobile.git\ncd pi-mobile/bridge\npnpm install\n# create .env and set BRIDGE_AUTH_TOKEN (see Configuration section below)\npnpm start\n```\n\nThe 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.\n\n### 2. Phone Setup\n\nInstall the APK or build from source:\n```bash\n./gradlew :app:assembleDebug\nadb install app/build/outputs/apk/debug/app-debug.apk\n```\n\n### 3. Connect\n\n1. Add a host in the app:\n   - Host: your laptop's Tailscale MagicDNS hostname (`\u003cdevice\u003e.\u003ctailnet\u003e.ts.net`)\n   - Port: `8787` (or whatever the bridge uses)\n   - Use TLS: off for local/Tailscale bridge unless you've put TLS in front\n   - Token: set this in `bridge/.env` as `BRIDGE_AUTH_TOKEN`\n\n2. The app will fetch your sessions from `~/.pi/agent/sessions/` (or `BRIDGE_SESSION_DIR` if overridden)\n\n3. Tap a session to resume it\n\n## How It Works\n\n### Sessions\n\nSessions 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.\n\n### Process Management\n\nThe bridge manages one pi process per cwd:\n- First connection to a project spawns pi (with internal extensions for tree navigation + mobile workflow commands)\n- Process stays alive with idle timeout (`BRIDGE_PROCESS_IDLE_TTL_MS`)\n- Short disconnects keep control locks during reconnect grace (`BRIDGE_RECONNECT_GRACE_MS`)\n- Reconnecting reuses the existing process\n- Crash restart with exponential backoff\n\n### Message Flow\n\n```\nUser types prompt\n    ↓\nApp sends WebSocket → Bridge\n    ↓\nBridge writes to pi stdin (JSON line)\n    ↓\npi processes, writes events to stdout\n    ↓\nBridge forwards events → App\n    ↓\nApp renders streaming text/tools\n```\n\n## Chat UX Highlights\n\n- **Thinking blocks**: streaming reasoning appears separately and can be collapsed/expanded.\n- **Tool cards**: tool args/output are grouped with icons and expandable output.\n- **Edit diff viewer**: `edit` tool calls show before/after content.\n- **Command palette**: insert slash commands quickly from the prompt field menu, including bridge-backed mobile commands.\n- **Quick copy action**: copy the last assistant response from the chat header menu without typing `/copy`.\n- **Bash dialog**: execute shell commands with timeout/truncation handling and history.\n- **Session status in chat**: shows the active session name and queued message count from pi state.\n- **Session names in session browser**: active named sessions are surfaced more clearly in the Sessions header, rename dialog, and cards.\n- **Session stats sheet**: token/cost/message/context counters, queued-message summary, and session path.\n- **Model picker**: provider-aware searchable model selection.\n- **Tree navigator**: inspect branch points, filter views, jump in-place, or fork from chosen entries.\n- **Session coherency guard**: warns on cross-device edits and offers **Sync now**.\n- **Settings controls**: auto-compaction, auto-retry, steer/follow-up delivery modes, theme, and status-strip visibility.\n\n## Troubleshooting\n\n### Can't connect\n\n1. Check Tailscale is running on both devices\n2. Verify the bridge is running: `curl http://100.x.x.x:8787/health` (only if `BRIDGE_ENABLE_HEALTH_ENDPOINT=true`)\n3. Check the token matches exactly (BRIDGE_AUTH_TOKEN)\n4. Prefer the laptop's MagicDNS hostname (`*.ts.net`) over raw IP literals\n\n### Sessions don't appear\n\n1. Check `~/.pi/agent/sessions/` exists on laptop\n2. Verify the bridge has read permissions\n3. Check bridge logs for errors\n\n### Streaming is slow/choppy\n\n1. Check logcat for `PerfMetrics` - see actual timing numbers\n2. Look for `FrameMetrics` jank warnings\n3. Verify WiFi/cellular connection is stable\n4. Try closer to the laptop (same room)\n\n### App crashes on resume\n\n1. Check logcat for out-of-memory errors\n2. Large session histories can cause issues\n3. Try compacting the session first: `/compact` in pi, then resume\n\n## Development\n\n### Project Structure\n\n```\napp/              - Android app (Compose UI, ViewModels)\ncore-rpc/         - RPC protocol models and parsing\ncore-net/         - WebSocket transport and connection management\ncore-sessions/    - Session caching and repository\nbridge/           - Node.js bridge service\nbenchmark/        - Macrobenchmark / baseline profile scaffolding\n```\n\n### Running Tests\n\nUse JDK 21 for Android and Gradle work in this repo.\n\n```bash\n# Android tests\n./gradlew test\n\n# Bridge tests\ncd bridge \u0026\u0026 pnpm test\n\n# Bridge full checks (lint + typecheck + tests)\ncd bridge \u0026\u0026 pnpm run check\n\n# All Android quality checks\n./gradlew ktlintCheck detekt test\n```\n\n### Logs to Watch\n\n```bash\n# Performance metrics\nadb logcat | grep \"PerfMetrics\"\n\n# Frame jank during streaming\nadb logcat | grep \"FrameMetrics\"\n\n# General app logs\nadb logcat | grep \"PiMobile\"\n\n# Bridge logs (on laptop)\npnpm start 2\u003e\u00261 | tee bridge.log\n```\n\n## Configuration\n\n### Bridge Environment Variables\n\nCreate `bridge/.env`:\n\n```env\nBRIDGE_HOST=0.0.0.0                 # Bind host (default: 127.0.0.1)\nBRIDGE_PORT=8787                    # Port to listen on\nBRIDGE_AUTH_TOKEN=your-secret       # Required authentication token\nBRIDGE_PROCESS_IDLE_TTL_MS=300000   # Idle process eviction window (ms)\nBRIDGE_RECONNECT_GRACE_MS=30000     # Keep control locks after disconnect (ms)\nBRIDGE_SESSION_DIR=/absolute/path/to/.pi/agent/sessions  # Override the session dir used for indexing and spawned pi runtimes\nBRIDGE_LOG_LEVEL=info               # fatal,error,warn,info,debug,trace,silent\nBRIDGE_ENABLE_HEALTH_ENDPOINT=true  # set false to disable /health endpoint\n```\n\n### App Build Variants\n\nDebug builds include logging and assertions. Release builds (if you make them) strip these for smaller size.\n\n## Security Notes\n\n- Token auth is required - don't expose the bridge without it\n- Token comparison is hardened in the bridge (constant-time hash compare)\n- The bridge binds to localhost by default; explicitly set `BRIDGE_HOST` to your Tailscale IP for remote access\n- Avoid `0.0.0.0` unless you intentionally expose the service behind strict firewall/Tailscale policy\n- `/health` exposure is explicit via `BRIDGE_ENABLE_HEALTH_ENDPOINT` (disable it for least exposure)\n- Android cleartext traffic is scoped to `localhost` and Tailnet MagicDNS hosts (`*.ts.net`)\n- All traffic goes over Tailscale's encrypted mesh\n- Session data stays on the laptop; the app only displays it\n\n## Limitations\n\n- No offline mode - requires live connection to laptop\n- Session history is fetched via `get_messages` and rendered in a capped window (no true server-side pagination yet)\n- Tree navigation is MVP-level (functional, minimal rendering)\n- Mobile keyboard shortcuts vary by device/IME\n\n## Testing\n\nSee [docs/testing.md](docs/testing.md) for emulator setup and testing procedures.\n\nQuick start:\n```bash\n# Start emulator, build, install\n./gradlew :app:installDebug\n\n# Watch logs\nadb logcat | grep -E \"PiMobile|PerfMetrics\"\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayagmar%2Fpi-mobile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fayagmar%2Fpi-mobile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayagmar%2Fpi-mobile/lists"}