How Munder Difflin Implements Persistent Memory for Agents: Architecture and Code Reference

Munder Difflin stores agent notes in plain-text memory.md files under hive/agents/<agent-id>/ and continuously mines them into a shared semantic index (MemPalace) every three minutes, enabling persistent, searchable long-term memory across sessions.

Munder Difflin is an Electron-based multi-agent framework where persistent memory for agents is implemented through a dual-layer architecture combining local markdown files with a shared vector index. This article examines the source code implementation in chaitanyagiri/munder-difflin, detailing how the MemoryManager and MemoryReflector classes orchestrate durable knowledge storage and retrieval.

The Dual-Layer Storage Architecture

Munder Difflin separates durable storage from searchable semantic memory. Each layer serves a distinct purpose in the persistence lifecycle.

Local Agent Memory Files

Each agent maintains its own long-term notes in a plain-text memory.md file located at hive/agents/<agent-id>/memory.md. These files survive process restarts and serve as the source of truth for an agent’s accumulated knowledge. The system treats these as append-only logs that agents can read and write during their execution.

The Shared MemPalace Index

To enable cross-agent semantic search, the application maintains a centralized vector database called the MemPalace. According to src/main/memory.ts lines 74-77, the MemoryManager.palacePath() method builds the palace location at <harnessHome>/palace, creating a shared "home" for the semantic index that all agents can query.

The MemoryManager Class (src/main/memory.ts)

The MemoryManager runs in the main Electron process and acts as the bridge between local markdown files and the shared semantic index.

CLI Discovery and Environment Injection

Before spawning agents, the manager resolves the external mempalace binary location. The MemoryManager.bin() method (lines 79-115) searches $PATH and common install locations—including ~/.local/bin/mempalace on Linux/macOS and Windows where mempalace—to locate the CLI.

When an agent spawns, MemoryManager.env() (lines 39-44) injects two critical environment variables into the child process:

{
  MEMPALACE_PALACE_PATH: <palace-path>,
  MEMPALACE_EMBEDDING_MODEL: <model>
}

This injection ensures that all CLI calls from the agent automatically target the correct shared palace without hardcoded paths.

Continuous Mining Loop (Store)

Every three minutes (MINE_INTERVAL_MS), the manager scans hive/agents/*/memory.md for modification time changes. For any updated file, it executes the mining command via the mineAgent helper (lines 88-102 and 108-118):

mempalace mine <agentDir> --wing <agentId> --agent <agentId>

The mining process is idempotent; the CLI deduplicates entries, making re-mining safe. A ten-minute timeout protects against hung processes (lines 120-127). When the MemoryReflector updates a file, the changed mtime automatically triggers re-indexing on the next cycle.

Semantic Search and Recall (Read)

The manager exposes two async helpers for retrieving information:

  • search(query, {wing?, results?}) – Executes mempalace search for semantic lookup across all agents (lines 80-85).
  • wakeUp(wing?) – Executes mempalace wake-up to generate a short digest for session initialization (lines 87-92).

Both methods use the internal runCli helper (lines 46-71) to spawn the binary with the injected environment and enforce a 120-second timeout.

Memory Maintenance and Condensing (src/main/reflect.ts)

Unbounded growth of memory.md files would eventually degrade performance. The MemoryReflector provides automatic compression to keep memory files manageable.

The MemoryReflector Class

Running in the same main process as the MemoryManager, the MemoryReflector periodically parses each memory.md, creates backups, and summarizes old sections using a headless Claude-Haiku call (lines 30-41). It then rewrites the file into a strict three-region format (lines 86-102):

  1. Pinned facts – Critical information that must never be summarized.
  2. Condensed summary – AI-generated compression of older sections.
  3. Recent verbatim sections – The most recent entries kept in full.

Automatic Re-indexing After Condensing

After the reflector writes the condensed file, the memory.md modification time updates. The MemoryManager mining loop detects this change on its next three-minute iteration and automatically re-indexes the updated content, ensuring the semantic search index remains synchronized with the compressed local storage.

Lifecycle and Configuration

The persistence system initializes only when specific conditions are met. In src/main/index.ts (lines 68-71), MemoryManager.start() verifies that:

  • The semanticMemory user setting is enabled.
  • The mempalace CLI binary is discoverable.
  • The palace home directory exists.

The mining loop can be gracefully stopped with memory.stop(). User-tunable parameters—including embeddingModel, condensing intervals, and size triggers—reside in src/main/config.ts.

Practical Implementation Examples

The following examples demonstrate how to interact with the persistent memory system programmatically.

Creating an Agent with Persistent Memory

import { spawn } from 'node:child_process';
import { MemoryManager } from './memory';

// Initialize with config-provided paths
const memory = new MemoryManager(
  () => config.harnessHome,
  () => ({ enabled: true, model: 'minilm' })
);
memory.start(); // Begins the 3-minute mining loop

// Spawn agent with palace environment injected
const proc = spawn('claude', ['--agent', 'my-agent'], {
  env: { ...process.env, ...memory.env() },
});

Performing Semantic Lookups

async function findRelevantNotes(query: string) {
  const result = await memory.search(query, { results: 10 });
  if (result.ok) {
    console.log('Search results:\n', result.output);
  } else {
    console.error('Search failed:', result.error);
  }
}

Manual Memory Condensing

import { MemoryReflector } from './reflect';

const reflector = new MemoryReflector(
  () => config.harnessHome,
  () => 'claude',
  () => memory.env(),
  () => ({
    enabled: true,
    intervalMs: 30_000,
    byteTriggerPct: 60,
    sectionTrigger: 40,
    recentKeep: 12,
    minBytes: 16_384,
  }),
  (e) => console.log('Reflector log:', e)
);

// Force immediate condensing for a specific agent
reflector.reflectNow('my-agent').then((res) => console.log(res));

Summary

  • Munder Difflin implements persistent memory for agents through a combination of local memory.md files and a shared MemPalace semantic index.
  • The MemoryManager (src/main/memory.ts) orchestrates CLI discovery, environment injection, and a continuous mining loop that indexes changes every three minutes.
  • Agents communicate with the palace via injected environment variables (MEMPALACE_PALACE_PATH and MEMPALACE_EMBEDDING_MODEL).
  • The MemoryReflector (src/main/reflect.ts) prevents unbounded file growth by condensing old entries into a three-region format and triggering automatic re-indexing.
  • All search and recall operations use the external mempalace CLI with enforced timeouts for stability.

Frequently Asked Questions

Where does each agent store its persistent notes?

Each agent writes to a plain-text memory.md file located under hive/agents/<agent-id>/memory.md within the hive folder. This file serves as the durable, human-readable source of truth for the agent’s long-term knowledge.

How often does Munder Difflin index new memory entries?

The MemoryManager scans for changes every three minutes (MINE_INTERVAL_MS). Any memory.md file with a modified timestamp since the last successful mine is re-indexed into the shared MemPalace using the mempalace mine command.

What prevents the memory files from growing indefinitely?

The MemoryReflector class periodically compresses memory.md files by summarizing older sections via Claude-Haiku and rewriting the file into a structured format with pinned facts, condensed summaries, and recent verbatim entries. This condensing runs automatically based on configurable byte and section triggers.

How do agents discover the shared semantic memory index?

When spawning an agent, the main process calls MemoryManager.env(), which injects the MEMPALACE_PALACE_PATH and MEMPALACE_EMBEDDING_MODEL environment variables into the child process. This ensures the agent’s CLI calls automatically target the correct shared palace location without requiring manual path configuration.

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 →