https://github.com/nabobery/signalpr
Reviewer-first desktop app for AI-assisted GitHub PR review with multi-lane parallel analysis, interactive approval, and auto-fix
https://github.com/nabobery/signalpr
ai code-review desktop-app github react rust sqlite tauri typescript
Last synced: about 21 hours ago
JSON representation
Reviewer-first desktop app for AI-assisted GitHub PR review with multi-lane parallel analysis, interactive approval, and auto-fix
- Host: GitHub
- URL: https://github.com/nabobery/signalpr
- Owner: nabobery
- License: mit
- Created: 2026-03-27T04:40:26.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-20T18:15:10.000Z (about 1 month ago)
- Last Synced: 2026-05-20T23:53:23.576Z (about 1 month ago)
- Topics: ai, code-review, desktop-app, github, react, rust, sqlite, tauri, typescript
- Language: Rust
- Size: 938 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# SignalPR
**A reviewer-first desktop application that transforms noisy AI pull request analysis into compact, human-approved review drafts.**
---
## The Problem
AI-powered code review tools create a new problem instead of solving one: they generate too much noise.
- They repeat the same observation across every file it appears in
- They surface weak, speculative, or irrelevant comments at the same priority as real issues
- They post directly to GitHub without human oversight, polluting PR timelines
- They lack architectural context, so findings are generic and shallow
- They create a second filtering job on top of the review job
The result: "AI-assisted review" ends up slower than doing it yourself.
## The Solution
SignalPR sits between your AI tools and GitHub. It runs specialized analysis agents in parallel, passes raw findings through a multi-stage cleaner pipeline that deduplicates, ranks, and verifies them, and then opens an editable workspace so you can approve what gets posted.
**Nothing is sent to GitHub without your sign-off.**
The core insight is that the problem isn't AI quality — it's the missing layer between raw AI output and the final review. SignalPR is that layer.
### How it works
```
Paste PR URL
│
▼
Fetch diff + metadata (via gh CLI)
│
▼
┌────────────────────────────────┐
│ Parallel agent lanes │
│ ├── Security │
│ ├── Architecture │
│ └── Performance │
└────────────────────────────────┘
│
▼
┌────────────────────────────────┐
│ Cleaner pipeline │
│ 1. Normalize │
│ 2. Deduplicate │
│ 3. Rank by confidence │
│ 4. Verify line anchors │
│ 5. Remap to current diff │
│ 6. Cluster + synthesize │
└────────────────────────────────┘
│
▼
Review workspace (edit, suppress, rewrite)
│
▼
Single batched review posted to GitHub
```
---
## Key Features
**Multi-lane orchestration** — Security, architecture, and performance agents run in parallel with specialized prompts rather than a single generic "review this" instruction.
**Cleaner pipeline** — The core differentiator. Raw findings go through six stages: normalization, deduplication, confidence ranking, diff anchor verification, anchor remapping, and semantic clustering. Fifty raw comments collapse to eight high-signal findings.
**Human-in-the-loop workspace** — A full review workspace with a file tree, diff view, and Signal Board. Edit finding text, change severity, suppress noise, or rewrite comments before anything reaches GitHub.
**Multi-provider support** — Works with Codex (CLI and App Server), GitHub Copilot, OpenCode, Claude, Gemini, Cursor, and PI. Providers stream findings to the UI in real time.
**Local-first and private** — No SignalPR cloud backend. State is stored in local SQLite. Credentials stay in your OS keychain. The app only routes code to the providers you explicitly choose.
**Repo-level config** — Drop a `.signalpr.yml` in any repo to configure which agents run, the deduplication threshold, the maximum surfaced findings, and more.
---
## Tech Stack
| Layer | Technology |
|---|---|
| Desktop shell | Tauri v2 |
| Frontend | React 19 + TypeScript + Vite |
| Routing | React Router 7 |
| Styling | Tailwind CSS v4 + Lucide React |
| Backend | Rust (async with Tokio) |
| IPC | Tauri commands + events |
| Persistence | SQLite (rusqlite) |
| Credentials | OS keychain (keyring) |
| AI providers | Codex, GitHub Copilot, OpenCode, Claude, Gemini, Cursor, PI |
| PR fetching | GitHub CLI (`gh`) |
| Streaming | WebSocket (tokio-tungstenite) + SSE |
| HTTP client | reqwest |
| Testing | Vitest (frontend) + cargo test (backend) |
---
## Project Structure
```
signalpr/
├── src/ # React frontend
│ ├── App.tsx # Route definitions
│ ├── features/
│ │ ├── intake/ # PR URL input and session creation
│ │ ├── onboarding/ # Tool detection and setup guidance
│ │ ├── review/ # Main review workspace
│ │ ├── settings/ # User preferences and agent config
│ │ └── submission/ # Review submission UI
│ ├── lib/
│ │ ├── ipc.ts # Typed Tauri invoke() wrappers
│ │ ├── types.ts # Shared TypeScript interfaces
│ │ └── store.ts # Review workspace state (React context)
│ └── ui/ # Shared UI components
│
└── src-tauri/ # Rust backend
└── src/
├── commands/ # Tauri IPC command handlers
├── orchestration/ # Multi-lane review engine and state machine
│ ├── engine.rs # Coordinates parallel agent execution
│ ├── lane.rs # Per-lane status tracking
│ └── state.rs # ReviewRun state machine
├── cleaner/ # Six-stage finding post-processing
│ ├── dedup.rs
│ ├── normalize.rs
│ ├── rank.rs
│ ├── verify.rs
│ ├── remap.rs
│ └── synthesis.rs
├── providers/ # AI provider adapters
│ ├── traits.rs # ReviewProvider trait
│ ├── codex.rs # Codex one-shot CLI
│ ├── codex_app_server/ # Persistent Codex via JSON-RPC
│ ├── claude.rs # Anthropic API
│ ├── copilot/ # GitHub Copilot v3 JSON-RPC
│ ├── opencode/ # OpenCode HTTP + SSE
│ ├── gemini/ # Gemini CLI via ACP (JSON-RPC over stdio)
│ ├── cursor/ # Cursor CLI via ACP (JSON-RPC over stdio)
│ ├── pi/ # PI Agent SDK via pi --mode rpc (LF-JSONL)
│ └── github.rs # PR metadata fetching
├── storage/ # SQLite data layer
├── config/ # Configuration loading (.signalpr.yml)
├── channels/ # Slack/Discord notification integrations
└── agents/ # Custom agent registry
```
---
## Prerequisites
- **[Rust](https://rustup.rs/)** — stable toolchain
- **[Node.js](https://nodejs.org/)** (18+) and **[pnpm](https://pnpm.io/)**
- **[Tauri prerequisites](https://v2.tauri.app/start/prerequisites/)** for your OS (WebView2 on Windows, Xcode tools on macOS, webkit2gtk on Linux)
- **[GitHub CLI](https://cli.github.com/)** (`gh`) — authenticated with `gh auth login`
- At least one review provider:
- [Codex CLI](https://github.com/openai/codex) or Codex App Server
- [OpenCode](https://opencode.ai/)
- `ANTHROPIC_API_KEY` in your environment (for Claude)
- GitHub Copilot subscription (for Copilot provider)
- [Gemini CLI](https://github.com/google-gemini/gemini-cli) (`npm i -g @google/gemini-cli`) with `GEMINI_API_KEY` set (for Gemini; API key required — OAuth is not supported)
- [Cursor CLI](https://cursor.com/docs/cli) (`curl https://cursor.com/install -fsS | bash`) with `CURSOR_API_KEY` set (for Cursor; generate a key at Cloud Agents → User API Keys in the Cursor Dashboard)
- [PI Agent SDK](https://github.com/mariozechner/pi) (`npm i -g @mariozechner/pi-coding-agent`) for the PI provider
---
## Setup and Development
```bash
# Clone the repo
git clone git@github.com:nabobery/SignalPR.git
cd SignalPR
# Install frontend dependencies
pnpm install
# Start the development build (Vite + Tauri hot reload)
pnpm tauri dev
```
This starts the Vite dev server on `localhost:1420` and opens the Tauri window with hot module replacement on the frontend and auto-rebuild on Rust changes.
---
## Available Scripts
| Command | Description |
|---|---|
| `pnpm tauri dev` | Start the full app in development mode |
| `pnpm tauri build` | Build a production-ready native binary |
| `pnpm test` | Run all tests (Rust + frontend) |
| `pnpm test:frontend` | Run Vitest tests only |
| `pnpm test:rust` | Run Rust tests only |
| `pnpm check` | Full quality check (typecheck + lint + format + tests) |
| `pnpm typecheck` | TypeScript type check |
| `pnpm lint` | Oxlint |
| `pnpm lint:fix` | Oxlint with auto-fix |
| `pnpm lint:rust` | Cargo clippy |
| `pnpm format` | Oxfmt (frontend TS/TSX/CSS) |
---
## Repo Configuration
Create a `.signalpr.yml` at the root of any repository to customize review behavior for that project:
```yaml
version: 1
agents:
security: true
architecture: true
performance: true
nitpick: false # Off by default — too noisy
cleaner:
similarity_threshold: 0.85
drop_nitpicks: true
max_surface_findings: 8 # Cap how many findings reach the workspace
submission:
require_human_approval: true
```
Configuration precedence: **repo config > user config > defaults**
---
## Architecture Notes
**IPC boundary** — The frontend never calls `invoke()` directly. All Tauri commands are wrapped in typed functions in [src/lib/ipc.ts](src/lib/ipc.ts). Backend events (`review_progress`, `codex_lane_delta`, `codex_approval_requested`) are emitted to the frontend for real-time progress updates.
**Provider adapter pattern** — Every review provider implements the `ReviewProvider` trait in [src-tauri/src/providers/traits.rs](src-tauri/src/providers/traits.rs). Adding a new provider means implementing that trait — the orchestration engine does not need to change.
**Review run state machine** — A `ReviewRun` moves through: `Created → RunningAgents → Cleaning → ReadyForReview → Submitting → Submitted` (with `Failed` as a terminal error state from any stage). This makes recovery from restarts deterministic.
**Credential storage** — Secrets are stored in the OS keychain via `keyring`. Nothing sensitive is written to SQLite or log files.
---
## Contributing
1. Fork the repo and create a branch from `main`.
2. Run `pnpm check` before opening a PR — this runs the full quality gate (typecheck, lint, format, tests).
3. Keep frontend and backend concerns cleanly separated: React components talk to the backend exclusively through [src/lib/ipc.ts](src/lib/ipc.ts).
4. New AI providers belong in `src-tauri/src/providers/` and must implement the `ReviewProvider` trait.
5. New cleaner stages belong in `src-tauri/src/cleaner/` and should be independently testable with unit tests.
6. The cleaner pipeline and orchestration engine have in-memory SQLite test fixtures — add tests there rather than mocking at the integration layer.
7. Open an issue first for large changes so the direction can be agreed on before implementation.
---
## License
MIT