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.ts implements this).
  • Append-only logs: Consumers track their own cursor; history never rewrites.
  • Global files restricted: Only log.jsonl (append) and board.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:

  1. Receives JSON payload from Claude Code
  2. Tags with session_id via environment variable
  3. 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:

  1. Agent B needs data from Agent C → writes to agents/B/outbox/.
  2. Router (src/main/router.ts) detects the file, moves it to agents/C/inbox/, appends to log.jsonl, and commits.
  3. Agent C finishes its turn; the Stop hook fires via Event Plane.
  4. Main process polls C's inbox, finds the pending request, returns "block" decision.
  5. 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →