How Runtime Patches Are Applied in Feynman Before Launching Pi
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 within the launchPiChat function. This public API serves as the gateway for starting Pi chat sessions and deliberately sequences environment validation before process spawning.
// 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 within the patchPiRuntimeNodeModules function. This dispatcher resolves the bundled Pi version, validates compatibility, and orchestrates transformations across multiple node_modules trees.
// 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 dependenciesresolve(appRoot, ".feynman", "npm", "node_modules")– Feynman's isolated npm cachegetFeynmanNpmGlobalNodeModulesPath(feynmanAgentDir, platform)– Global Feynman npm prefix whenfeynmanAgentDiris providedresolve(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.jsto align Pi's command-line parser with Feynman's delimiter contract. -
Security Hardening: Updates the
brace-expansionpackage to secure against known vulnerabilities and modifiesesbuildandundicitrees to disable unsafe proxies and ensure compatibility with Feynman's bundled runtime. -
Pi Core Packages: Transforms
pi-coding-agent,pi-agent-core,pi-ai, andpi-tuito insert Feynman-specific defaults (such aspiConfig), 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_TARGETSplus forward-fixtures to provide the patched web-access implementation required for browser-based sub-agents. -
Alpha-Hub Integration: Bumps
@advaitpaliwal/alpha-hubsource files to the bundled0.1.4application binary interface. -
MCP SDK Validation: Modifies
@modelcontextprotocol/sdk/package.jsonto guarantee correct peer-dependency layout. -
State File Permissions: Enforces safe file-mode defaults in
pi-coding-agent/dist/core/auth-storage.jsfor credential storage. -
Model Registry Alignment: Updates
pi-coding-agent/dist/core/model-registry.jsandmodel-runtime.jsto align semantics with the bundled Pi version. -
Extension Handler Timeouts: Applies patches from
scripts/lib/pi-extension-handler-timeout-patch.mjsto stabilize extension lifecycle management. -
Runtime Correctness: Implements forward-fixes from
scripts/lib/pi-runtime-correctness-patch.mjscovering agent loops, session managers, Llama usage patterns, and OpenTelemetry integration.
Practical Implementation Examples
Normal Launch with Automatic Patching
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
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
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
launchPiChatfunction insrc/pi/launch.tstriggers the patching pipeline immediately before spawning Pi, ensuring the child process sees modified code. -
Dispatcher:
patchPiRuntimeNodeModulesinsrc/pi/runtime-patches.tsorchestrates the patching logic across multiplenode_modulesroots, including standard dependencies and Feynman's isolated npm caches. -
Idempotency: All patches use a safe read-transform-write pattern that returns
falseif 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, 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 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →