From 8ce05620e0efe0bb4b21baabfb4c6d8f270836dd Mon Sep 17 00:00:00 2001
From: Evandro Fonseca Junior <1+evandro@noreply.git.evandro.dev.br>
Date: Sat, 24 Oct 2026 04:12:59 +0000
Subject: [PATCH] docs(readme): padroniza README (hero, badges, quickstart,
arquitetura)
---
README.md | 315 ++++++++++++++++++++++++++----------------------------
1 file changed, 150 insertions(+), 165 deletions(-)
diff --git a/README.md b/README.md
index b839491..c415de9 100644
--- a/README.md
+++ b/README.md
@@ -1,213 +1,198 @@
-# PiAgentUI
+
-**Desktop and web workspace for AI coding agents: real Pi Agent sessions, streaming chat, MCP and skills panels, terminal, file explorer and a Tauri desktop app.**
+

-
-
-
-
-
-
-[](https://github.com/evandrodevbr/PiAgentUI/actions/workflows/build.yml)
+
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
+
+
+
+
**English (US)** | [Português (BR)](./README.pt-BR.md) | [Español](./README.es.md) | [日本語](./README.ja.md)
-## About
+
-PiAgentUI is a chat and workspace front end for the Pi Agent runtime. Instead of a bare terminal, it gives you sessions, model switching, tool calls rendered as cards, MCP server metadata, skills grouped by source, slash commands, Git controls, a terminal, and a file explorer in one window, as a web app or as a Tauri desktop app.
+
-The project is Pi-first: sessions, models, context usage, tool calls, skills, MCP configuration and slash commands come from the Pi runtime whenever possible. The UI caches and enriches that data for presentation but does not invent agent state. It is a rename and rework of the OpenCodeUI base, and part of that inheritance is still visible (see [Current state and limitations](#current-state-and-limitations)).
+## 📌 The problem
-## How it works
+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.
-```text
- browser window / Tauri webview
- |
- | HTTP /api/* + SSE /global/event + WebSocket
- v
- Pi extension server (extensions/piagentui-server.ts, Node http + ws)
- |-- serves the built UI from dist/ and injects window.PI_BOOT_DATA {baseUrl, token}
- |-- writes connection info to ~/.pi/agent/piagentui-port.json {port, token}
- |-- enforces bearer-token auth on /api/* and loopback-only access by default
- |-- bridges sessions, models, tools, MCP, skills and commands
- ^
- | loaded by the runtime
- Pi Agent process
-```
+## ✨ What it does
-- On session start the extension listens on port `58785` (or the next free port) and publishes the selected port plus a random token in the discovery file.
-- `GET /global/health` is open; every other `/api/*` route requires `Authorization: Bearer `.
-- The Tauri app reads the same discovery file through the `get_pi_agent_connection` Rust command, so the desktop build connects to the local runtime without manual configuration.
-- `npm run dev` (Vite) is a front-end-only development server; it proxies `/api` to `127.0.0.1:4096` with the `/api` prefix stripped, so point it at a compatible server or use the extension-served build for the Pi flow.
+- 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`.
-## Stack
+## 🚀 Quickstart
-| Area | Choice |
-|---|---|
-| UI | React 19, TypeScript 5.9 |
-| Build | Vite 8 (rolldown), `tsc -b` as the type gate |
-| Styling | Tailwind CSS 4 plus project design tokens |
-| Desktop / mobile | Tauri 2 (Rust 1.85+), Android targets generated in `src-tauri/gen` |
-| Markdown and code | Streamdown, Shiki, KaTeX |
-| Terminal | xterm.js |
-| i18n | i18next, locales `en`, `pt-BR`, `es`, `ja`, `zh-CN`, `hi`, `bn`, `ar` |
-| Tests | Vitest 4, Testing Library, jsdom |
-| Local backend | Pi extension: Node HTTP server plus `ws` (SSE and WebSocket) |
-| Gateway (containers) | Rust router (`src-router`, axum) in front of Caddy |
-| Packages | npm with `package-lock.json` |
+| 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 |
-## Requirements
-
-- Node.js `>=22` (CI runs Node 22; verified locally on Node 24.20.0)
-- npm `>=10` (the repository is npm-based; `package-lock.json` is authoritative)
-- Rust `1.85+` only if you build the desktop app or the gateway
-- Docker only for the container stack in `docker/`
-- Pi Agent installed locally to have real sessions and models; without it the UI starts in standalone mode and only shows the server connection dialog
-
-## Quick start
+Without Pi Agent the UI starts in standalone mode and only shows the server connection dialog.
```bash
-git clone https://github.com/evandrodevbr/PiAgentUI.git
+git clone https://git.evandro.dev.br/evandro/PiAgentUI.git
cd PiAgentUI
-npm ci # 615 packages, runs scripts/copy-material-icons.mjs
+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
```
-Web UI served by the Pi extension (this is the path that talks to a real Pi runtime):
+`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 # the extension serves dist/
-# with Pi Agent running this repository as a Pi package (see package.json -> "pi")
-cat ~/.pi/agent/piagentui-port.json # {"port": 58785, "token": "..."}
-# open http://127.0.0.1:58785
+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 app:
+Desktop and Android:
```bash
-npm run tauri dev # development window, uses the Vite dev server
-npm run tauri build # bundles per src-tauri/tauri.conf.json (deb on Linux, dmg, nsis)
+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
```
-Android (see `scripts/dev-android.sh` and the Android job in the release workflow):
+### Container stack
-```bash
-npm run tauri android dev
+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
```
-## Usage
+- 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.
-Local endpoints exposed by the extension server. All of them, except `/global/health` and the SSE route, require the bearer token from the discovery file.
-
-| Endpoint | Purpose |
-|---|---|
-| `GET /global/health` | Liveness probe, returns `{"status":"ok","pi":"ready"}` |
-| `GET /global/event` | SSE event stream (sessions, message parts, status) |
-| `GET /api/models` | Model list with normalized capabilities |
-| `GET /api/sessions` | Session list |
-| `POST /api/sessions` | Create a session |
-| `POST /api/sessions/abort` | Abort the running turn |
-| `GET /api/sessions/:id/messages` | Session history normalized for rendering |
-| `GET /api/sessions/:id/context` | Context usage of the active session |
-| `POST /api/messages/send` | Send a user message to a session |
-| `GET /api/skills` | Effective skills grouped by source |
-| `GET /api/mcp/status` | Configured MCP servers (transport, command, URL, source) |
-| `GET /api/commands/list` | Built-in and dynamic slash commands |
-| `GET /api/agents`, `GET /api/files/list`, `GET /api/permissions/list`, `GET /api/questions/list` | Runtime inventory for the panels |
-| `GET /api/vcs/status`, `/info`, `/branches` | Git state used by the composer controls |
-| `GET /api/extensions/list` | Extension catalog for the extensions panel |
-| `GET /api/settings/stt`, `/api/settings/tts` | Voice settings (STT/TTS) |
-| `GET /api/network/access`, `POST /api/network/access` | LAN access toggle (loopback-only by default) |
-
-The full route table, including Git and extension mutations, lives in [`extensions/piagentui-server.ts`](extensions/piagentui-server.ts). Ports and paths can change; the discovery file is the source of truth for the port and token.
-
-Auditing the agent from a shell works too, for example:
-
-```bash
-TOKEN=$(node -e "console.log(require(process.env.HOME+'/.pi/agent/piagentui-port.json').token)")
-curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:58785/api/models | head -c 300
-```
-
-## Production and deploy
-
-```bash
-npm run build # tsc -b && vite build; output in dist/ (about 14 MB, static)
-npm run preview # serves dist/ locally for a final check
-```
-
-- Static hosting: `dist/` is a plain SPA. If it is mounted under a subpath, build with `VITE_BASE_PATH=/subpath/ npm run build`.
-- Container (front end plus Caddy): `docker/Dockerfile.frontend` builds the UI on Node 22 and serves it from Caddy on port 3000.
-- Full container stack: `docker-compose.yml` runs `gateway` (Caddy plus the Rust router on 6658/6659), `frontend` and `backend`. Copy `.env.example` to `.env` first. Images: `backend` and `gateway` come from `ghcr.io/evandrodevbr/opencodeui-{backend,gateway}` (published by the `docker-backend.yml` and `docker-gateway.yml` workflows); the `frontend` image still points at the upstream `ghcr.io/lehhair/opencodeui-frontend` because `docker-frontend.yml` has been failing since 2026-06-01 and no `ghcr.io/evandrodevbr/opencodeui-frontend` was ever published. To build all three locally use `docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build`.
-- GitHub Pages: `.github/workflows/deploy.yml` builds `dist/` with `VITE_BASE_PATH=/PiAgentUI/` and publishes it on every push to `main` (enable Pages with source "GitHub Actions" the first time).
-- Desktop and mobile releases: `.github/workflows/release.yml` runs on `v*` tags and attaches Windows, macOS, Linux and Android artifacts to the GitHub release.
-
-## Project structure
+## 🗂️ Structure
```text
-extensions/ Pi extension: HTTP/WebSocket server, settings store, git and
- extension managers, all with Vitest tests
-src/ React front end (Vite entry in index.html)
-├── api/ HTTP/SSE clients and the request pipeline
-├── components/ shared UI pieces (code blocks, diffs, command palette)
-├── features/ chat, input, messages, tools, sessions, settings, slash commands
-├── hooks/ session, events, transcription, permissions
-├── locales/ 8 translated bundles
-├── store/ Zustand-style stores (sessions, messages, layout, theme)
-└── constants/ API base URL, storage keys, UI metrics
-src-router/ Rust gateway router (axum) behind Caddy
-src-tauri/ Tauri 2 desktop and mobile shell (Rust), Android project in gen/
-docker/ Dockerfiles, Caddy configs, entrypoints
-scripts/ icon copy, version bump, release preparation, Android dev helper
-docs/superpowers/ design specs and plans written during the migration
+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
```
-## Verification
+## 🧪 Scripts
-Everything below was executed on a clean clone in this repository state:
-
-| Command | Result |
+| Command | What it does |
|---|---|
-| `npm ci` | 615 packages installed, postinstall copies 266 material icons |
-| `npm run typecheck` | exit 0 (`tsc -b`, app + extension projects) |
-| `npm run typecheck:extensions` | exit 0 |
-| `npm run lint` | exit 0 (0 errors, 109 warnings) |
-| `npm run build` | exit 0, `dist/` about 14 MB |
-| `npm run test:run` | 89 files, 319 tests, all passing |
-| `npm run validate` | exit 0 (the same gate CI runs in `build.yml`) |
-| `cargo check` in `src-router/` | exit 0 |
-| `cargo check --manifest-path src-tauri/Cargo.toml` | exit 0 (1 warning) |
-| extension server over HTTP | `/global/health` 200, `/` 200 with `PI_BOOT_DATA`, `/api/models` 200 with token and 401 without, `/api/sessions`, `/api/sessions/:id/messages`, `/api/sessions/:id/context`, `/api/skills`, `/api/mcp/status`, `/api/commands/list`, `/api/network/access` all 200, `/global/event` 200 `text/event-stream` |
+| `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`). |
-Two things to know when running the suite: `npm run test:run` needs `dist/` to exist, because the extension server test fetches the served `index.html`, so `npm run build` must run first (that is the order in `npm run validate`); and `npm run format:check` currently reports 67 files that are not Prettier-formatted, so `npm run check` fails on that step even though the CI gate passes.
+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.
-## Current state and limitations
-
-- Active single-developer project, pre-1.0 (`0.6.10`). The chat, sessions, MCP, skills and command panels work against a real Pi runtime; some areas are still moving.
-- Naming inheritance from the OpenCodeUI base is only partially cleaned: the Rust crate is `opencodeui-router`, container images are `opencodeui-*`, `.env.example` comments are in Chinese, and the Docker stack runs an `opencode serve` backend that belongs to the inherited deployment, not to the Pi extension flow.
-- There is no test for the Tauri shell or the Rust gateway beyond compilation; the Android and desktop bundles are only built by the release workflow.
-- The suite is component- and server-level; there is no end-to-end browser test and no coverage threshold.
-- `@mariozechner/pi-coding-agent` is a devDependency for types only (the runtime provides the real extension API), and npm marks that package line as deprecated in favour of `@earendil-works/pi-coding-agent`.
-- The front end talks to one runtime per window: the discovery file or a manually configured server. There is no multi-runtime aggregation.
-- Voice input exists in the UI (`src/hooks/useVoiceTranscription.ts`) and requires an OpenAI-compatible STT endpoint configured in settings; it is not covered by an automated browser test.
-- No published npm package and no hosted web demo; both README and code assume a local runtime.
-- `docker-frontend.yml` last ran on 2026-06-01 and failed at the build step, so `ghcr.io/evandrodevbr/opencodeui-frontend` was never published (verified against GHCR with the owner credentials); the compose files pull that one image from upstream until the workflow is fixed.
-
-## Documentation
+## 📚 Documentation
| Document | Content |
|---|---|
-| [`docs/superpowers/specs/`](docs/superpowers/specs/) | Design specs for the Pi extension migration, sessions, STT and Git controls |
-| [`docs/superpowers/plans/`](docs/superpowers/plans/) | Implementation plans and the roadmap for context, skills and MCP |
-| [`CHANGELOG.md`](CHANGELOG.md) | Release history used by the release workflow |
-| [`docker/`](docker/) | Dockerfiles, Caddy configs and entrypoints for the container stack |
+| [`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. |
-## License
+## 🛣️ Limitations and next steps
-GPL-3.0-only, as declared in `package.json` and [`LICENSE`](LICENSE). PiAgentUI is a fork and rework of OpenCodeUI; the original authors are credited in `src-tauri/Cargo.toml`.
+- 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.
-## Review checks (2026-09-30)
+## 🤝 Contributing
-Browser downloads include exactly the requested byte view, without adjacent bytes from its backing buffer. Session statistics skip the full message-text scan when real token usage is available. LAN discovery is best effort: restricted network-interface enumeration keeps the local API usable. Failed requests close partial responses without attempting to send headers twice.
+Open an issue or a PR on the [issue tracker](https://git.evandro.dev.br/evandro/PiAgentUI/issues). Before a PR, this must pass:
-Run `npm run validate` for application/extension type checks, lint, build and tests. Focused checks: `npm run test:run -- src/utils/downloadUtils.test.ts src/hooks/useSessionStats.test.tsx extensions/piagentui-server-core.test.ts`. Dependencies, native desktop/mobile builds and live agent flows require their own checks; an application unit-test pass does not replace those validations.
+```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`.