Message Queue Composition in Munder Difflin: When Agents Can Type into Terminals

Munder Difflin uses a single per-agent MD queue stored in Zustand to hold pending messages, and agents can only type into terminals when five conditions are met: idle status, no auto-pause (or manual release), completed boot grace, terminal automation safety, and minimum 4.5-second spacing between deliveries.

Understanding the message queue composition in Munder Difflin is essential for anyone building automation harnesses around Claude Code. The repository implements a strict, policy-driven gating system that prevents AI agents from interrupting users or corrupting in-flight terminal sessions. This article breaks down the queue architecture, the safety gates, and the precise conditions that allow an agent to write to a PTY.

Two Queues: What Munder Difflin Controls vs. Claude Code

Munder Difflin manages only one of two queues involved in message delivery. Understanding the boundary prevents architectural confusion when debugging delayed messages.

Queue Location Purpose
MD queue Harness Zustand store (per-agent) Holds messages Munder Difflin has accepted and parked until the terminal is free
Claude queue Inside Claude Code itself Holds text Claude Code has accepted but not yet started on—the harness never sees this

The rest of this article focuses exclusively on the MD queue that Munder Difflin owns and operates.

MD Queue Composition and Storage

The MD queue lives in the harness's Zustand store at src/renderer/src/store/store.ts. It is a simple array per agent ID:

  • Enqueue point: enqueueMessage(agentId, text)—called by composers, Slack ingress, scheduled jobs, and inbox nudges
  • Dequeue point: The drain loop (effect #4 in src/renderer/src/hooks/useHive.ts)—the only code that ever writes to a live terminal

This single-writer design eliminates race conditions between multiple automation sources.

The Five Conditions for Terminal Access

The drain loop evaluates these conditions on every store change (debounced 200 ms) plus a 3-second back-stop tick. All must be true for delivery:

Condition Implementation Rationale
Agent status is idle agent.status === 'idle' in store Prevents interrupting a running turn or active tool execution
Auto-delivery not paused or message manually released !autoPause || msg.manual Supports floor-wide pausing via Command Center with per-message override
Past boot grace window pastBootGrace flag Allows CLI startup banners to complete before automation begins
isTerminalAutomationSafe(ptyId) returns true terminalPool.ts Verifies user still owns the prompt (see next section)
≥ 4.5 s since last delivery timeSinceLast > 4500 Prevents rapid writes that would jam TUI-based interfaces

When a pause is active, queued rows display a Send now link that sets manual: true, bypassing only the pause check while preserving all other gates.

The "User Owns the Prompt" Safety Gate

isTerminalAutomationSafe in src/renderer/src/components/terminalPool.ts blocks delivery when any protection flag is active:

Flag Set When Cleared When
exited PTY process died PTY respawns
picker /model-style command opened a picker menu Enter, Escape, Ctrl-C typed into terminal, or 30-minute expiry (STALE_PICKER_MS)
draft Unsubmitted text detected on prompt line Submitting, clearing, or 30-minute expiry (STALE_INPUT_MS)
settling Short repaint window after line was freed Time elapsed

Critical behavior: Expiration of picker or draft does not erase user text or close open menus. The queued message types after whatever already exists on the line.

Reading the prompt line uses actual xterm buffer inspection (term.buffer.active in terminalPool.ts) rather than keystroke counting—ensuring the system never inadvertently erases drafts or closes pickers.

The Drain Loop: High-Level Flow

composer / Slack ingress ──► enqueueMessage(agentId, text) ──► MD queue ──► drain (effect #4) ──► PTY
scheduled /compact (effect #6) ──► …

Key implementation files:

Code Examples

Enqueueing a message from any producer:

// From composer, Slack ingress, or scheduled job
import { enqueueMessage } from 'src/renderer/src/store/store';

enqueueMessage('agent-42', 'npm install lodash');

The drain loop's safety check (from useHive.ts, effect #4):

if (
  agent.status === 'idle' &&
  !autoPause &&
  pastBootGrace &&
  isTerminalAutomationSafe(ptyId) &&
  timeSinceLast > 4500
) {
  const msg = mdQueue[agentId].shift();   // take front message
  pty.write(msg.text);                    // type the text
  pty.write('\r');                        // submit (Enter)
}

Summary

  • Munder Difflin maintains one MD queue per agent in its Zustand store—Claude Code's internal queue is invisible to the harness
  • The drain loop in useHive.ts is the sole writer to PTYs
  • Terminal access requires five simultaneous conditions: idle status, no pause (or manual release), completed boot grace, isTerminalAutomationSafe, and 4.5-second spacing
  • The "user owns the prompt" gate (terminalPool.ts) protects against automation during pickers, drafts, exits, and settle windows with 30-minute stale timeouts
  • Buffer reading in terminalPool.ts ensures read-only inspection—user state is never destroyed

Frequently Asked Questions

What happens if I click "Send now" during an auto-pause?

The message receives manual: true and moves to the front of the queue, bypassing only the pause check. All other conditions—idle status, boot grace, terminal safety, and timing—must still pass before the agent types into the terminal.

Can Munder Difflin see what's in Claude Code's internal queue?

No. The Claude queue exists entirely inside Claude Code and is opaque to the harness. Latency you observe may originate in either queue; only the MD queue is observable and controllable via Munder Difflin's UI and APIs.

Why does the system wait 4.5 seconds between deliveries?

The 4500 ms threshold prevents rapid back-to-back writes that would overwhelm TUI-based terminals (such as those running interactive CLI tools). This spacing ensures visual stability and prevents input jamming in complex terminal applications.

What clears a picker block besides the 30-minute timeout?

A picker flag clears when the user types Enter, Escape, or Ctrl-C into the terminal. These keystrokes signal intentional dismissal of the picker menu, at which point automation can safely resume.

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 →