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
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.