How the Hook Server Manages Agent Lifecycle Events in Munder Difflin
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, 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 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:
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:
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:
controlRegistry.haltAgent('agent-123'); // causes HookServer to return `continue: false`
Summary
- The HookServer in
src/main/hooks.tsacts 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, andStopare processed with specific logic for telemetry, circuit breaking, and UI notification. - Operator controls via
ControlRegistryenable 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, 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 in the renderer directory.
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 →