# How the Hook Server Manages Agent Lifecycle Events in Munder Difflin

> Discover how the Munder Difflin Hook Server manages agent lifecycles by listening to socket events, parsing payloads, and updating states for seamless operation. Learn more!

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

---

**The HookServer in Munder Difflin orchestrates agent lifecycles by listening on a Unix domain socket, parsing Claude-style hook payloads, and routing them through state updates, operator controls, and UI notifications via the Electron main process.**

The Munder Difflin harness uses a central **HookServer** to bridge Claude-style agent hooks with the Electron main process. Located in [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts), this component manages the full lifecycle of AI agents—from session initialization and tool execution to cost tracking and forced termination.

## Core Architecture

### Unix Socket and Payload Ingestion

The server creates a `net.Server` instance that listens on a Unix domain socket for newline-delimited JSON payloads. In `HookServer.start()`, the system clears stale socket files and registers connection handlers that buffer incoming data until complete lines are received for parsing as `HookPayload`.

### State Management Maps

Two critical State Maps track agent state across the lifecycle. The `transcriptPaths` map stores the most recent transcript file per agent, while `contextById` maintains the latest token-window accounting data. These are initialized during class construction at [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts) lines 50-60 and updated continuously as hooks arrive.

### Operator Controls and Circuit Breakers

The constructor injects optional `ControlRegistry` and `CircuitBreaker` instances. The `ControlRegistry` provides operator-level HALT capabilities and tool-approval workflows, while the `CircuitBreaker` detects runaway tool loops by monitoring repeated identical calls.

### Renderer Communication

The `getWebContents()` function facilitates UI synchronization by emitting events like `hive:hookEvent`, `hive:contextUpdate`, and `control:approvalRequest` to the renderer process. These emissions occur through the `emit()` and `notify()` methods defined in the early lines of the hooks module.

## Lifecycle Event Processing Pipeline

### Telemetry and Cost Tracking

**Status** events update the `contextById` map and forward context-window updates to the renderer without triggering breakpoints or ledger entries. **CostSample** events—often from proxy-bridge sidecars like qwen—append rows to the cost ledger using `estimateCostUsd`, then return early to avoid interrupting agent flow.

### Tool Execution Hooks

When agents invoke tools, **PreToolUse** events check the `ControlRegistry` for operator denials. If denied, the server returns a `hookSpecificOutput` containing `permissionDecision: 'deny'`. **PostToolUse** events feed usage data into `circuitBreaker.recordToolUse()` to detect identical repeated calls that might indicate runaway loops.

### Compaction and Session Boundaries

**PreCompact** and **PostCompact** events notify the circuit breaker about token compaction phases to prevent false-positive loop detection during legitimate context window management. **SessionStart** events record the session ID via `recordSession`, optionally inject the God roster context, and clear stale state from previous sessions.

### Termination and Notifications

**Stop** and **SubagentStop** events emit desktop notifications through the `notify()` function and forward termination events to the renderer while respecting upstream stop-hooks that re-enter the boundary. **Notification** events trigger native desktop toasts for idle states or permission requests visible to operators.

## Operator Override Mechanisms

### HALT Enforcement

Before processing most events, the server checks `control?.shouldHalt(agentId)`. If the operator has issued a HALT command, the server emits the event and returns `{ continue: false, stopReason: … }`, forcing clean termination at the hook boundary.

### Context Injection

During `SessionStart` or `UserPromptSubmit` events, the server may inject additional context—such as the God roster or queued operator steer—into the hook response. This enables downstream agents to see the latest floor state through updates to the `contextById` map.

## Integrating HookServer in the Main Process

The following example demonstrates starting the HookServer with all required dependencies:

```typescript
import { HookServer } from './hooks';
import { HiveManager } from './hive';
import { getWebContents } from './renderer';
import { getConfig } from './config';
import { controlRegistry } from './control';
import { circuitBreaker } from './breaker';

const server = new HookServer(
  new HiveManager(),
  getWebContents,
  getConfig,
  controlRegistry,
  circuitBreaker
);
server.start();

```

To receive lifecycle events in the renderer process, listen for the specific IPC channels:

```typescript
window.ipcRenderer.on('hive:hookEvent', (e, data) => {
  console.log(`[hook] ${data.agentId} – ${data.event}`, data);
  // Update UI avatar, show toast, etc.
});

```

Operators can programmatically halt agents through the control registry:

```typescript
controlRegistry.haltAgent('agent-123');   // causes HookServer to return `continue: false`

```

## Summary

- The **HookServer** in [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts) acts as the central bridge between Claude-style agents and the Munder Difflin Electron main process.
- It maintains **state maps** (`transcriptPaths`, `contextById`) to track transcripts and token windows across agent lifecycles.
- **Lifecycle hooks** including `Status`, `PreToolUse`, `PostToolUse`, `SessionStart`, and `Stop` are processed with specific logic for telemetry, circuit breaking, and UI notification.
- **Operator controls** via `ControlRegistry` enable HALT enforcement and tool approval workflows that can deny specific operations.
- The **CircuitBreaker** integration prevents runaway tool loops by tracking repeated identical calls and respecting compaction boundaries.

## Frequently Asked Questions

### What file contains the HookServer implementation?

The core implementation resides in [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts), which defines the `HookServer` class, its constructor, and the `start()` method that creates the Unix domain socket server. This file also contains the `handle()` method that routes incoming hook payloads to their appropriate lifecycle handlers.

### How does the HookServer detect runaway tool loops?

The server uses an injected `CircuitBreaker` instance that receives `recordToolUse()` calls during `PostToolUse` events. The breaker tracks identical repeated tool invocations and receives compaction notifications via `PreCompact` and `PostCompact` events to avoid false positives during legitimate context management.

### Can operators halt agent execution mid-lifecycle?

Yes. The server checks `control?.shouldHalt(agentId)` before processing most events. When HALT is triggered, the server returns `{ continue: false, stopReason: … }` to the agent, forcing termination at the hook boundary while emitting the event to the renderer for UI updates.

### How does the HookServer communicate with the UI?

The server uses `getWebContents()` to access the Electron renderer process, emitting events such as `hive:hookEvent`, `hive:contextUpdate`, and `control:approvalRequest` through the `emit()` and `notify()` methods. The React frontend consumes these via [`useHive.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/useHive.ts) in the renderer directory.