# How the Hive Coordination Layer Handles Inter-Agent Messaging and Routing in munder-difflin

> Discover how the munder-difflin hive coordination layer ensures reliable inter-agent messaging and routing using a poll-based file-system router for efficient delivery.

- Repository: [Chaitanya Giri/munder-difflin](https://github.com/chaitanyagiri/munder-difflin)
- Tags: internals
- Published: 2026-08-20

---

**The Hive coordination layer uses a poll-based file-system router that scans agent outboxes every ~1.5 seconds and atomically moves JSON messages to recipient inboxes using `renameSync`, guaranteeing reliable inter-agent delivery without native file watchers.**

The inter-agent messaging and routing system in **munder-difflin** is powered by the Hive, an on-disk, multi-agent coordination subsystem managed entirely by the main Electron process. All communication between agents flows through this layer, which persists state under `<harnessHome>/hive/` and enforces a single-committer Git model.

## What Is the Hive Coordination Layer?

The Hive is the central nervous system for agent-to-agent communication in munder-difflin. Located under `<harnessHome>/hive/`, it is orchestrated by the **`HiveManager`** class in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts) and bootstrapped from [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts). Rather than using network sockets or message brokers, the Hive relies on an on-disk directory structure and atomic file operations to route messages between agents.

## Agent Workspace Layout

Every agent registered with the Hive receives its own dedicated folder under `agents/<id>/`. According to the **`HiveManager`** definition in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts) (lines 1–10), each workspace contains:

- `inbox/` – Directory for incoming messages.
- `outbox/` – Directory for outgoing messages.
- [`identity.md`](https://github.com/chaitanyagiri/munder-difflin/blob/main/identity.md) – Agent identity document.
- [`memory.md`](https://github.com/chaitanyagiri/munder-difflin/blob/main/memory.md) – Persistent agent memory.

This layout ensures that agents only need file-system access to participate in the messaging network.

## HiveMessage Format

Messages exchanged between agents are plain JSON objects conforming to the **`HiveMessage`** interface declared in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts) (lines 48–63). A `HiveMessage` includes metadata fields such as `from`, `to`, `act`, `subject`, `body`, timestamps, and routing controls like `hops` and `requires_reply`.

The router treats any file ending in `.json` inside an `outbox/` as a valid message payload.

## Poll-Based Router and Routing Mechanism

The core routing logic is implemented as a **poll-based router** running on a `setInterval` timer (`routerTimer`). As implemented in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts) around lines 1311–1350, the router executes the following cycle approximately every 1.5 seconds:

1. Enumerates every registered agent.
2. Reads all `.json` files inside the agent's `outbox/`.
3. Parses each file into a `HiveMessage` and inspects the `msg.to` field.
4. Atomically moves the file to `agents/<recipient>/inbox/` using `fs.renameSync`.
5. Archives the original file under the sender's `outbox/.sent` using `fs.renameSync`.

The design deliberately avoids `fs.watch` to sidestep macOS quirks and to guarantee atomicity through simple file operations.

## Delivery Guarantees and Atomicity

The Hive coordination layer provides three key reliability mechanisms:

- **Atomic move** – `renameSync` ensures a message is never duplicated or left partially written during transit.
- **Sent archive** – The `outbox/.sent` directory preserves a permanent record of dispatched messages, which the UI can render later.
- **Cursor tracking** – A [`cursor.json`](https://github.com/chaitanyagiri/munder-difflin/blob/main/cursor.json) file tracks inbox consumption, guaranteeing each message is processed exactly once (used by the Stop hook).

These mechanisms allow the system to recover cleanly from crashes without message loss.

## Human-in-the-Loop Routing

Messages addressed to `human` are automatically intercepted by the router and redirected to the special **"god" agent**. The god agent's UI surfaces a permission prompt, allowing human operators to approve or reject actions inline. This routing decision happens inside the standard router loop without requiring a separate approval queue.

## Hook Integration for Claude-Code Agents

Agents that expose a **`HIVE_SOCK`** via the `sockPath()` method receive lifecycle hook payloads such as `Stop` and `PreToolUse`. The router does not directly manage these hook calls; instead, it ensures that any message generated by a hook finishes its lifecycle and appears in the recipient's inbox. The hook shim writes JSON payloads to the Unix domain socket, and the Hive layer translates those into standard outbox files for the next router tick.

## Step-by-Step Message Flow

A complete round-trip through the Hive inter-agent messaging pipeline looks like this:

1. **Agent writes** a JSON file to its own `outbox/` using any filename ending in `.json`.
2. **Router tick** scans the `outbox/` of every registered agent.
3. For each message file:
   - The router reads the JSON and validates the `HiveMessage` structure.
   - It resolves the recipient from the `to` field.
   - It performs an atomic `renameSync` to move the file into `agents/<recipient>/inbox/`.
   - It archives the original under the sender's `outbox/.sent/`.
4. **Inbox consumer**—whether a Claude-Code hook, the UI, or a custom skill—reads the file from the recipient's inbox, processes it, and optionally writes a response to its own `outbox/`.
5. The router picks up the response on the next tick, completing the round-trip.

## Code Examples

### Sending a Message from an Agent

Agents produce messages by writing JSON files directly to their outbox:

```typescript
import { writeFileSync, join } from 'node:fs';
import { randomBytes } from 'node:crypto';

const msg = {
  id: randomBytes(6).toString('hex'),
  conversation: 'conv-123',
  in_reply_to: null,
  from: 'agentA',
  to: 'agentB',
  act: 'request',
  subject: 'Need data',
  body: 'Please fetch the latest sales numbers.',
  hops: 0,
  requires_reply: true,
  needs_human: false,
  created_at: new Date().toISOString()
};

const outboxDir = join(
  process.env.HIVE_ROOT!,
  'agents',
  'agentA',
  'outbox'
);

writeFileSync(
  join(outboxDir, `${msg.id}.json`),
  JSON.stringify(msg, null, 2)
);

```

When the next router tick runs, this file is moved to `agents/agentB/inbox/` and archived under `agents/agentA/outbox/.sent/`.

### Reading a Received Message

Recipients consume inbox messages by reading the JSON files from their `inbox/` directory:

```typescript
import { readdirSync, readFileSync, join } from 'node:fs';

const inboxDir = join(process.env.HIVE_ROOT!, 'agents', 'agentB', 'inbox');

for (const file of readdirSync(inboxDir)) {
  if (!file.endsWith('.json')) continue;
  const raw = readFileSync(join(inboxDir, file), 'utf8');
  const msg = JSON.parse(raw) as HiveMessage;
  console.log('Got message:', msg.subject, msg.body);
}

```

### Hook-Driven Automatic Routing

For Claude-Code agents, the system generates a [`settings.json`](https://github.com/chaitanyagiri/munder-difflin/blob/main/settings.json) that points the hook shim to **`HIVE_SOCK`**. The shim writes JSON payloads to this socket, which the Hive layer surfaces as standard outbox files. The poll-based router then picks them up on its next tick without requiring any additional routing code.

## Key Files in the Messaging Pipeline

- **[`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts)** – Defines `HiveMessage`, `HiveManager`, the poll-based router loop, and archive helpers.
- **[`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts)** – Bootstraps `HiveManager`, starts the `routerTimer`, and integrates the Hive with the Electron main process.
- **[`src/shared/agentProvider.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/agentProvider.ts)** – Determines whether a provider can receive inbox messages (`canReceiveInbox`) and whether it is hive-aware.
- **[`src/main/pty.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/pty.ts)** – Spawns agent PTYs with environment variables such as `HIVE_ROOT` and `AGENT_DIR` that the router relies on.
- **[`HIVE.md`](https://github.com/chaitanyagiri/munder-difflin/blob/main/HIVE.md)** – Design document covering the on-disk layout, the single-committer Git model, and the rationale for avoiding file watchers.

## Summary

- The Hive coordination layer handles inter-agent messaging and routing in munder-difflin through an on-disk, poll-based file-system router.
- All messages are plain JSON conforming to the `HiveMessage` interface, stored in per-agent `inbox/` and `outbox/` directories.
- The router in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts) uses `renameSync` to atomically move messages from sender outboxes to recipient inboxes every ~1.5 seconds.
- Delivery guarantees include atomic moves, a `outbox/.sent` archive, and [`cursor.json`](https://github.com/chaitanyagiri/munder-difflin/blob/main/cursor.json) tracking for exactly-once processing.
- Human-in-the-loop messages route to the "god" agent automatically, while Claude-Code hooks leverage `HIVE_SOCK` for lifecycle integration.

## Frequently Asked Questions

### How does the Hive router avoid message loss during crashes?

The router relies on `fs.renameSync` for both delivery and archiving. Because `rename` is atomic on POSIX systems, a message either remains in the sender's outbox or arrives completely in the recipient's inbox—there is no intermediate state. After delivery, the original is archived under `outbox/.sent`, creating a durable record even if the process restarts.

### Why does the Hive use polling instead of file watchers?

According to the source comments in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts), the poll-based router avoids `fs.watch` to eliminate macOS-specific quirks and to guarantee atomicity. A simple `setInterval` timer scanning every ~1.5 seconds is deterministic, portable, and avoids race conditions that can occur with native file-system event APIs.

### Can agents communicate without writing files directly?

Yes. Agents using Claude-Code can write to the `HIVE_SOCK` Unix domain socket exposed via `sockPath()`. The Hive layer translates these socket payloads into outbox files, which the poll-based router then delivers using the standard inbox move. This allows hook-driven agents to participate without managing the file system directly.

### What happens when a message is addressed to a human operator?

When `msg.to` equals `human`, the router redirects the message to the special "god" agent. The god agent's UI presents a permission prompt inline, enabling human approval without a separate queue or routing bypass. This is handled inside the standard router loop in [`src/main/hive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hive.ts).