# How Runtime Patches Are Applied in Feynman Before Launching Pi

> Discover how Feynman applies runtime patches to node_modules before launching Pi. Learn about idempotent source transformations for seamless integration.

- Repository: [Advait Paliwal/feynman](https://github.com/advaitpaliwal/feynman)
- Tags: internals
- Published: 2026-09-08

---

**Feynman applies runtime patches through the `patchPiRuntimeNodeModules` dispatcher immediately before spawning the Pi child process, traversing all relevant `node_modules` trees to perform idempotent source transformations that align Pi components with Feynman's execution environment.**

The Feynman framework orchestrates its bundled Pi agent through a sophisticated runtime modification pipeline. Every time you initiate a Pi chat session, the system verifies Node version compatibility and rewrites specific source files across multiple package trees to ensure Pi's CLI arguments, security configurations, and core behaviors conform to Feynman's operational requirements.

## The Launch Entry Point

The patch application begins in [`src/pi/launch.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/launch.ts) within the **`launchPiChat`** function. This public API serves as the gateway for starting Pi chat sessions and deliberately sequences environment validation before process spawning.

```typescript
// src/pi/launch.ts
export async function launchPiChat(options: PiRuntimeOptions): Promise<void> {
    ensureSupportedNodeVersion();                     // Verify Node version
    patchPiRuntimeNodeModules(options.appRoot,        // ← Apply all patches
                              options.feynmanAgentDir);
    // ...
    const child = spawn(process.execPath, [...], {
        cwd: options.workingDir,
        stdio: "inherit",
        env: buildPiEnv(options, paths, executables),
    });
    // ...
}

```

The function first calls **`ensureSupportedNodeVersion()`** to validate the Node runtime, then immediately invokes **`patchPiRuntimeNodeModules`** with the application root and Feynman agent directory. Only after the patcher returns does the system spawn the Pi child process, guaranteeing the child sees the modified code.

## The Patch Dispatcher Architecture

The centralized patching logic resides in [`src/pi/runtime-patches.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/runtime-patches.ts) within the **`patchPiRuntimeNodeModules`** function. This dispatcher resolves the bundled Pi version, validates compatibility, and orchestrates transformations across multiple `node_modules` trees.

```typescript
// src/pi/runtime-patches.ts
export function patchPiRuntimeNodeModules(
    appRoot: string,
    feynmanAgentDir?: string,
    platform = process.platform,
): boolean {
    const bundledPiVersion = resolveBundledPiVersion(appRoot);
    // ...assert version compatibility...

    const nodeModuleRoots = [
        resolve(appRoot, "node_modules"),
        resolve(appRoot, ".feynman", "npm", "node_modules"),
    ];
    if (feynmanAgentDir) {
        nodeModuleRoots.push(
            getFeynmanNpmGlobalNodeModulesPath(feynmanAgentDir, platform),
            resolve(feynmanAgentDir, "npm", "node_modules")
        );
    }

    // Apply patches to CLI args, brace-expansion, esbuild, undici-proxy,
    // Pi sub-packages, forward-fixes, third-party bundles, Alpha-Hub, MCP SDK...
    
    return changed;   // true if any file was rewritten
}

```

The function returns a **boolean** indicating whether any files were modified, though the caller currently relies on the side effects rather than the return value.

### Node Module Discovery

The patcher constructs an array of **`nodeModuleRoots`** to ensure comprehensive coverage across Feynman's nested dependency structure:

- **`resolve(appRoot, "node_modules")`** – The primary application dependencies
- **`resolve(appRoot, ".feynman", "npm", "node_modules")`** – Feynman's isolated npm cache
- **`getFeynmanNpmGlobalNodeModulesPath(feynmanAgentDir, platform)`** – Global Feynman npm prefix when `feynmanAgentDir` is provided
- **`resolve(feynmanAgentDir, "npm", "node_modules")`** – Agent-specific npm modules

### Idempotent Transformation Strategy

Each patch follows a consistent **read-transform-write** pattern using `readFileSync` to load source files, applying string transformations, and writing back with `writeFileSync` only when necessary. The system is **idempotent**—if a file already contains the expected transformation, the patcher returns `false` and leaves the source untouched. This guarantees that repeated launches do not corrupt files or trigger unnecessary I/O operations.

## Specific Runtime Patch Targets

The dispatcher applies targeted modifications across thirteen distinct categories:

- **CLI Arguments**: Patches `node_modules/**/pi-coding-agent/dist/cli/args.js` to align Pi's command-line parser with Feynman's delimiter contract.

- **Security Hardening**: Updates the `brace-expansion` package to secure against known vulnerabilities and modifies `esbuild` and `undici` trees to disable unsafe proxies and ensure compatibility with Feynman's bundled runtime.

- **Pi Core Packages**: Transforms `pi-coding-agent`, `pi-agent-core`, `pi-ai`, and `pi-tui` to insert Feynman-specific defaults (such as `piConfig`), fix runtime bugs, and apply forward-fixes for AI integration, docparser invisible-text handling, compaction tools, and line-ending normalization.

- **Pi-Web-Access**: Rewrites all files listed in `PI_WEB_ACCESS_PATCH_TARGETS` plus forward-fixtures to provide the patched web-access implementation required for browser-based sub-agents.

- **Alpha-Hub Integration**: Bumps `@advaitpaliwal/alpha-hub` source files to the bundled `0.1.4` application binary interface.

- **MCP SDK Validation**: Modifies `@modelcontextprotocol/sdk/package.json` to guarantee correct peer-dependency layout.

- **State File Permissions**: Enforces safe file-mode defaults in [`pi-coding-agent/dist/core/auth-storage.js`](https://github.com/advaitpaliwal/feynman/blob/main/pi-coding-agent/dist/core/auth-storage.js) for credential storage.

- **Model Registry Alignment**: Updates [`pi-coding-agent/dist/core/model-registry.js`](https://github.com/advaitpaliwal/feynman/blob/main/pi-coding-agent/dist/core/model-registry.js) and [`model-runtime.js`](https://github.com/advaitpaliwal/feynman/blob/main/model-runtime.js) to align semantics with the bundled Pi version.

- **Extension Handler Timeouts**: Applies patches from `scripts/lib/pi-extension-handler-timeout-patch.mjs` to stabilize extension lifecycle management.

- **Runtime Correctness**: Implements forward-fixes from `scripts/lib/pi-runtime-correctness-patch.mjs` covering agent loops, session managers, Llama usage patterns, and OpenTelemetry integration.

## Practical Implementation Examples

### Normal Launch with Automatic Patching

```typescript
import { launchPiChat } from "./src/pi/launch.js";

await launchPiChat({
  appRoot: "/my/project",
  feynmanAgentDir: "/my/project/.feynman/agents",
  workingDir: "/my/project",
  mode: "chat",
  thinkingLevel: "medium",
});

```

This call automatically verifies the Node version, applies all runtime patches across discovered `node_modules` trees, and spawns the Pi child process with the modified environment.

### Manual Patch Invocation

```typescript
import { patchPiRuntimeNodeModules } from "./src/pi/runtime-patches.js";

const changed = patchPiRuntimeNodeModules("/my/project");
console.log(`Runtime patches applied: ${changed}`);

```

Running this snippet manually reproduces the same pre-launch patching without actually spawning Pi, useful for debugging or warm-up scenarios.

### Verifying Patched Files

```typescript
import { readFileSync } from "node:fs";

const patched = readFileSync(
  "/my/project/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js",
  "utf8"
);
console.log(patched.includes("Feynman"));

```

Inspecting the file reveals injected Feynman-specific CLI handling that the patcher inserted during the transformation phase.

## Summary

- **Entry Point**: The **`launchPiChat`** function in [`src/pi/launch.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/launch.ts) triggers the patching pipeline immediately before spawning Pi, ensuring the child process sees modified code.

- **Dispatcher**: **`patchPiRuntimeNodeModules`** in [`src/pi/runtime-patches.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/runtime-patches.ts) orchestrates the patching logic across multiple `node_modules` roots, including standard dependencies and Feynman's isolated npm caches.

- **Idempotency**: All patches use a safe read-transform-write pattern that returns `false` if no changes are necessary, allowing repeated launches without file corruption.

- **Coverage**: The system patches CLI arguments, security-sensitive dependencies (brace-expansion, esbuild, undici), Pi core packages, web-access implementations, Alpha-Hub integration, MCP SDK metadata, and state file permissions.

- **Timing**: Patches run **before every launch**, modifying source files on disk so the spawned Pi process inherits the correct runtime behavior immediately upon startup.

## Frequently Asked Questions

### When exactly do the runtime patches execute?

The patches execute immediately after Node version validation and immediately before the `spawn()` call that creates the Pi child process. According to the source code in [`src/pi/launch.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/launch.ts), this sequencing guarantees that the Pi agent boots into an already-patched environment.

### Are the patches safe to run multiple times?

Yes. The patching system is **idempotent**—each transformation checks whether the target file already contains the expected changes. If the file is already patched, the function returns `false` without rewriting the file, preventing corruption from repeated launches.

### What Pi components are modified during patching?

The patcher targets **`pi-coding-agent`** (CLI args, auth storage, model registry), **`pi-web-access`** (browser sub-agent support), **`pi-ai`** and **`pi-tui`** (configuration defaults), plus security patches for `brace-expansion`, `esbuild`, and `undici`. It also modifies **`@advaitpaliwal/alpha-hub`** and **`@modelcontextprotocol/sdk`** for version compatibility.

### Can I manually trigger the patches without launching Pi?

Yes. Import **`patchPiRuntimeNodeModules`** from [`src/pi/runtime-patches.ts`](https://github.com/advaitpaliwal/feynman/blob/main/src/pi/runtime-patches.ts) and invoke it with your application root path. This returns a boolean indicating whether any files were modified, allowing you to apply patches ahead of time or verify patch status without spawning the agent.