Developers
Developer guide
GridHive is one TypeScript code base: a local Fastify server that runs agent CLIs in real terminals, a React board, an Electron wrapper, and a small cloud part for accounts and sharing. Everything is MIT licensed on GitHub.
Prerequisites
| Tool | Version | Needed for |
|---|---|---|
| Node.js | 20 or later (CI and releases use 22) | Everything |
| npm | Comes with Node | Installing and scripts |
| Git | Any recent | Cloning; worktree-per-agent and the git panel |
| An agent CLI | Claude Code, Codex, Gemini CLI, Grok Build or OpenCode | Running real agents (tests use fake CLIs) |
Terminals use node-pty, which ships prebuilt binaries for Windows, macOS and Linux, so no compiler is needed.
Daily workflow
$ git clone https://github.com/customerimpact/gridhive
$ cd gridhive && npm install
$ npm run dev # server + UI with hot reload
| Command | What it does |
|---|---|
npm run dev | Server (tsx watch) and the Vite UI with hot reload |
npm run typecheck | TypeScript, no emit |
npm test | Unit tests (Vitest) |
npm run test:e2e | End-to-end tests in a real browser (Playwright) against fake CLIs |
npm run build then npm start | Production build, the same thing npx gridhive runs |
npm run desktop:dev | Build and open the Electron app |
npm run desktop:dist | Windows installer (desktop:dist:mac for the .dmg) |
GRIDHIVE_HOME and --port.Repository layout
src/
server/ local Fastify server: terminals, hooks, jobs, loops, usage, phone, sharing
agents/ one adapter per CLI (claude, codex, gemini, grok, opencode, custom)
web/ React board (React Flow + xterm.js), the phone page and the share viewer
desktop/ Electron main process: window, tray, notifications, auto-update
shared/ types and logic used on both sides (protocol, recipes, share crypto)
relay/ Cloudflare Worker: end-to-end encrypted relay for sharing and the phone
site/ gridhive.dev: this website and its API (Vercel + Neon)
tests/ e2e specs, fake CLIs, desktop tests
scripts/ icons, screenshots, cache stamps, relay keys
How it works
board (browser or desktop window)
│ WebSocket + REST, per-run token
▼
local server on 127.0.0.1:4317 ──── node-pty ───▶ claude · codex · gemini · grok · opencode
▲ │
└──── hook events (POST /hook/<id>) ◀──────────┘ status: working / needs you / resting
└──── MCP bridge (orchestrator tools) ◀─────────┘ jobs, reports, handoffs, memory
- Real terminals. Each agent is the unmodified CLI in its own PTY, streamed to xterm.js.
- Status from the CLI itself. Claude Code gets per-agent HTTP hooks through a temporary
--settingsfile, so nothing in~/.claudechanges. Other CLIs use their own events or output patterns. - Restore. The board is saved as JSON in
~/.gridhive; on restart each agent resumes its own conversation. - Desktop app. Electron runs the same server in-process and adds a tray, a badge and auto-update.
Orchestrator tools
Claude Code, Codex, Gemini CLI and OpenCode agents get a small MCP server named gridhive, so any of them can coordinate the others:
| Tool | What it does |
|---|---|
list_agents | The other agents on the board, nearest first, with status |
send_job | Hand an agent a task (to, title, message); drawn as a line on the board |
report_job | Report a job done or failed; the result is typed into the sender's terminal |
list_jobs | Jobs sent and received, with status and results |
request_user_action | Put something only a human can do in the Actions inbox |
handoff | Summarize this session and brief another (or a new) agent |
read_memory / append_memory | Shared project and global notes |
Adding an agent
Everything CLI-specific lives behind one interface in src/server/agents/types.ts, so the rest of the app stays agent-agnostic:
interface AgentAdapter {
id: AgentKind;
label: string;
supportsResume: boolean;
supportsHooks: boolean; // false = status from terminal output
supportsMcp: boolean;
detect(settings): Promise<DetectResult>;
buildLaunch(info, mode /* 'new' | 'resume' */, ctx): LaunchSpec;
removeConsoleFiles?(consoleId): void;
statusFromOutput?(chunk): { status: 'needs_you' | 'resting' } | null;
}
Copy an existing adapter (gemini.ts is a small one), register it in agents/index.ts and add its id to src/shared/agents.ts. Adapters never write the user's own config files; per-agent config goes in files the adapter removes with the agent.
Recipes & badges
A recipe is a team setup (roles, agents, models, first prompts) packed into a link. The code sits after #, so it never reaches a server:
https://gridhive.dev/r#<code>
The code is base64url JSON: { v: 1, n: name, d?: description, r: [{ n?: name, ro?: role, p?: prompt, a?: agent, m?: model, w?: 1 }] }, where a is codex, gemini, grok or opencode (missing means Claude Code) and w: 1 gives the agent its own worktree. Accounts and folders are never included.
In the app, open Templates and click the share icon next to a template for its link and badge, or write the badge for your README yourself:
[](https://gridhive.dev/r#<code>)
Opening the link shows every role and prompt first. It opens in the desktop app (gridhive://recipe?d=<code>) or a running npx gridhive; nothing starts until you press Launch.
Security model
- The server listens on
127.0.0.1only and needs a random token (in the URL once, then an HttpOnly cookie). HostandOriginare checked on every request, which blocks other websites and DNS rebinding.- Phone access is a separate, opt-in listener with an allow-listed API and a revocable token per paired phone.
- Shared sessions are end-to-end encrypted (AES-256-GCM); the key is in the link after
#and never reaches gridhive.dev or the relay. Viewers can't type into terminals.
Found a vulnerability? See SECURITY.md.
Contributing
Issues and pull requests are welcome. Read CONTRIBUTING.md first; in short: add tests with new behavior, keep npm run typecheck, npm test and npm run test:e2e green, and never let tests touch real agent config folders.