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

ToolVersionNeeded for
Node.js20 or later (CI and releases use 22)Everything
npmComes with NodeInstalling and scripts
GitAny recentCloning; worktree-per-agent and the git panel
An agent CLIClaude Code, Codex, Gemini CLI, Grok Build or OpenCodeRunning 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
CommandWhat it does
npm run devServer (tsx watch) and the Vite UI with hot reload
npm run typecheckTypeScript, no emit
npm testUnit tests (Vitest)
npm run test:e2eEnd-to-end tests in a real browser (Playwright) against fake CLIs
npm run build then npm startProduction build, the same thing npx gridhive runs
npm run desktop:devBuild and open the Electron app
npm run desktop:distWindows installer (desktop:dist:mac for the .dmg)
Your real setup stays untouched. Tests run fake agent CLIs on spare ports with a temporary data folder. Point a dev server elsewhere with 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 --settings file, so nothing in ~/.claude changes. 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:

ToolWhat it does
list_agentsThe other agents on the board, nearest first, with status
send_jobHand an agent a task (to, title, message); drawn as a line on the board
report_jobReport a job done or failed; the result is typed into the sender's terminal
list_jobsJobs sent and received, with status and results
request_user_actionPut something only a human can do in the Actions inbox
handoffSummarize this session and brief another (or a new) agent
read_memory / append_memoryShared 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:

[![Run in GridHive](https://gridhive.dev/assets/run-in-gridhive.svg)](https://gridhive.dev/r#<code>)

Run in GridHive badge

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.1 only and needs a random token (in the URL once, then an HttpOnly cookie).
  • Host and Origin are 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.