README.md
Birdbrain
Capture the web as evidence. Local-first, cryptographically verifiable, zero cloud.
Explore the docs »
Report Bug
·
Request Feature
Table of Contents
About The Project
You're doing web research that matters — documenting extremist content, tracking fraud networks, investigating a story. You need to prove, later, that a page said what it said when you found it. Screenshots lie. PDFs strip context. Browser history evaporates.
Birdbrain is a local-first desktop app for investigators who need cryptographically verifiable web captures. Not screenshots, not PDFs — the actual live DOM frozen to a self-contained file, SHA-256 hashed the moment it hits disk. Built for OSINT researchers, journalists, and fraud investigators who can't afford to lose chain of custody.
Everything lives on your machine. No cloud, no accounts, no one else's retention policy. Think of it as a local-first, open source alternative to commercial tools like Hunchly.
Key features:
- SHA-256 integrity — every capture is hashed at ingestion; re-verify at any time to prove nothing changed
- Freeze-dry serialization — pages become self-contained HTML with CSS, fonts, and images inlined as data URIs; they open offline, forever
- Cases — organize captures into investigations with metadata, selectors, and notes
- Selectors — define regex, glob, or literal string patterns; the extension highlights matches on live pages and can auto-capture when a match is found
- Tags & bulk operations — keyboard-driven tagging across captures
- Full-text search — SQLite FTS5 across all captured content
- HTML/PDF export — generate audit-trail reports with investigator name, timestamps, and per-capture hash verification
- Health dashboard — live ring-buffered capture feed with timings and error categorization
Early alpha — v0.1.0. Core pipeline, cases, tags, selectors, notes, search, and export are all working. See the Roadmap for what's next.
Built With
| Layer | Technology |
|---|---|
| Desktop shell | Electron 35 + electron-vite + electron-builder |
| UI | React 19, Tailwind CSS v4, Zustand, TanStack Router, TanStack Query |
| Capture server | Hono 4 (HTTP, runs in Electron main process) |
| Database | better-sqlite3 — synchronous, WAL mode, FTS5 |
| Page serialization | freeze-dry |
| Language | TypeScript (strict) |
| Testing | Vitest (unit), Playwright (E2E against real Electron) |
| Package manager | pnpm |
Getting Started
Prerequisites
- Node.js 20 or later
- pnpm 9 or later (
npm install -g pnpm) - Google Chrome (for the extension)
Installation
| 1 | # Clone the repo |
| 2 | git clone https://github.com/thebristolsound/birdbrain.git |
| 3 | cd birdbrain |
| 4 | |
| 5 | # Install dependencies (also rebuilds native modules for your Electron version) |
| 6 | pnpm install |
| 7 | |
| 8 | # Start the desktop app in dev mode with hot reload |
| 9 | pnpm dev |
Other useful commands:
| 1 | pnpm build # Production build |
| 2 | pnpm package # Package platform installers (NSIS / DMG / AppImage) |
| 3 | pnpm test # Vitest unit tests |
| 4 | pnpm test:e2e # Playwright E2E against a built app |
| 5 | pnpm test:e2e:debug # Playwright with inspector |
| 6 | pnpm lint # ESLint |
| 7 | pnpm format # Prettier |
| 8 | pnpm rebuild:electron # Rebuild native deps after a Node version upgrade |
Loading the Chrome Extension
| 1 | # Build the extension once |
| 2 | pnpm build:extension |
| 3 | |
| 4 | # Or keep it rebuilding automatically during development |
| 5 | pnpm dev:extension |
Then load it into Chrome:
- Open
chrome://extensions - Enable Developer mode (toggle in the top-right corner)
- Click Load unpacked
- Select the
extension/distdirectory inside the cloned repo - The Birdbrain icon will appear in your toolbar
The extension talks to the desktop app at http://localhost:19845. Start the desktop app first — the extension popup shows connection status so you can confirm the link is live.
Note: Rebuild the extension (
pnpm build:extension) after any changes toextension/src/. Thepnpm dev:extensionwatch mode handles this automatically.
Usage
How the pipeline works
| 1 | sequenceDiagram |
| 2 | participant Ext as Chrome Extension |
| 3 | participant Hono as Hono Server<br/>(localhost:19845) |
| 4 | participant Hash as SHA-256 Hash |
| 5 | participant Disk as Disk (flat files) |
| 6 | participant DB as SQLite |
| 7 | participant UI as Renderer (React) |
| 8 | |
| 9 | Ext->>Hono: POST /api/captures<br/>{ source: 'manual' | 'auto' | 'selector' } |
| 10 | Hono->>Hono: Validate + dual-layer URL filter |
| 11 | Hono->>Hash: Hash freeze-dried HTML |
| 12 | Hash->>Disk: Write content files |
| 13 | Hash->>DB: INSERT capture row + hash |
| 14 | DB-->>Hono: Row ID |
| 15 | Hono->>Hono: Post-capture selector matching |
| 16 | Hono-->>UI: IPC event → health dashboard update |
| 17 | UI-->>UI: Re-render capture list |
Click the extension icon to manually capture the current page, or set up Selectors in a case to auto-capture any page whose URL or content matches your patterns. Every capture lands in the desktop app, hashed and stored, ready to add to a case, tag, and annotate.
For a technical deep-dive into the capture pipeline, error handling, selector matching, and hash verification, see docs/capture-pipeline.md.
Project structure
Expand directory tree
| 1 | birdbrain/ |
| 2 | ├── src/ |
| 3 | │ ├── main/ # Electron main process |
| 4 | │ │ ├── services/ |
| 5 | │ │ │ ├── captureServer.ts # Hono HTTP server (port 19845) |
| 6 | │ │ │ ├── database.ts # SQLite + schema migrations |
| 7 | │ │ │ ├── storage.ts # File I/O for capture content |
| 8 | │ │ │ ├── export.ts # HTML/PDF report generation |
| 9 | │ │ │ ├── hash.ts # SHA-256 integrity |
| 10 | │ │ │ └── settings.ts # Persistent user settings |
| 11 | │ │ └── ipcHandlers.ts # All IPC handler registrations |
| 12 | │ ├── preload/ # contextBridge IPC bridge |
| 13 | │ ├── renderer/ # React UI |
| 14 | │ │ ├── stores/ # Zustand app store |
| 15 | │ │ ├── hooks/ # useCases, useCaptures, useTags, useSearch, … |
| 16 | │ │ └── components/ # Feature-organized UI components |
| 17 | │ └── shared/ |
| 18 | │ ├── types.ts # Case, Capture, Tag, Selector, … |
| 19 | │ └── ipc.ts # Typed IPC channel definitions |
| 20 | ├── extension/ |
| 21 | │ └── src/ |
| 22 | │ ├── background.ts # Service worker |
| 23 | │ ├── content.ts # freeze-dry, selector matching, Shadow-DOM toasts |
| 24 | │ └── popup/ # Extension popup UI |
| 25 | ├── e2e/ # Playwright E2E tests |
| 26 | ├── tests/ # Vitest unit tests |
| 27 | └── docs/ # Technical documentation |
Roadmap
v0.1.0 — working now:
- Full capture pipeline (manual, auto, selector-triggered)
- Cases, tags, notes, bulk operations
- Selectors (regex, glob, literal) with live page highlighting
- SHA-256 integrity and re-verification
- Full-text search (SQLite FTS5)
- HTML and PDF export with audit trail
- Health dashboard with real-time capture feed
Coming next:
- UI design refresh
- AI features — entity extraction, relationship mapping, pattern detection via OpenRouter BYOK (removed in a recent refactor; being redesigned for the next iteration)
- Hunchly import
- Additional export formats
The project is actively developed. Expect breaking changes before 1.0.
See open issues for the full list of proposed features and known bugs.
Contributing
Standard GitHub flow: fork the repo, create a branch, open a PR against master.
- Fork the project
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
Code style is enforced via ESLint + Prettier:
| Rule | Value |
|---|---|
| Semicolons | None |
| Quotes | Single |
| Trailing commas | None |
| Print width | 100 characters |
| Indent | 2 spaces |
| TypeScript | Strict mode |
Tests are required for non-trivial changes. Run pnpm test for unit tests and pnpm test:e2e for end-to-end. Both must pass before a PR will be reviewed.
License
Distributed under the MIT License. See LICENSE for more information.
Contact
Matt Donovan — @thebristolsound
Project link: https://github.com/thebristolsound/birdbrain
Acknowledgments
- freeze-dry — the page serialization library that makes offline-complete captures possible
- better-sqlite3 — synchronous SQLite bindings that keep the main process simple
- Hono — the lightweight server that receives captures from the extension
- electron-vite — fast Vite-based build tooling for Electron
- Best-README-Template — README structure