PiAgentUI logo

PiAgentUI

Desktop and web workspace for AI coding agents: streams real Pi Agent sessions with chat, tool cards, MCP and skills panels.

Quickstart · Architecture · Docs · Issues ![Stack](https://img.shields.io/badge/Stack-Tauri%20%2B%20TypeScript-24C8DB?logo=tauri&logoColor=white) ![Status](https://img.shields.io/badge/status-beta%200.6.10-yellow) ![License](https://img.shields.io/badge/license-GPL--3.0--only-green) **English (US)** | [Português (BR)](./README.pt-BR.md) | [Español](./README.es.md) | [日本語](./README.ja.md)

## 📌 The problem Pi Agent runs in a terminal. A bare terminal gives you no overview of sessions, no readable tool calls, and no place to inspect MCP servers, skills or context usage. PiAgentUI puts those in one window, as a web app or a Tauri desktop app, without inventing agent state: sessions, models, tools, skills and commands come from the Pi runtime whenever possible. ## ✨ What it does - Streams real Pi Agent sessions into a chat view over SSE (`/global/event`), with Markdown, code highlighting (Shiki) and math (KaTeX). - Renders tool calls as cards and shows context usage for the active session. - Switches models, using the normalized capabilities returned by the runtime. - Lists configured MCP servers (transport, command, URL, source) and effective skills grouped by source. - Exposes built-in and dynamic slash commands, plus Git controls in the composer. - Embeds a terminal (xterm.js) and a file explorer next to the chat. - Accepts voice input through an OpenAI-compatible STT endpoint configured in settings. - Ships as a web build or a Tauri 2 app, with UI locales `en`, `pt-BR`, `es`, `ja`, `zh-CN`, `hi`, `bn` and `ar`. ## 🚀 Quickstart | Tool | Minimum version | Needed for | |---|---|---| | Node.js | `>=22` (`.tool-versions`: 22.22.0) | everything | | npm | `>=10` | everything (`package-lock.json` is authoritative) | | Rust | `1.85.0` (`src-tauri/Cargo.toml`) | desktop app and gateway router only | | Docker | Docker Compose | container stack only | | Pi Agent | installed locally | real sessions and models | Without Pi Agent the UI starts in standalone mode and only shows the server connection dialog. ```bash git clone https://git.evandro.dev.br/evandro/PiAgentUI.git cd PiAgentUI npm ci # postinstall runs scripts/copy-material-icons.mjs npm run build # tsc -b && vite build -> dist/ npm run dev # Vite dev server on http://localhost:5173 ``` `npm run dev` is front-end only: it proxies `/api` to `127.0.0.1:4096` with the prefix stripped. For the Pi flow, build first and let the extension serve `dist/`: ```bash npm run build cat ~/.pi/agent/piagentui-port.json # {"port": 58785, "token": "..."} # open http://127.0.0.1:58785 (Pi Agent running this repo as a Pi package, see package.json "pi") ``` Desktop and Android: ```bash npm run tauri dev # desktop window on the Vite dev server npm run tauri build # bundles: nsis, dmg, deb (src-tauri/tauri.conf.json) npm run tauri android dev # see scripts/dev-android.sh ``` ### Container stack Copy `.env.example` to `.env` first. Four compose files exist: | File | Command | What it does | |---|---|---| | `docker-compose.yml` | `docker compose up -d` | Full stack: `gateway` (Caddy + Rust router, `127.0.0.1:6658` and `6659`), `frontend` (Caddy, 3000) and `backend` (`opencode serve`, 4096, 4G memory limit). | | `docker-compose.standalone.yml` | `docker compose -f docker-compose.standalone.yml up -d` | Front end only, for an existing `opencode serve`. Uses `BACKEND_URL` (default `host.docker.internal:4096`) and `PORT` (default `3000`). | | `docker-compose.host.yml` | `docker compose -f docker-compose.yml -f docker-compose.host.yml up -d` | Optional override: `backend` runs privileged with the Docker socket and the host `/` mounted at `/host`. Use only when really needed. | | `docker-compose.build.yml` | `docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build` | Optional override: builds gateway, frontend and backend locally from `docker/`. | The `backend` and `gateway` images come from `ghcr.io/evandrodevbr/opencodeui-{backend,gateway}`. The `frontend` image still points at upstream `ghcr.io/lehhair/opencodeui-frontend`, because `docker-frontend.yml` has failed since 2026-06-01 and no `ghcr.io/evandrodevbr/opencodeui-frontend` was published. ### Environment variables All variables come from `.env.example` and apply to the container stack only (the Pi extension flow needs none). | Variable | Required | Description | |---|---|---| | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `DEEPSEEK_API_KEY`, `GROQ_API_KEY`, `MISTRAL_API_KEY`, `XAI_API_KEY` | At least one | LLM provider keys passed to the backend container. | | `GATEWAY_PORT` | No (`6658`) | Host port of the unified entry point. | | `PREVIEW_PORT` | No (`6659`) | Host port of the dedicated preview entry point. | | `PREVIEW_DOMAIN` | No | Separate domain for previews, to avoid front-end asset path problems; the reverse proxy forwards it to `PREVIEW_PORT`. | | `WORKSPACE` | No (`./workspace`) | Host directory mounted at `/workspace` in the backend. | | `OPENCODE_SERVER_PASSWORD` | Public deployments | Password for the backend and the router. Set it when exposing the stack. | | `OPENCODE_SERVER_USERNAME` | No (`opencode`) | Username paired with the password above. | | `PUBLIC_BASE_URL` | No | Public base URL used by the router built into the gateway. | | `ROUTER_SCAN_INTERVAL` | No (`5`) | Router scan interval. | | `ROUTER_TOKEN_LENGTH` | No (`12`) | Length of the generated route tokens. | | `ROUTER_PORT_RANGE` | No (`3000-9999`) | Port range the router handles. | | `ROUTER_EXCLUDE_PORTS` | No (`4096`) | Ports the router skips. | | `USE_CHINA_MIRROR` | No (`1`) | Backend image build option: use the mirror sources below. | | `APT_MIRROR`, `APT_SECURITY_MIRROR` | No | Debian mirrors for the backend image build. | | `NPM_CONFIG_REGISTRY`, `NODEJS_ORG_MIRROR`, `PIP_INDEX_URL`, `PIP_TRUSTED_HOST` | No | npm, Node.js and pip sources for the backend toolchain. | | `MISE_INSTALL_URL`, `OPENCODE_INSTALL_URL` | No | Installer URLs used when building the backend image. | ## 🧱 Architecture ```mermaid flowchart LR UI["React UI in browser or Tauri webview"] -->|"HTTP api, SSE, WebSocket"| SRV["Pi extension server"] PI["Pi Agent runtime"] -->|"loads extension"| SRV SRV -->|"writes port and token"| DISC["~/.pi/agent/piagentui-port.json"] TAURI["Tauri shell"] -->|"get_pi_agent_connection"| DISC TAURI --> UI ``` - The extension (`extensions/piagentui-server.ts`, Node `http` + `ws`) serves the built UI from `dist/` and injects `window.PI_BOOT_DATA {baseUrl, token}`. - On session start it listens on port `58785` (or the next free one) and publishes the port and a random token in the discovery file. - `GET /global/health` is open; other `/api/*` routes require `Authorization: Bearer `. Access is loopback-only by default, with a LAN toggle at `/api/network/access`. - The extension bridges sessions, models, tools, MCP, skills and commands; the full route table lives in the server file. - The Tauri app reads the same discovery file, so the desktop build connects to the local runtime without manual setup. - In containers, the Rust router (`src-router`, axum) sits behind Caddy as the gateway in front of the frontend and backend services. ## 🗂️ Structure ```text extensions/ Pi extension: HTTP/WebSocket server, settings, git and extension managers (Vitest) src/ React 19 front end: api, components, features, hooks, locales, store src-router/ Rust gateway router (axum) behind Caddy src-tauri/ Tauri 2 desktop and mobile shell, Android project in gen/ docker/ Dockerfiles, Caddyfiles, entrypoints scripts/ icon copy, version bump, release preparation, Android dev helper docs/ design specs and plans (docs/superpowers/) assets/ app icon sources .github/ 6 workflows: build, deploy, release, docker-backend/frontend/gateway ``` ## 🧪 Scripts | Command | What it does | |---|---| | `npm run dev` | Vite dev server (front end only). | | `npm run build` | `tsc -b && vite build`, output in `dist/`. | | `npm run preview` | Serves `dist/` locally for a final check. | | `npm run typecheck` | `tsc -b` (app and extension projects). | | `npm run type-check` | Alias of `typecheck`. | | `npm run typecheck:extensions` | `tsc -p tsconfig.extension.json --noEmit`. | | `npm run lint` | `eslint .` | | `npm run format` | `prettier . --write` | | `npm run format:check` | `prettier . --check` | | `npm run test` | `vitest` in watch mode. | | `npm run test:run` | `vitest run` (needs `dist/`, so build first). | | `npm run validate` | typecheck, extension typecheck, lint, build, tests. The gate CI runs in `build.yml`. | | `npm run check` | format check, lint, build, tests. | | `npm run tauri` | Tauri CLI (`dev`, `build`, `android dev`). | | `npm run icons:tauri` | Regenerates `src-tauri/icons` from `src-tauri/app-icon.manifest.json`. | | `npm run release:prepare` | Runs `scripts/prepare-release.mjs`. | | `npm run postinstall` | Runs `scripts/copy-material-icons.mjs` (automatic after `npm ci`). | Deploy notes: `dist/` is a plain SPA; under a subpath build with `VITE_BASE_PATH=/subpath/ npm run build`. `deploy.yml` publishes to GitHub Pages with `VITE_BASE_PATH=/PiAgentUI/` on pushes to `main`, and `release.yml` attaches Windows, macOS, Linux and Android artifacts on `v*` tags. ## 📚 Documentation | Document | Content | |---|---| | [`docs/superpowers/specs/`](docs/superpowers/specs/) | Design specs: Pi extension migration, sessions, STT and Git controls. | | [`docs/superpowers/plans/`](docs/superpowers/plans/) | Implementation plans and the context, skills and MCP roadmap. | | [`CHANGELOG.md`](CHANGELOG.md) | Release history used by the release workflow. | | [`docker/`](docker/) | Dockerfiles, Caddy configs and entrypoints. | ## 🛣️ Limitations and next steps - Active single-developer project, pre-1.0 (`0.6.10`); some areas are still moving. - OpenCodeUI naming is only partly cleaned: the Rust crate is `opencodeui-router`, images are `opencodeui-*`, `.env.example` comments are in Chinese, and the Docker backend runs `opencode serve`, which belongs to the inherited deployment, not the Pi extension flow. - `docker-frontend.yml` must be fixed before `ghcr.io/evandrodevbr/opencodeui-frontend` exists; compose files pull that image from upstream until then. - No tests for the Tauri shell or the Rust gateway beyond compilation; desktop and Android bundles are only built by the release workflow. - Tests are component- and server-level: no end-to-end browser test and no coverage threshold. `npm run format:check` reported unformatted files at the last audit, so `npm run check` can fail on that step while `npm run validate` passes. - `@mariozechner/pi-coding-agent` is a devDependency for types only, and npm marks that package line as deprecated in favour of `@earendil-works/pi-coding-agent`. - One runtime per window (discovery file or manually configured server); no multi-runtime aggregation. - Voice input needs an OpenAI-compatible STT endpoint and has no automated browser test. - No published npm package and no hosted web demo. ## 🤝 Contributing Open an issue or a PR on the [issue tracker](https://git.evandro.dev.br/evandro/PiAgentUI/issues). Before a PR, this must pass: ```bash npm run validate ``` ## 📄 License GPL-3.0-only, see [`LICENSE`](LICENSE). PiAgentUI is a fork and rework of OpenCodeUI; the original authors are credited in `src-tauri/Cargo.toml`.