How the Hive and Event Plane Enable Multi-Agent Coordination in Munder Difflin
Munder Difflin splits autonomous Claude agent runtime state into two orthogonal layers: the Hive (on-disk Git persistence) and the Event Plane (real-time hook-driven IPC), enabling auditable, reactive multi-agent workflows.
The hive/event plane architecture in Munder Difflin solves a critical challenge in multi-agent systems: how to give autonomous Claude agents both durable, version-controlled memory and real-time reactive behavior. This design separates persistence from communication, letting agents remember indefinitely, coordinate asynchronously, and respond to live events without losing state.
The Two-Layer Architecture
| Layer | Responsibility | Key Mechanism |
|---|---|---|
| Hive | Durable, auditable state | Git-tracked folder with atomic file writes |
| Event Plane | Real-time event streaming | Claude Code hooks over Unix-domain socket |
These layers operate independently but coordinate through the Electron main process, which is the sole Git committer and the consumer of all IPC events.
Understanding the Hive: On-Disk Persistence
The Hive lives at <harnessHome>/hive/ as a regular Git repository. Only the Electron main process commits, enforcing a strict single-writer policy that prevents merge conflicts and index lock contention.
Directory Layout
hive/
PROTOCOL.md # Agent contract: how to remember and message
registry.json # Roster of all agents with capabilities
board.md # Shared blackboard (god agent only)
tasks.json # Task ledger with assignee and status
log.jsonl # Append-only global event feed
agents/<agentId>/
identity.md # Static agent description
memory.md # Long-term per-agent memory
inbox/ # Incoming messages
inbox/.done/ # Processed messages (audit trail)
outbox/ # Outgoing messages (router drains)
cursor.json # Last processed message ID
Core Design Rules
- One-writer-per-file: Each agent writes only inside
agents/<id>/. - Atomic writes: Messages use temp-file + rename (
hive.tsimplements this). - Append-only logs: Consumers track their own cursor; history never rewrites.
- Global files restricted: Only
log.jsonl(append) andboard.md(god-mediated) permit cross-agent writes.
The message schema follows a trimmed FIPA-lite "speech-act" format defined in HIVE.md:
{
"id": "2026-05-30T14-03-11-123Z-a1b2",
"conversation": "conv-7f3",
"in_reply_to": null,
"from": "agent.researcher",
"to": "agent.coder | god | broadcast",
"act": "request | inform | propose | query | agree | refuse | done",
"subject": "short human-readable summary",
"body": "free text / markdown / structured payload",
"hops": 3,
"requires_reply": true,
"needs_human": false,
"created_at": "ISO-8601"
}
Writing Messages to the Hive
Agents output messages to their outbox/; the router.ts implementation handles delivery:
import { writeFileSync, renameSync } from 'fs';
import { v4 as uuid } from 'uuid';
import * as path from 'path';
const msg = {
id: `${new Date().toISOString()}-${uuid()}`,
conversation: 'conv-123',
in_reply_to: null,
from: 'agent.researcher',
to: 'agent.coder',
act: 'request',
subject: 'fetch latest spec',
body: 'Please read SPEC.md and summarize the key points.',
hops: 0,
requires_reply: true,
needs_human: false,
created_at: new Date().toISOString(),
};
const outDir = '/path/to/hive/agents/researcher/outbox';
const tmp = path.join(outDir, `${msg.id}.tmp`);
const final = path.join(outDir, `${msg.id}.json`);
writeFileSync(tmp, JSON.stringify(msg, null, 2));
renameSync(tmp, final); // atomic: router polls for .json files only
Consuming Messages from the Hive
import { readdirSync, readFileSync, renameSync } from 'fs';
import * as path from 'path';
const inbox = '/path/to/hive/agents/coder/inbox';
const done = path.join(inbox, '.done');
for (const file of readdirSync(inbox)) {
if (!file.endsWith('.json')) continue;
const msg = JSON.parse(readFileSync(path.join(inbox, file), 'utf8'));
// Process message...
renameSync(path.join(inbox, file), path.join(done, file));
}
Understanding the Event Plane: Real-Time IPC
While the Hive handles durability, the Event Plane enables reactivity. Claude Code processes emit structured events through hooks, which a shim (tools/cth-hook) forwards over a Unix-domain socket to the Electron main process.
Hook Types and Flow
| Hook | When Fired | Use in Munder Difflin |
|---|---|---|
UserPromptSubmit |
New user input | Trigger agent activation |
PreToolUse |
Before tool execution | Audit or block operations |
PostToolUse |
After tool completion | Update state, route results |
Notification |
Claude emits alert | Surface to UI or escalate |
Stop |
Turn ends | Poll inbox, decide block/resume |
Each hook:
- Receives JSON payload from Claude Code
- Tags with
session_idvia environment variable - POSTs to
~/.cth/events.sock
The main process consumes these events to:
- Update the Pixi canvas avatar state machine
- Refresh the xterm view
- Trigger Hive operations (routing, logging, committing)
- Decide whether to block an agent (keep active for pending messages)
Hook Shim Implementation
# Conceptual cth-hook shim
cat | jq '. + {session_id: "$CLAUDE_SESSION_ID"}' |
while read -r line; do
printf '%s\n' "$line" >> ~/.cth/events.sock
done
How Hive and Event Plane Coordinate
The true power of Munder Difflin's hive/event plane design emerges in their integration. Consider this request-response flow:
- Agent B needs data from Agent C → writes to
agents/B/outbox/. - Router (
src/main/router.ts) detects the file, moves it toagents/C/inbox/, appends tolog.jsonl, and commits. - Agent C finishes its turn; the
Stophook fires via Event Plane. - Main process polls C's inbox, finds the pending request, returns "block" decision.
- C stays active, reads request, performs work, replies through its outbox.
This hybrid approach gives synchronous coordination semantics built on asynchronous, durable storage.
The God Orchestrator
A privileged god agent (the "CEO" desk) centralizes sensitive operations per src/main/godAgent.ts:
- Routing resolution: Handles routine outbound requests without waking target agents.
- Human escalation: Surfaces critical requests (destructive actions, budget overruns) through native Claude Code sessions.
- Blackboard ownership: Sole writer of
board.md, ensuring conflict-free shared planning.
The god agent is itself a consumer of both planes: it receives events via IPC and persists decisions to the Hive.
Key Implementation Files
| File | Purpose |
|---|---|
HIVE.md |
Design document specifying layout, schema, routing, and god orchestrator |
SPEC.md |
Two-plane architecture specification (Event Plane vs Terminal Plane) |
src/main/hive.ts |
Runtime Hive API: load agents, persist messages, Git commits |
src/main/router.ts |
Outbox watcher, message mover, log.jsonl appender |
src/main/godAgent.ts |
Privileged orchestrator logic |
tools/cth-hook |
Hook-to-socket shim for Claude Code integration |
Summary
- Hive provides Git-backed durability with atomic file writes, single-writer rules, and append-only logs.
- Event Plane delivers real-time reactivity through Claude Code hooks over Unix-domain sockets.
- Router (
router.ts) bridges them: watching outboxes, moving messages, committing history. - God agent centralizes escalation and shared state to prevent merge conflicts.
- Together they enable auditable, recoverable, reactive multi-agent coordination without sacrificing either persistence or responsiveness.
Frequently Asked Questions
What is the difference between the Hive and the Event Plane?
The Hive is the on-disk, Git-tracked persistence layer where all agent state, messages, and history live permanently. The Event Plane is the real-time IPC mechanism that streams hook events from Claude Code processes to the main process. The Hive ensures you can replay and audit everything; the Event Plane ensures the UI and agents react immediately to state changes.
Why does only the main process commit to Git?
Munder Difflin enforces a single-writer-per-file rule to eliminate Git index lock contention. If multiple agents or processes tried to commit simultaneously, Git's locking would create race conditions and failures. By centralizing all commits in the main process, the system guarantees atomic, conflict-free history.
How do agents communicate without direct connections?
Agents communicate through asynchronous mailbox files. When Agent A sends to Agent B, A writes to its own outbox/. The router (main process) detects this, moves the file to B's inbox/, logs it, and commits. B discovers the message on its next activation via the Event Plane's Stop hook, which triggers a poll of its inbox.
What happens when an agent needs human approval?
The god agent adjudicates such requests. When a message has needs_human: true or involves critical operations, the god agent escalates through a native Claude Code session rather than auto-resolving. This privileged agent is also the sole writer of board.md, maintaining a clean audit trail for all human-involved decisions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →