Skip to content

Latest commit

Β 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hive

Hive drives CLI coding agents the way a manager drives a team. You describe a change; Hive decides which agent β€” and which model, on which provider β€” is right for it, runs it against a real git working tree, retries when it fails, and shows you what it did: tool calls, thinking, token spend, files touched.

The agents are not built into Hive. They are the CLIs you already have on your PATH β€” Claude Code, opencode, Codex, Gemini CLI, Cursor Agent, aider, Amp, goose, Crush, Copilot CLI, Qwen Code, pi β€” and Hive is the thing that routes work to them, keeps them honest, and gives you one place to watch it happen.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Electron window / browser  Β·  React UI (packages/client)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚  REST + Server-Sent Events
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Express API on :3001  (packages/server)                    β”‚
β”‚                                                             β”‚
β”‚   Orchestrator ── Router ──── a model picks the agent,      β”‚
β”‚        β”‚                      the model and the provider    β”‚
β”‚        β”‚       ── LoopEngine ─ retry until it works         β”‚
β”‚        β”‚       ── Permissions ─ gate destructive work       β”‚
β”‚        β”‚       ── Resources ─── file locks                  β”‚
β”‚        β–Ό                                                    β”‚
β”‚   Harness adapters β†’ spawn a CLI, parse its event stream    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β–Ό
   claude Β· opencode Β· codex Β· gemini Β· cursor-agent Β· aider Β·
   amp Β· goose Β· crush Β· copilot Β· qwen Β· pi   (your repo as cwd)

Why this exists

You already run Claude Code + Codex + opencode + local models. Now manage them like a team instead of eight terminals.

Problem How Hive solves it
Which agent for what? A model reads the task and dispatches it across every installed CLI and provider β€” no keyword table
Keeping agents honest Loop engine retries on real errors, stops on real failures, shows every tool call
Context switching One chat window, persistent sessions per project, activity trail survives page changes
Memory that sticks Second Brain builds soul.md from what it observes β€” your preferences, which harness wins which work
Visibility Office floor (isometric), Kanban board, live logs, git diffs β€” all in one window

What it looks like

The Hive dashboard: who is working, what is uncommitted, which harnesses are online

Demo: 30s capture of fan-out (one message β†’ 3 sub-agents), attachments drag/drop, and Office floor live β€” coming in docs/demo.gif. Tracked in CHANGELOG.md Unreleased.

Quick start

Prerequisites

  • Node.js 22+ and pnpm 9+
  • At least one agent CLI on your PATH. Hive works with one and gets more useful with each one you add β€” hive doctor lists what it can see.
pnpm install
pnpm --filter hive exec npm link   # optional: puts `hive` on your PATH
hive                               # API server + UI + desktop window

Then either use the window Hive opened, or visit http://localhost:3000.

hive doctor checks the whole setup β€” Node version, ports, which agent CLIs it can find β€” and is the first thing to run when something doesn't come up.

The hive command

Command What it starts
hive API server, Vite dev server, and the Electron window, as one process
hive web API server + UI; open http://localhost:3000 yourself
hive server API server only, on :3001
hive stop Frees Hive's ports, whatever is holding them
hive doctor Checks this machine can run all of the above
hive doctor --deep Also runs one real prompt per CLI to prove its event stream still parses

Useful flags: -p/--port (API port), --ui-port, --devtools, --no-window, and for the doctor --deep / --json. hive --help has the full list.

Every child process runs with the repo root as its working directory. That matters: the server resolves hive.config.json against process.cwd(), so starting the pieces by hand from elsewhere loads different configuration. hive guarantees the right cwd; if you start things manually, do it from the repo root.


First run

The first time you open Hive it asks one question: which model should decide routing?

Everything else it works out. It probes all twelve CLIs, switches on the ones that answered, leaves the rest off, and writes a soul.md seeded with what it found β€” the agents available, an opening category β†’ harness table, and the router model you picked.

It asks about the router model because that is the one thing it cannot discover. This model runs on every task, so it is a spending decision, and a tool that makes a spending decision for you silently is a tool you stop trusting. A small fast model is the right answer and is preselected; "choose automatically" is also there, and picks the smallest capable model it can find.

Nothing is locked in. The answer lands in ~/.hive/mem/soul.md, which you can edit by hand:

## Harness preferences

- Router model: claude-code/anthropic/haiku
- test β†’ opencode
- refactor β†’ claude-code
- bugfix β†’ codex
- Prefer local models for anything trivial
- Never use amp for migrations

Adding a project seeds that repository's own mem/soul.md, which overrides the machine-wide one. It starts nearly empty on purpose β€” it is for what is different about this repo, not a copy of your global preferences.

From there the Second Brain takes over: it watches which agent actually finishes which kind of work and proposes new soul.md entries, which you approve or reject on the Memory screen. Setup is the cold start for a loop that then runs itself.

To go through it again: Settings β†’ Harnesses β†’ Re-run setup, or POST /api/setup/reset.


The agents

Hive drives twelve CLIs. Each is probed at startup with --version; the ones that answer are the ones routing can choose from, so installing a new CLI is the whole of adding it to the team.

CLI Binary Where it's the right call Structured events
Claude Code claude Large refactors, unfamiliar codebases, documentation βœ…
opencode opencode Any provider's model β€” the widest catalogue here; tests, CI βœ…
Codex codex Algorithms, tricky logic, debugging an unknown failure βœ…
Gemini CLI gemini Very large context: auditing or summarising a whole repository βœ…
Cursor Agent cursor-agent Changes that must find their own blast radius in a big repo βœ…
pi pi Short scoped edits and quick questions; fast to start βœ…
Qwen Code qwen High-volume mechanical edits where cost per run matters βœ…
aider aider Surgical edits to files you can already name β€”
Amp amp Long autonomous tasks you don't want to babysit β€”
goose goose Jobs needing MCP tooling or machine automation β€”
Crush crush Quick edits and one-shot questions β€”
Copilot CLI copilot GitHub-shaped work: issues, pull requests, Actions β€”

"Structured events" means the CLI emits a JSON event stream Hive parses into typed tool calls, thinking blocks and token counts. The five without one are run through their non-interactive flag and their stdout is surfaced line by line as it arrives β€” less detail, but honest about it, and no token accounting comes back from them.

Each CLI's real strengths and limits are written down in packages/server/src/harnesses/profiles.ts. That file is not documentation about the code β€” it is what the router reads when it decides.

Adding another CLI is an adapter in harnesses/, a profile entry, a probe spec in harnesses/health.ts, and a default block in config.ts. See docs/DEVELOPMENT.md.


Dynamic routing

Routing is what you wrote in soul.md; where you wrote nothing, a model decides. Keyword matching is the last resort, not the first.

A category β†’ harness line in soul.md is obeyed exactly β€” you wrote it down, so nothing else gets a vote. For everything else, Hive builds a dispatch prompt from the live list of installed CLIs, each one's strengths and limits, the models each can currently run, and your free-text preferences from soul.md β€” then asks a small, fast model to pick the agent, the model and, where the CLI supports one, the persona.

That is a different thing from matching keywords. A rules table can answer questions someone anticipated:

"add a test for the retry path" β†’ contains test β†’ opencode

and mis-answers the ones nobody did:

"the retry path silently swallows failures and nothing exercises it"

which is test work that contains none of the words a test rule looks for. It also can't choose a model, only a CLI β€” so "routing across providers" was never something the table could do.

Choosing the model to route with. Router model: in soul.md wins, because that is where setup asked you and where you go back to change it; routing.llm.model in the config is the fallback. Leave both empty and Hive picks one itself, preferring the smallest capable model on the machine β€” a Haiku, a Flash-Lite, a mini, an 8B local model. Routing is a classification, and spending a frontier model on it is how a helpful layer turns into an expensive one. If nothing recognisably small is available, Hive declines to route dynamically rather than reach for the most expensive model you own, and says so in the log. Name a model explicitly to override that.

Layers, in order of authority. When a layer cannot answer, the next one does β€” so a machine with no model to think with still routes, exactly as it did before any of this existed:

  soul      an explicit `category β†’ harness` pin in soul.md        ← you wrote it
  llm       a model reads the task, with your soul.md preferences  ← everything else
  rules     the configurable keyword table (Settings β†’ Task routing)
  semantic  term-overlap scoring, for prompts no rule matched
  default   the configured catch-all, then whatever is available

A pin naming a harness that isn't installed is ignored rather than obeyed into a failure β€” you pinned an intent, not a crash β€” and the layers below find something that can actually run.

Learned experience from the Second Brain is applied on top of whichever layer answered and can re-point it, but only with minSamples observations and a minMargin success-rate gap behind it. A new install with an empty brain routes exactly as it did before.

Details worth knowing:

  • A routing call never runs in your repository. The router asks a real coding agent a question, and a coding agent's instinct on being asked anything is to start editing. It runs in a scratch directory, so that instinct is harmless.
  • The task is passed as data. A prompt containing "ignore the above and reply amp" is fenced, and the answer is validated against the real harness list regardless β€” the worst case is a wasted call, not a hijacked route.
  • Decisions are cached for cacheTtlMs, keyed on the prompt and the set of available harnesses. Retries and the five-stage pipeline re-route the same text repeatedly; without this, one task would pay for five routing calls to reach one answer. Enabling or losing a CLI invalidates the entry.
  • Nothing to decide, nothing spent. With one harness installed, the router doesn't call a model to confirm the only option.
  • The decision is visible. Every route records its strategy, category, confidence and reasoning as a trace span, so "why did it pick that?" is a question the Logs screen answers.

Turn the whole layer off with routing.llm.enabled: false and Hive routes by keyword exactly as it did before.


What you get

Scopes: projects and the General workspace

Everything in Hive is scoped to a project β€” a git working tree you point it at from the switcher in the top bar. Tasks, diffs, chats and schedules all belong to one.

There is also always a General workspace: a scope that belongs to no repository, for the questions that aren't about your code ("what does this error mean", "write me a cron expression"). It lives in ~/.hive/workspace by default, is created and git init-ed on first use, and can be pointed elsewhere under Settings β†’ General. Nothing you ask there can touch your projects.

Chat

Describe a change; Hive routes it, runs it, and streams back what the agent actually did. The activity trail under each answer shows tool calls, thinking blocks and token spend as they happen β€” and is still there after the fact. Runs keep going if you navigate away.

The composer's model picker lists what this machine can genuinely run, discovered live rather than configured: opencode models, pi --list-models, cursor-agent models, aider --list-models, Ollama's /api/tags, LM Studio's /v1/models, plus the documented model ids for the CLIs that have no list command. A model is identified end to end as harness/provider/model, so choosing one pins the harness too β€” and pinning it takes precedence over the router.

The staged loop

By default a task is one harness run, retried on a retryable error. Turn on the staged loop (Settings β†’ Execution) and it becomes five, each with a gate that can send the work back:

plan β†’ implement β†’ test β†’ review β†’ ship

The gates are the point, because a harness that does the wrong thing still exits zero:

  • implement fails if the working tree is unchanged β€” a run that touched nothing did nothing, however confident its summary reads.
  • test runs the project's own test command (detected from package.json, Cargo.toml, go.mod, pyproject.toml, or set explicitly) and sends failures back to implement, bounded by a repair budget so it cannot loop forever.
  • review blocks a diff carrying conflict markers, a stray debugger, a new FIXME, or an it.only. A configured model can add a second opinion; the harness reviews its own diff when none is.

Stages drive the Office floor, so the room a character is standing in is the stage it reached.

Parallel agents

createParallelBranches gives each task its own branch and its own git worktree β€” a real directory sharing the repository's object store β€” so two agents editing the same file are editing two different checkouts. Branches merge back one at a time; the first conflict stops the run, reports the files, and aborts the merge rather than resolving it for you.

Because those worktrees are invisible to each other, agents in a session share a mailbox (/api/messages): one agent leaves a note about what it moved or renamed, and the next agent to start is told once, in its prompt.

Board, workflows, schedules

  • Kanban β€” eight columns across the real life of a task: Backlog, Queued, In progress, In review, Testing, Blocked, Done, Failed. Drag or use each card's column control; columns collapse so all eight fit; WIP limits flag an overloaded column.
  • Workflows β€” a node graph (trigger, agent task, tool, gate, approval, parallel, join, output) with undo/redo, auto-layout and validation.
  • Schedule β€” cron-backed recurring runs, with the history of what actually fired.

Watching and inspecting

  • Office β€” an isometric floor where each agent stands in the zone matching its task's stage. Decorative on purpose, but the positions are real: zone = pipeline phase.
  • Dashboard β€” who's working, what's uncommitted, which harnesses are online.
  • Capacity β€” how many agents run at once is a property of your machine, not a number typed once: leave loop.maxConcurrentAgents at 0 and Hive sizes it from your cores and memory. Runs past the limit queue in arrival order instead of fighting over the machine, and the Office header and the board's "In progress" limit both follow the same number.
  • Changes β€” working-tree and staged diffs, and commit history, per project.
  • Logs β€” a live tail plus per-task trace spans, so a run can be opened from the message that produced it β€” including the routing decision and why it was made.
  • Memory β€” the per-session key/value store agents share, browsable and editable.
  • Permissions β€” approve or deny destructive work. This is a real gate, and it watches what the agent does, not what you asked for: when a run reaches for git reset --hard or rm -rf, the harness process is killed mid-run and the task waits here until someone answers or it times out. Approving re-runs the task with that one command allowed, so the agent can finish. A prompt that merely mentions "reset" is not blocked β€” see permission.gateOn under Configuration.

Credentials: the CLIs bring their own

Hive has no API-key settings, on purpose. Every harness CLI holds its own authentication β€” claude /login, codex login, opencode auth login, gemini and qwen's browser sign-in, cursor-agent login, gh auth login for Copilot β€” and Hive uses whatever that CLI is already signed in with. If a model works in the terminal, it works in Hive.

The only servers configured directly are the local ones that need no key at all β€” Ollama and LM Studio β€” whose base URLs live under localModels.


Configuration

hive.config.json at the repo root is merged over the built-in defaults, and the PORT, HIVE_HOST and HIVE_AUTH_TOKEN environment variables win over both. Everything in it is editable from the Settings screen, which writes the same file β€” so the UI and the file never drift.

{
  "localModels": {
    "ollama": "http://localhost:11434",
    "lmstudio": "http://localhost:1234",
  },
  "harnesses": {
    // One block per CLI. `path` is the binary; set it if yours isn't on PATH
    // under the usual name. `enabled: false` hides a CLI from routing entirely.
    "claude-code": {
      "enabled": true,
      "path": "claude",
      "defaultModel": "…",
      "args": [],
      "concurrency": 2,
    },
  },
  "routing": {
    "default": "opencode",
    "fallback": "claude-code",
    "llm": {
      "enabled": true,
      // "" = pick a small, fast model automatically.
      "model": "",
      // Let the router choose the model, not only the CLI.
      "selectModel": true,
      "timeoutMs": 20000,
      "minConfidence": 0.5,
      "cacheTtlMs": 300000,
    },
    // The fallback cascade, used when the model above declines or is off.
    "rules": [
      {
        "id": "test",
        "pattern": "test|spec|assert",
        "harness": "opencode",
        "enabled": true,
      },
    ],
  },
  "permission": {
    "enabled": true,
    "timeout": 60000,
    "destructiveActions": ["rm", "push --force"],
    // What the gate inspects. "commands" (default) watches the agent's
    // actual shell tool calls and halts the run on a match. "prompt"
    // scans your prompt once, before anything runs. "both" does each.
    "gateOn": "commands",
  },
  "loop": {
    "maxIterations": 10,
    "timeoutMs": 300000,
    "maxConcurrentAgents": 3,
  },
  "server": {
    "port": 3001,
    // Loopback by default: every endpoint here can spawn a CLI agent with
    // shell access to your repo. Binding anything else without an
    // authToken is refused at startup rather than warned about.
    "host": "127.0.0.1",
    "authToken": "",
    // Empty = any localhost origin, which is what Vite and Electron need.
    "allowedOrigins": [],
  },
  "storage": { "cacheDir": "./.hive-cache" },
  "general": { "defaultProjectId": "", "rootDirectory": "" },
  // Written by the first-run setup screen; reset it to be asked again.
  "setup": { "completed": true, "completedAt": 0, "version": 1 },
}

Harnesses start disabled. A fresh config has every CLI enabled: false, and startup switches on the ones it actually finds. A harness that isn't installed is never left enabled β€” that would put it in the routing table and the Settings switches as ready for work, and the only way to discover otherwise would be a task failing at spawn time. Turning one off yourself is respected and survives restarts; uninstalling its CLI turns it off for you.

routing.rules is an ordered table β€” array order is priority, and the rule with taskType: "default" is always the catch-all. It only decides anything when routing.llm doesn't. general.rootDirectory is the General workspace's folder; blank means ~/.hive/workspace.

routing.llmModel from earlier versions is still read and migrated into routing.llm.model on load, so an existing config keeps working.

The server is local-only until you say otherwise. Hive's API spawns agents with shell and git access to your project, so reaching the port is close enough to a shell on the machine. It binds 127.0.0.1, and starting it on any other interface without server.authToken fails with an error instead of quietly listening. To run it somewhere other people can reach:

HIVE_AUTH_TOKEN=$(openssl rand -hex 32) HIVE_HOST=0.0.0.0 hive server

The client sends that token from VITE_HIVE_TOKEN at build time, or localStorage["hive.token"] at runtime.

Where state lives

What Where
Projects, tasks, workflows, schedules, logs, spans storage/cache/hive.db (SQLite, WAL)
Shared memory .hive-cache/<sessionId>/<key>.json
Configuration hive.config.json
General workspace ~/.hive/workspace (configurable)
Chat sessions, UI prefs browser localStorage

Upcoming

Not built yet. Listed here because each is a new subsystem rather than a tweak, and because two of them change properties people reasonably assume a tool like this already has.

  • MCP in both directions. Hive treats every harness as an opaque subprocess, while MCP has become the substrate all of them speak. Outbound: let the orchestrator call MCP servers directly for work too small to justify spawning a whole agent CLI. Inbound: expose Hive itself β€” tasks, board, routing decisions β€” as an MCP server, so it can be driven from Claude Desktop, Cowork or an IDE instead of only its own UI.
  • Sandboxed agent runs. The permission gate detects a destructive command and stops the run; it does not contain anything, and a command matching no pattern can still do real damage. An opt-in container/gVisor sandbox per worktree would bound the blast radius, which is currently "arbitrary shell access to your repo."
  • Budget and spend caps. Token and cost per run are already recorded and then never read back. A per-project and per-day ceiling that refuses to admit a run β€” rather than reporting the damage afterwards β€” is what stops a retry storm turning into a surprise bill.
  • A router scorecard. The Second Brain already tracks success rate per harness per category and only ever feeds it back into routing. Surfacing it β€” which agent wins which category, over how many samples β€” would make the learning half of the system visible instead of implicit.
  • OpenTelemetry GenAI semantic conventions. The trace system speaks its own shape; emitting the GenAI conventions over OTLP would let runs go to Grafana or Honeycomb instead of only the built-in Logs page.

Development

pnpm dev:server     # API server via tsx, no build step
pnpm dev:client     # Vite dev server for the UI
pnpm dev:electron   # UI + Electron window
pnpm build         # tsc --build (shared+server) + client vite build
pnpm typecheck     # tsc --noEmit over the whole repo
pnpm test           # vitest (see vitest.config.mts β€” server tests; client tests via jsdom)
pnpm lint           # eslint
pnpm format         # prettier --write .
pnpm format:check   # CI gate: prettier --check .

pnpm build compiles shared + server via tsc --build and then runs pnpm --filter @hive/client build. To typecheck without emitting, run pnpm typecheck from the root or pnpm --filter @hive/server exec tsc --noEmit.

See docs/DEVELOPMENT.md for the package layout, how to add a harness, a provider or a settings field, and the sharp edges worth knowing about before you hit them. docs/ARCHITECTURE.md covers how a request becomes a running agent (including fan-out), and docs/API.md is the REST + SSE reference.

Ports & API base

  • API defaults to http://localhost:3001, UI to http://localhost:3000.
  • Override with hive --port 3005 --ui-port 3006 (or PORT/HIVE_UI_PORT env). The UI picks up the API port via VITE_API_BASE β€” bin/hive.js sets it for both Vite dev (VITE_API_BASE) and Electron (HIVE_API_BASE/HIVE_UI_URL). If you start server/client by hand, set VITE_API_BASE=http://localhost:<apiPort>.
  • hive doctor reports both ports and whether a Hive server is actually listening vs just β€œport in use”.

Fan-out, attachments, and vision

Fan-out. A single chat message can split into sub-agents (loop.fanout.enabled, default true, config.ts fanout/maxSubtasks=4). The planner (packages/server/src/fanout/planner.ts) declines by default β€” short prompts (<80 chars) or single tasks run as one agent. When it accepts, each subtask gets its own branch + worktree, boards as a sub-card (parent_id), runs under ConcurrencyGate, then branches are committed and merged into the current branch (loop.fanout.merge). Explicit β€œuse subagents / in parallel” lowers the bar but never forces a split; sub-agents are never re-planned (no recursion). Parent task holds no concurrency slot (avoids deadlock at maxConcurrentAgents:1).

Attachments. Drop images/files in the composer (ChatPage.tsx useAttachments.ts). Files are stored under OS temp, not the working tree (so git diff isn’t polluted), paths are absolute (sub-agents have different worktrees). Per-harness translation: opencode --file, codex --image, others via prompt-named paths, ollamaDirect/lmstudioDirect inline text / images / image_url. Served at GET /api/attachments/:id with Content-Disposition: attachment + nosniff.

Vision fallback. Blind models (e.g. qwen2.5-coder) get image descriptions from a vision model (vision.model in config, or auto-picked). Capability comes from Ollama (/api/tags capabilities) and LM Studio /api/v0/models (type: vlm), joined with opencode models catalog; null means β€œassume can see”. Refusals (β€œdoes not support image input”) are detected (refusal.ts) and not forwarded as facts.

Repository layout

bin/hive.js                          the `hive` command
packages/shared                      types shared across packages (no runtime code)
packages/server                      Express API, orchestrator, SQLite
packages/server/src/router.ts        the routing cascade, soul.md first
packages/server/src/setup.ts         first-run: probe, seed soul.md, reconcile harnesses
packages/server/src/secondBrain/starterSoul.ts   writes and reads soul.md's routing section
packages/server/src/fanout/          planner + summary for sub-agent fan-out
packages/server/src/visionBridge.ts  vision fallback + refusal detection
packages/server/src/harnesses/       one adapter per CLI (+ winShim.ts for .cmd shims)
packages/server/src/harnesses/profiles.ts   what each CLI is for β€” read by the router
packages/server/src/harnesses/eventStream.ts   each CLI's output format, pinned by tests
packages/client                      React UI (Vite) + the Electron shell
docs/                                architecture, development, API, design system
docs/examples/                       ready-to-import workflow recipes
hive.config.json                     configuration, read and written by the app

Troubleshooting

Symptom Cause and fix
Everything routes to one harness Only one CLI is installed, or the rest are enabled: false. hive doctor lists what Hive can see.
A category always goes to the same agent soul.md pins it. Delete that category β†’ harness line to hand it back to the router's judgement.
The setup dialog never appeared setup.completed is already true. Settings β†’ Harnesses β†’ Re-run setup, or POST /api/setup/reset.
A harness you installed stays switched off It was off when setup ran, or you declined it. Turn it on in Settings β†’ Harnesses β€” restarts won't override your choice.
Routing ignores the model you expect Something upstream pinned it: a harness/provider/model chosen in the composer wins over the router, by design.
Routing seems to fall back to keywords No small model was available to route with. Name one in routing.llm.model β€” the log says so at startup.
A task hangs and then fails Its prompt matched permission.destructiveActions. Answer it on the Permissions screen; unanswered, it times out.
The model picker is empty No agent CLI is on PATH and Ollama/LM Studio aren't running. hive doctor says which.
The activity trail is plain text Expected for aider, Amp, goose, Crush and Copilot CLI β€” they emit no structured stream. See the agents table.
The activity trail is empty for a harness That CLI changed its output format. hive doctor --deep runs one real prompt through each CLI and says which stopped parsing.
"not a git repository" The scope's folder isn't a repo. Changed-file detection needs one β€” that's why the General workspace git inits itself.
Ports already in use hive stop, or start with -p / --ui-port.
Settings look stale after editing the file The config is a cached singleton. Restart the server, or edit through the Settings screen, which updates it in place.

License

MIT License

About

Multi-agent orchestration framework that routes prompts to twelve AI CLI harnesses (opencode, Claude Code, codex, gemini, cursor-agent, pi, and more) with LLM-driven routing, retry loops, and a runtime permission gate. TypeScript/Express REST API + Vite/React 19 client (Tailwind 4, Pixi.js) in Electron.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages