# How Semantic Memory Is Managed in Munder Difflin: A Deep Dive into the MemoryManager Class

> Explore how Munder Difflin manages semantic memory with the MemoryManager class. Discover its vector-indexed MemPalace, embedding mining, and asynchronous search APIs.

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

---

**Munder Difflin manages semantic memory through a dedicated `MemoryManager` class that maintains a vector-indexed MemPalace outside the standard markdown hive, periodically mining agent [`memory.md`](https://github.com/chaitanyagiri/munder-difflin/blob/main/memory.md) files into embeddings while exposing asynchronous search and wake-up APIs via IPC channels.**

Munder Difflin is an open-source knowledge management system that extends beyond static markdown storage by implementing **semantic memory management** through a specialized vector indexing subsystem. Unlike traditional file-based storage, the application maintains a separate "palace" of vector embeddings that enables semantic search across agent memories. This article examines the technical implementation of this system, focusing on the `MemoryManager` class in [`src/main/memory.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/memory.ts) and its integration with the broader application architecture.

## The MemoryManager Core Architecture

The `MemoryManager` class serves as the central nervous system for semantic memory operations. It orchestrates CLI detection, environment configuration, and lifecycle management for the external MemPalace vector index.

### CLI Detection and Binary Resolution

Before any semantic operations can occur, the manager must locate the `mempalace` CLI binary. The `bin()` method implements a comprehensive search strategy:

- **`where`/`which` command execution** – Scans the system `PATH` for the executable
- **Fallback directory probing** – Checks `~/.local/bin`, Homebrew installations, and pip package locations
- **Result caching** – Stores the discovered path to avoid repeated filesystem scans

This detection logic resides in [`src/main/memory.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/memory.ts) (lines 38-74) and represents the first gate in the semantic memory initialization sequence.

### Environment Variable Injection

Once the CLI is located, the manager ensures all agent processes access the same vector index. The `env()` and `childEnv()` methods inject critical environment variables:

- **`MEMPALACE_PALACE_PATH`** – Points to the shared vector index directory
- **Embedding model configuration** – Specifies the chosen model (default: `minilm`) and compute device

This guarantees consistency across the application boundary, ensuring that every subprocess operates against the same semantic palace.

### Status Monitoring

The `status()` method (lines 84-95) aggregates system state into a `MemoryStatus` object that reports three critical conditions:

1. CLI availability (binary found in `PATH`)
2. User-enabled configuration flag (`semanticMemory` in config)
3. Existence of the palace directory on disk

This tri-state check enables the UI to display accurate initialization states and allows the system to gracefully degrade when dependencies are missing.

## Semantic Memory Lifecycle and Mining Loop

The semantic memory subsystem operates on a continuous lifecycle: initialization, periodic mining, and on-demand retrieval.

### Palace Initialization and Garbage Collection

During `start()` (lines 23-34), the manager performs initial housekeeping:

- **Quarantine reaping** – Calls `reapPalace()` to remove stray temporary copies left by MemPalace’s rename-aside mechanism
- **Directory validation** – Confirms the palace home folder exists before attempting operations
- **Mining loop activation** – Begins the background process that synchronizes markdown changes into vector embeddings

The `reapPalace()` function specifically targets directories listed in `quarantineDirsToReap`, cleaning up orphaned segments that could otherwise consume disk space.

### The Mining Process

The core synchronization mechanism runs every `MINE_INTERVAL_MS` (10 minutes) via `startMineLoop()`. The process follows this sequence:

1. **Change detection** – Scans `hive/agents/*/memory.md` for modifications since the last cycle
2. **Serialized execution** – Uses a `mining` flag to prevent concurrent `mempalace mine` processes
3. **Per-agent processing** – Executes `mempalace mine <agentDir> --wing <id> --agent <id>` for each changed file
4. **Timeout handling** – Aborts operations exceeding 10 minutes to prevent system hangs
5. **Backoff logic** – If quarantine directories are detected, `nextMineDelayMs` (imported from [`palaceReap.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/palaceReap.ts)) extends the interval up to `MINE_BACKOFF_MAX_MS` (30 minutes)

The `mineNow()` method (lines 89-113) exposes this functionality for manual triggering, handling the full lifecycle including `.gitignore` rule application.

### Search and Wake-up Operations

The manager exposes two primary retrieval APIs that wrap CLI calls:

**`search(query, options)`** – Executes `mempalace search` with configurable result limits:

```typescript
import { memory } from './index';   // singleton from src/main/index.ts

async function semanticSearch(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);
  }
}

```

**`wakeUp(wingId?)`** – Retrieves a concise digest (600-900 tokens) of the entire palace or a specific wing:

```typescript
async function wakeUpForWing(wingId: string) {
  const { ok, output, error } = await memory.wakeUp(wingId);
  if (ok) {
    // output contains condensed palace summary
    return output;
  }
  throw new Error(error);
}

```

Both methods utilize the internal `runCli()` wrapper to spawn subprocesses and parse stdout/stderr streams.

### Dynamic Refresh Capabilities

The `refresh()` method (lines 58-62) enables hot-reloading of the semantic memory subsystem. When users toggle the feature in settings or install the CLI after application startup, this function:

- Clears the binary cache via `resetBinCache()`
- Re-evaluates CLI availability
- Restarts the mining loop if conditions are met

This adaptability ensures the system responds to configuration changes without requiring a full application restart.

## Configuration and UI Integration

Semantic memory management is tightly integrated with the application's configuration layer and renderer process.

### Configuration Schema

The feature flag resides in [`src/main/config.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/config.ts) (lines 18-21):

```typescript
/** Enable semantic memory (MemPalace CLI). No-op if mempalace isn't installed. */
semanticMemory: boolean;

```

When `true` (the default), the system attempts to activate the memory manager during bootstrap. The configuration also specifies the **embedding model** via `embeddingModel`, defaulting to `minilm` if unspecified.

### Singleton Instantiation

In [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts) (lines 6-9), the application creates a single `MemoryManager` instance:

```typescript
const memory = new MemoryManager(
  () => readConfig().harnessHome,
  () => ({
    enabled: c.semanticMemory !== false,
    model: c.embeddingModel ?? 'minilm'
  })
);

```

This singleton pattern ensures consistent state across the main process while allowing lazy evaluation of configuration values.

### Settings Modal and IPC Wiring

The renderer communicates with the memory subsystem through IPC channels defined in [`src/main/realtimeActions.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/realtimeActions.ts) (lines 156-162). The Settings component ([`src/renderer/src/components/SettingsModal.tsx`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/renderer/src/components/SettingsModal.tsx), lines 306-312) provides the user interface:

```typescript
// Renderer – SettingsModal.tsx (simplified)
const toggleSemantic = async (next: boolean) => {
  await window.cth.updateConfig({ semanticMemory: next });
  setSemMemOn(next);
};

```

When toggled, the configuration update propagates to the main process, triggering `MemoryManager.refresh()` to re-arm or suspend the mining loop accordingly.

## Practical Implementation Examples

### Manually Triggering a Re-mine

For development or debugging scenarios, you can force an immediate mining cycle:

```typescript
// Exposed via IPC or dev console
memory.mineNow().then(() => console.log('Mining cycle completed'));

```

This runs the full `mineNow()` implementation, respecting timeouts and quarantine detection while bypassing the standard interval timer.

### Checking Semantic Memory Availability

Before performing operations, verify the subsystem is ready:

```typescript
const status = await memory.status();
if (status.available) {
  console.log(`Palace located at: ${process.env.MEMPALACE_PALACE_PATH}`);
} else {
  console.warn('Semantic memory unavailable - install mempalace CLI');
}

```

### Environment-Aware Process Spawning

When spawning agents that need semantic access, use the manager's environment injection:

```typescript
const childEnv = memory.childEnv();
const agentProcess = spawn('agent-binary', [], {
  env: { ...process.env, ...childEnv }
});

```

This ensures the subprocess inherits `MEMPALACE_PALACE_PATH` and embedding model configurations.

## Summary

- **Munder Difflin** implements semantic memory through the `MemoryManager` class in [`src/main/memory.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/memory.ts), which orchestrates an external MemPalace vector index.
- The system detects the `mempalace` CLI via the `bin()` method, searching `PATH` and common installation directories with fallback logic.
- A background mining loop runs every 10 minutes (with 30-minute backoff capability) to convert agent [`memory.md`](https://github.com/chaitanyagiri/munder-difflin/blob/main/memory.md) files into vector embeddings via `mineNow()`.
- **Environment variables** (`MEMPALACE_PALACE_PATH`) ensure consistent palace access across all agent processes.
- The `search()` and `wakeUp()` APIs provide semantic retrieval capabilities, returning ranked results or condensed palace digests.
- **Configuration** is controlled by the `semanticMemory` boolean in [`src/main/config.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/config.ts), accessible through the Settings modal with hot-reload support via `refresh()`.
- Garbage collection via `reapPalace()` prevents disk pollution from temporary quarantine directories.

## Frequently Asked Questions

### What is the MemPalace CLI and why does Munder Difflin require it?

The MemPalace CLI is an external dependency that provides vector indexing and semantic search capabilities. Munder Difflin delegates embedding generation and similarity search to this tool rather than implementing vector operations internally. The `MemoryManager` acts as a Node.js wrapper, spawning `mempalace` subprocesses for mining, searching, and wake-up operations. If the CLI is not installed, the semantic memory subsystem gracefully degrades to a no-op state while the rest of the application continues functioning.

### How often does the MemoryManager mine agent memories?

By default, the mining loop executes every **10 minutes** (`MINE_INTERVAL_MS`). However, if the system detects quarantine directories (temporary files left by MemPalace operations), the `nextMineDelayMs` backoff logic extends this interval up to a maximum of **30 minutes** (`MINE_BACKOFF_MAX_MS`). Developers can also trigger immediate mining via the `mineNow()` method without waiting for the interval.

### What happens if the MemPalace CLI is installed after Munder Difflin starts?

The application handles late CLI installation through the `refresh()` mechanism. When the user toggles semantic memory in settings or the system detects a configuration change, `MemoryManager.refresh()` clears the binary cache, re-scans for the CLI, and starts the mining loop if the binary is now available. This dynamic adaptation eliminates the need to restart the application when installing dependencies.

### Can semantic memory be enabled for specific agents only?

Currently, the `semanticMemory` configuration flag operates globally across the entire hive. The mining process automatically discovers all agents through the `hive/agents/*/memory.md` glob pattern, processing every changed file regardless of individual agent settings. While the `search()` and `wakeUp()` APIs accept optional `wing` parameters to filter results, the underlying vector index includes embeddings from all agents whose memory files have been mined.