Content
<div align="center">
<a href="https://kroch228.github.io/pigide-landing/">
<picture>
<source srcset=".github/readme/hero.webp" type="image/webp"/>
<img src=".github/readme/hero.gif" alt="PigIDE — Intent Into Motion" width="100%"/>
</picture>
</a>
<br/>
[](https://kroch228.github.io/pigide-landing/)
[](LICENSE)
[](#stack)
[](#prerequisites)
[](CODE_OF_CONDUCT.md)
<br/>
**A desktop IDE that hosts a pool of CLI coding agents as tiled terminal panes.**
<br/>You direct. The swarm builds. Voice in. Code out.
<br/>
**→ <a href="https://kroch228.github.io/pigide-landing/">View the live landing page</a>**
</div>
---
## Quickstart
```bash
git clone https://github.com/<your-fork>/pigide
cd pigide/frontend && pnpm install && cd ../src-tauri
cargo tauri dev
```
Once the window is open:
1. **+** in the Workspaces sidebar — your first workspace.
2. **+ kiro-cli** (or any agent type) inside an empty TilingArea — terminal tile spawns with the agent already running.
3. Talk to the orchestrator on the right pane to dispatch tasks across tiles.
4. `Ctrl+,` opens Settings · `Ctrl+1..9` jumps between workspaces.
For voice: hold the configured PTT hotkey (off by default — bind in `Settings → Voice`) and speak. Partials stream into the focused input within 300 ms.
<div align="center">
<img src=".github/readme/stats.svg" alt="6 agent runtimes · 300 ms voice latency · 120k GPU particles · 100% local" width="100%"/>
</div>
<br/>
<div align="center">
<img src=".github/readme/marquee.svg" alt="Conduct the swarm · You direct · Agents build" width="100%"/>
</div>
<br/>
## Stack
- **Rust core (Tauri 2):** `portable-pty`, `rusqlite`, `reqwest`, `tokio`, `cpal`, `whisper-rs`
- **Frontend (React + TypeScript + Vite):** `allotment`, `@xterm/xterm`, `zustand`
## Prerequisites
- Rust 1.80+ (`rustc 1.95` tested)
- Node 20+ + pnpm 9+ (`node 25`, `pnpm 10` tested)
- Linux: `webkit2gtk-4.1` and PulseAudio/ALSA dev libs
- An OmniRouter instance running locally (defaults to `http://localhost:20128`)
- `~/.local/bin/kiro-cli` and `/usr/bin/claude` for the agent tiles
<br/>
## Build
<details>
<summary><b>Development run</b> — <code>cargo tauri dev</code></summary>
```bash
# Install frontend deps
cd frontend
pnpm install
cd ..
# Run the dev server (Vite) + Tauri window
cd src-tauri
cargo tauri dev
# (or, if @tauri-apps/cli is installed in frontend/, `pnpm tauri dev` from frontend/)
```
</details>
<details>
<summary><b>Release build</b> — <code>./scripts/build.sh</code></summary>
Script builds frontend and Tauri app, automatically selects Whisper backend (GPU/CPU) and puts everything into `./dist/` in the repository root.
```bash
./scripts/build.sh
```
What's included in `dist/`:
```
dist/
├── bin/ # raw executables (pigide, pigide-cli)
├── bundle/ # installers (.deb / .rpm / .AppImage / .dmg / .msi)
└── BUILD_INFO.txt # date, commit, used GPU backend
```
GPU backend is determined automatically (CUDA → ROCm → Vulkan → CPU; on macOS — Metal). Can be forced via `PIGIDE_GPU`:
```bash
PIGIDE_GPU=cuda ./scripts/build.sh # NVIDIA, requires CUDA toolkit
PIGIDE_GPU=hipblas ./scripts/build.sh # AMD ROCm
PIGIDE_GPU=vulkan ./scripts/build.sh # cross-vendor Vulkan
PIGIDE_GPU=metal ./scripts/build.sh # Apple Silicon
PIGIDE_GPU=cpu ./scripts/build.sh # CPU-only
```
At runtime, can force CPU without rebuilding: `PIGIDE_WHISPER_CPU=1`.
Before building, script shows **preflight**: current branch, commit, ahead/behind relative to `origin/main`, and list of uncommitted changes. If working tree is dirty — asks for confirmation (this is insurance against situation when you forgot to commit and then lost edits on checkout). To skip question in CI: `PIGIDE_BUILD_DIRTY=1 ./scripts/build.sh`.
</details>
<details>
<summary><b>First-run notes</b> — where data, logs, and models live</summary>
- Database: `~/.config/pigide/db.sqlite`
- Whisper model: downloaded on first PTT use to `~/.cache/pigide/ggml-small.bin`
- Logs: stderr, set `RUST_LOG=pigide=debug,info`
</details>
<br/>
## Architect model
The Kiro orchestrator runs against a swappable LLM backend. Default is the **Anthropic Messages API** with **Claude Opus 4.5** as primary and **Claude Opus 4** as automatic fallback on `5xx` / `529` / timeout. Set `ANTHROPIC_API_KEY` in the environment, or paste a key into `Right pane → Settings → API key`.
OmniRouter (OpenAI-compatible) remains available — switch via `Right pane → Settings → Provider`.
<br/>
## Watcher (optional)
<details>
<summary>Background supervisor of agent stdout on Gemini Flash-Lite</summary>
Watcher listens to stdout of each spawned agent, classifies chunks via Google AI Studio Generative Language API (by default `gemini-2.5-flash-lite` — Gemma 3 4B IT from the initial AI Studio v1beta brief no longer returns; live testing showed that Gemma 4 31B goes into reasoning-prose instead of strict JSON, and Flash-Lite provides strict-JSON and costs ~10× less) and escalates "questions to human" to Architect's mailbox `role:coordinator`, on thread `watcher:<agent_id>`. Architect's response is automatically injected back into stdin of the original agent — the agent does not hang on interactive prompt while you approach.
### Enable
Build-time option:
```bash
cd src-tauri
cargo build --features watcher
# or for debug-run
GEMINI_API_KEY=AIzaSy... cargo tauri dev --features watcher
```
Without `GEMINI_API_KEY`, Watcher silently disables on startup (one warning line in logs) — the rest of the app works as usual.
### Environment variables
| Variable | Default | Purpose |
|-|-|-|
| `GEMINI_API_KEY` | — (required) | Google AI Studio key. Only goes into `x-goog-api-key` header, not into URL or logs. |
| `PIGIDE_WATCHER_RPM` | `10` | Per-agent rate-limit (requests per minute). Token-bucket: if overflowed, chunk is dropped, not queued. |
| `PIGIDE_WATCHER_MODEL` | `gemini-2.5-flash-lite` | Name of Generative Language API model. Change if your key has access to another Gemma/Gemini-Flash-Lite. |
### MCP tool
When Watcher is active, MCP server registers one new tool:
```json
{ "method": "tools/call", "params": { "name": "watcher_status", "arguments": {} } }
```
Returns `{enabled, rpm, agents: { <agent_id>: {last_classification, calls_this_minute, blocked_until, dropped} }}` — convenient for dashboards and checking that bucket is not stuck.
### Cost
`gemini-2.5-flash-lite` is available in free-tier AI Studio with per-project limit around 30 RPM per key (at the time of writing). Default `PIGIDE_WATCHER_RPM=10` is chosen so that one agent does not eat up the key limit alone. On paid tiers, Flash-Lite is the cheapest Gemini API model, ~$0.075 per 1M input tokens and $0.30 per 1M output tokens (text).
</details>
<br/>
## PigVoice — instant voice-to-text
<details>
<summary>Streaming voice layer · sub-300 ms perceived latency · LocalAgreement-2 merger</summary>
PigVoice is the streaming voice layer baked into PigIDE. Goal: **sub-300 ms perceived latency** from speech to first visible token, with partial hypotheses dropped straight into the focused input.
### How it works
```
mic (cpal) → resample 16k → Silero-style VAD → rolling-window Whisper
→ LocalAgreement-2 merger → voice://partial events
→ on VAD endpoint: clean final → voice://final
```
The on-device engine is `whisper.cpp` (via `whisper-rs`, no new native deps). Partials are stabilised with **LocalAgreement-2**: a token only commits to the visible UI once two successive decoding passes agree on it, so the text never wobbles backwards. See [`PIGVOICE_RESEARCH.md`](./PIGVOICE_RESEARCH.md) and [`PIGVOICE_PLAN.md`](./PIGVOICE_PLAN.md) for the full design.
</details>
### Settings (in `~/.config/pigide/db.sqlite`, table `settings`)
| key | default | meaning |
|-|-|-|
| `voice.partial_enabled` | `true` | turn streaming partials on/off (falls back to batch) |
| `voice.partial_hop_ms` | `250` | re-decode cadence while in a speech segment |
| `voice.endpoint_silence_ms` | `400` | silence required to commit a final segment |
| `voice.engine` | `whisper-streaming` | `whisper-streaming` / `whisper-batch` / `deepgram` (cloud, opt-in) |
| `voice.cloud_api_key` | unset | Deepgram Nova-3 key (kept in user settings, never written to git) |
| `voice.cloud_endpoint` | Deepgram default | overrideable WS endpoint |
| `voice.hotkey_enabled` | `false` | global PTT hotkey (off by default; conflicts with WMs) |
| `voice.record_mode` | `push-to-talk` | or `toggle` |
| `voice.inject_enabled` | `false` | type final transcript into the focused window |
| `whisper.model_id` | `small` | one of `tiny` / `base` / `small` / `medium` / `large` / `distil-large` |
| `whisper.language` | `auto` | Whisper language hint |
The streaming path defaults to `tiny` for first-token speed; pick a larger model from the in-app voice settings panel for better accuracy. If the model isn't downloaded yet, the streaming loop quietly no-ops and the existing batch path triggers a download on `stop`.
### GPU acceleration (optional)
By default PigIDE builds Whisper CPU-only. The release build script (`./scripts/build.sh`) automatically determines GPU; to choose manually, export `PIGIDE_GPU=cuda|hipblas|vulkan|metal|cpu` — see the [Build](#build) section. Whisper context tries GPU and falls back to CPU with a `warn!` log if initialization fails (no toolkit, no device, OOM, etc.). At runtime, force CPU with `PIGIDE_WHISPER_CPU=1`.
System dependencies by backend:
- `gpu-cuda` — CUDA toolkit (cublas, cudart, nvcc). Arch: `sudo pacman -S cuda`. Ubuntu: `sudo apt install nvidia-cuda-toolkit`.
- `gpu-hipblas` — AMD ROCm.
- `gpu-vulkan` — Vulkan SDK.
- `gpu-metal` — Apple Silicon, nothing to install.
Verify the live backend in logs (`RUST_LOG=pigide=info`):
```
whisper: GPU backend initialized (model=small)
```
### Events (Tauri)
| event | payload | when |
|-|-|-|
| `voice://state` | `{ state: "idle" \| "recording" \| "transcribing" }` | start/stop |
| `voice://partial` | `{ stable, unstable, segment_id }` | every `partial_hop_ms` mid-segment |
| `voice://final` | `{ text, segment_id }` | VAD endpoint or user stop |
| `voice://transcript` | `{ text }` | back-compat alias of `final` |
| `voice://engine-error` | `{ engine, error }` | non-fatal engine failure |
| `voice://download` | `{ bytes, total }` | model download progress |
### Tests
```bash
cd src-tauri
# unit tests for the merger, VAD, mode controller, cloud config, etc.
cargo test --lib voice::
# end-to-end streaming integration test (no mic / no model needed):
cargo test --test integration_streaming
# latency benchmark — fails if median first-partial > 600 ms:
cargo test --test bench_latency --release
```
<br/>
## Skills — extensible Architect prompt-modules
<details>
<summary>Auto-discovered YAML modules · hot-reload · per-turn injection</summary>
The Architect's prompt is no longer fixed. **Skills** are small named `.md` modules with a YAML frontmatter that the Architect auto-discovers from `~/.pigide/skills/` and `<workspace>/.pigide/skills/` and selects per turn (by tags / triggers / explicit `@skill:<id>` mention).
```markdown
---
id: builder-brief-writer
name: Builder Brief Writer
description: Writes a self-contained brief for a Builder agent
priority: 60
tags: [dispatch, builder]
triggers: [builder]
---
You are composing a Builder brief.
GOAL: {{goal}}
{{#if files_in_scope}}FILES: {{files_in_scope}}{{/if}}
```
Five built-ins ship by default — including `user-skill-prompt-engineer`, the meta-skill the Architect invokes whenever it's about to dispatch to a sub-agent. The Skills panel (right pane → Skills) lists everything, toggles enable/disable, shows the last turn's selection trace, and lets you stub a new user skill from the UI.
The Architect prompt itself (`src-tauri/src/orchestrator/prompt.rs`, v2 — gold-standard meta-prompting; v1 archived alongside as `prompt.v1.rs`) drives every turn through a deterministic 8-step pipeline: **intent → contract** (role / goal / exit_criteria) → **skill selection** → **memory grounding** → **decomposition** (Plan-and-Solve / Least-to-Most) → **draft** (via `[[user-skill-prompt-engineer]]`) → **self-critique** (Self-Refine + Chain-of-Verification) → **dispatch** (parallel where independent) → **observe + self-improve** (`create_memory` for new patterns). Research citations are at the top of `prompt.rs`.
See the built-in skills in `src-tauri/resources/skills/` for examples.
```bash
# unit tests (parser, router, composer, registry)
cargo test --lib skills::
# integration test (end-to-end compose + hot-reload)
cargo test --test skills_integration
```
</details>
<br/>
## Acknowledgements
PigIDE integrates third-party software whose licenses are reproduced in `LICENSES/` and summarised in [`NOTICE`](./NOTICE):
- **[Ruflo](https://github.com/ruvnet/ruflo)** (MIT, 2024-2026 ruvnet) — used as a supervised Node.js sidecar (`pigide-ruflod`) that powers the orchestrator-ledger layer. PigIDE talks to it over its MCP server (transport=stdio); see `src-tauri/src/ruflo/` for the bridge.
<br/>
<div align="center">
<sub> 2026 PigIDE · Tauri · React · Rust · Three.js · <b>local · forever</b></sub>
<br/>
<sub><a href="https://kroch228.github.io/pigide-landing/">kroch228.github.io/pigide-landing</a></sub>
</div>
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available