# How the Munder Difflin Prerequisites Checker Detects and Installs Missing Tools

> Learn how the Munder Difflin prerequisites checker detects missing tools using static catalogs and PATH probing, then generates install commands for your system.

- Repository: [Chaitanya Giri/munder-difflin](https://github.com/chaitanyagiri/munder-difflin)
- Tags: how-to-guide
- Published: 2026-08-20

---

**The Munder Difflin prerequisites checker combines a static `ToolSpec` catalog with runtime PATH probing to detect missing binaries and generate platform-specific installation commands for manual execution.**

Munder Difflin is an Electron-based development harness that relies on external binaries—UV, Git, Node—and the **MemPalace** semantic-memory service. The **prerequisites checker** ensures the host environment contains these dependencies before agents begin work. According to the `chaitanyagiri/munder-difflin` source code, the system uses a declarative catalog in [`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts) and a runtime probe via the `tools:status` IPC handler to identify gaps and provide exact installation instructions.

## Static Tool Catalog Definition

All external dependencies are declared in [`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts). Each entry follows the **`ToolSpec`** interface, which encodes detection rules and platform-aware install commands.

### ToolSpec Structure

Every tool in the catalog specifies metadata and installation logic:

```ts
interface ToolSpec {
  id: string;           // Stable identifier (e.g., 'uv', 'git')
  bin: string | null;   // Binary name to probe on PATH
  kind: 'prerequisite' | 'memory' | 'engine';
  essential: boolean;   // Required for core functionality
  install: {
    posix: string;      // macOS/Linux command
    win32: string;      // Windows command
  };
  why: string;          // User-facing impact description
}

```

The checker filters for `kind === 'prerequisite'` when validating the environment.

### Platform-Specific Install Commands

The catalog provides exact shell commands for each platform. For example, UV and Git entries include conditional installation scripts:

```ts
{
  id: 'uv',
  bin: 'uv',
  kind: 'prerequisite',
  essential: true,
  install: {
    posix: 'curl -LsSf https://astral.sh/uv/install.sh | sh',
    win32: 'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"'
  },
  docsUrl: 'https://docs.astral.sh/uv/'
},
{
  id: 'git',
  bin: 'git',
  kind: 'prerequisite',
  essential: true,
  install: {
    posix: 'xcode-select --install   # macOS · or: sudo apt install git',

    win32: 'winget install --id Git.Git -e'
  }
}

```

Source: [[`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts)](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts#L44-L82)

## Runtime Detection via IPC

When the UI requests the current environment state, the Electron main process handles the **`tools:status`** channel in [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts). This handler probes the host machine and returns a `ToolStatus` array indicating presence or absence.

### Probing PATH with resolveCliCommand

For standard prerequisites, the handler uses **`resolveCliCommand`** (a wrapper around `which` on POSIX and `where` on Windows) to locate binaries:

```ts
ipcMain.handle('tools:status', (): ToolStatus[] => {
  const win = process.platform === 'win32';
  
  return toolCatalog().map((spec): ToolStatus => {
    const installCommand = win ? spec.install.win32 : spec.install.posix;
    
    // Probe ordinary prerequisites
    if (!spec.bin) return { ...spec, installCommand, found: false, path: null };
    
    let path: string | null = null;
    try {
      const resolved = resolveCliCommand(spec.bin);
      if (resolved !== spec.bin && existsSync(resolved)) {
        path = resolved;
      }
    } catch { /* Silent failure never crashes the panel */ }
    
    return { ...spec, installCommand, found: !!path, path };
  });
});

```

Source: [[`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts)](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts#L65-L88)

The `resolveCliCommand` utility originates from [`src/main/shellEnv.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/shellEnv.ts) and normalizes PATH resolution across platforms.

### Special Handling for MemPalace

The **MemPalace** service (`spec.id === 'mempalace'`) bypasses standard PATH probing. Its status derives from the memory subsystem via `memory.status()`, which checks both binary availability and palace initialization state:

```ts
if (spec.id === 'mempalace') {
  const mem = memory.status(); // Returns { available, initialized, bin }
  return {
    ...spec,
    installCommand,
    found: !!mem?.available,
    path: mem?.bin ?? null,
    detail: mem?.available
      ? (mem.initialized ? 'palace initialised' : 'installed — palace not built yet')
      : undefined
  };
}

```

This ensures the semantic-memory service reports readiness separately from simple binary presence.

## Generating Installation Prompts

Once detection completes, the **`setupPrompt`** function in [`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts) converts missing tools into actionable instructions. It formats a bullet list containing the install command and any additional notes:

```ts
export function setupPrompt(missing: ToolStatus[]): string {
  if (missing.length === 0) return '';
  
  const lines = missing.map(t => {
    const cmd = t.installCommand ? `\n  install: ${t.installCommand}` : '';
    const note = t.note ? `\n  note: ${t.note}` : '';
    return `- ${t.label} (${t.id})${cmd}${note}`;
  });
  
  return [
    'Set up my missing local tooling:',
    '',
    ...lines,
    '',
    'For each one: run the install command …'
  ].join('\n');
}

```

Source: [[`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts)](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts#L46-L66)

**Important:** The system **does not automatically execute** these commands. The UI displays the prompt to the user (or sends it to the "Michael" agent), requiring manual execution and subsequent verification.

## Practical Installation Flow

The complete detection and installation workflow follows these steps:

1. **Frontend Request**: The renderer calls `ipcRenderer.invoke('tools:status')`.
2. **Backend Returns**: An array of `ToolStatus` objects with `found` booleans and `installCommand` strings.
3. **Filter Missing**: The UI filters for `found === false` to identify gaps.
4. **Prompt Generation**: Calls `setupPrompt(missing)` to produce a human-readable checklist.
5. **Manual Execution**: The user runs the displayed commands (e.g., `curl … | sh` for UV, `winget install …` for Git).
6. **Re-verification**: After installation, the UI re-invokes `tools:status` to confirm the tools are now present.

### Example: Fetching Prerequisites in a Renderer Process

```ts
async function checkAndPrompt() {
  // Fetch status from main process
  const status: ToolStatus[] = await window.ipc.invoke('tools:status');
  
  // Isolate missing prerequisites
  const missing = status.filter(t => !t.found && t.kind === 'prerequisite');
  
  if (missing.length === 0) {
    console.log('All prerequisites satisfied');
    return;
  }
  
  // Generate installation instructions
  const prompt = setupPrompt(missing);
  displayModal(prompt); // Present to user for manual execution
}

```

## Summary

- **Static Catalog**: [`src/shared/toolCatalog.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/shared/toolCatalog.ts) defines tools via `ToolSpec`, including platform-specific `install.posix` and `install.win32` commands.
- **Runtime Probe**: The `tools:status` IPC handler in [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts) uses `resolveCliCommand` (from [`src/main/shellEnv.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/shellEnv.ts)) to check PATH for each binary.
- **MemPalace Exception**: Semantic-memory status comes from `memory.status()`, not standard PATH resolution.
- **Manual Installation**: The `setupPrompt` function generates explicit shell commands, but the user must execute them manually and re-verify.

## Frequently Asked Questions

### How does the prerequisites checker distinguish between macOS and Windows install commands?

The `tools:status` handler checks `process.platform === 'win32'` and selects the appropriate command from the `ToolSpec.install` object. For Windows, it uses `spec.install.win32`; for all other platforms (macOS, Linux), it uses `spec.install.posix`.

### Does Munder Difflin automatically install missing tools?

No. The prerequisites checker **detects** missing tools and generates installation prompts via `setupPrompt`, but it **never executes** the install commands automatically. The user must copy and run the displayed commands (e.g., `curl … | sh` or `winget install …`) manually, then trigger a re-check.

### What happens if a binary is not found on PATH?

If `resolveCliCommand` fails to locate the binary (or returns a path that fails `existsSync`), the handler sets `found: false` and `path: null` in the `ToolStatus` object. The frontend then includes this tool in the missing list passed to `setupPrompt`, which surfaces the pre-defined install command for that platform.

### How is MemPalace handled differently from other prerequisites?

Unlike standard tools probed via `resolveCliCommand`, **MemPalace** status derives from the `memory.status()` method, which checks both binary availability and initialization state. This allows the UI to distinguish between "binary installed" and "semantic memory palace initialized," providing granular feedback to the user.