How Prime Agent Integrates the IPython Kernel for Stateful Code Execution

Prime Agent integrates a persistent IPython kernel through a three-layer architecture: a tool definition that exposes notebook cells to the model, a provisioner that manages kernel lifecycle and state persistence, and a terminal UI component that renders rich output.

The integration turns Prime Agent into a long-lived RLM (Reasoning & Learning Machine)—a Python environment where variables, imports, and async tasks survive across multiple agent turns. This implementation lives in the PrimeIntellect-ai/prime-agent repository and powers the agent's ability to execute Python, run shell commands via %%bash magic, and maintain computational state.

Core Architecture: Three Integration Layers

The IPython integration is split across three coordinated systems:

Layer Responsibility Primary Source File
Tool Definition Registers the ipython tool, handles execution flow, error recovery, and result packaging [packages/coding-agent/src/core/tools/ipython.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/tools/ipython.ts)
Kernel Provisioner Lazily creates, starts, restores, and disposes KernelManager instances per session [packages/coding-agent/src/core/tools/ipython.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/tools/ipython.ts) (class IpythonKernelProvisioner)
UI Component Renders cells with streaming output, image attachments, diffs, and status indicators [packages/coding-agent/src/modes/interactive/components/ipython-cell.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/interactive/components/ipython-cell.ts)

Kernel Lifecycle and Bootstrap Process

Lazy Initialization with ensure()

The IpythonKernelProvisioner class guarantees exactly one kernel per agent session. The first tool invocation triggers ensure(), which:

  1. Spawns a KernelManager from [packages/coding-agent/src/kernel/index.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/kernel/index.ts)
  2. Restores state from snapshotDir if configured (via restoreState())
  3. Executes bootstrap code to configure the environment

Bootstrap Code Injection

The kernel receives RLM_BOOTSTRAP_BASE_CODE (lines 24–38 in ipython.ts) on every fresh start:


# Simplified representation of RLM_BOOTSTRAP_BASE_CODE

import nest_asyncio
nest_asyncio.apply()  # Enable nested event loops

# Disable colored output for clean TUI rendering

%colors NoColor

# Attempt to import the RLM runtime

try:
    import rlm
except ImportError:
    pass

For sessions with custom Python skills, buildRlmBootstrapCode (lines 70–84) extends this base with dynamic imports:

// From packages/coding-agent/src/core/tools/ipython.ts
function buildRlmBootstrapCode(skills: PythonSkill[]): string {
  const imports = skills.map(s => `import ${s.module}`).join('\n');
  return `${RLM_BOOTSTRAP_BASE_CODE}\n${imports}\n${RLM_RUNTIME_CODE}`;
}

Execution Flow: From Model Request to Result

Step 1: Tool Registration

// Register the ipython tool at agent initialization
import { createIpythonTool } from "@prime-agent/coding-agent";

const ipythonTool = createIpythonTool(process.cwd(), {
  python: "python3",                           // Custom interpreter path
  snapshotDir: "~/.prime/agent/ipython",       // Persist namespace across restarts
  skills: [{ module: "pandas" }, { module: "numpy" }]  // Auto-import skills
});

agent.registerTool(ipythonTool);

Step 2: Model Invocation

When the model requests code execution:

// Automatic invocation when model calls tool
await agent.invokeTool("ipython", { 
  code: "import numpy as np; np.arange(5).tolist()" 
});

Step 3: Shell Magic Transformation

For %%bash cells, applyShellSettingsToBashMagicCell (lines 99–119) rewrites the source:

// Before: %%bash\necho $HOME
// After:  %%bash\nexport HOME=/explicit/path; echo $HOME
const transformed = applyShellSettingsToBashMagicCell(rawCode, {
  shellCmd: "/bin/bash",
  env: { PATH: "/usr/local/bin" }
});

Step 4: Kernel Execution with Busy-Handling

The executeWithBusyKernelChoice function handles concurrent execution attempts:

  • Wait: Queue until prior cell completes
  • Kill: Restart kernel, losing state but freeing executor
  • Cancel: Abort without execution

Killing inserts KERNEL_RESTART_NOTICE into output to alert the model.

Step 5: Result Packaging

createIpythonToolDefinition assembles a ToolResult containing:

interface ToolResult {
  content: Array<TextContent | ImageContent>;  // stdout + images
  isError: boolean;                            // Execution status
  details: {
    executionTimeMs: number;
    diff?: string;                             // File modifications
    attachments: Map<string, Buffer>;          // Generated images
  };
}

Image extraction uses IMAGE_MIME_TYPES from [packages/coding-agent/src/utils/mime.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/utils/mime.ts):

const IMAGE_MIME_TYPES = [
  'image/png',
  'image/jpeg',
  'image/svg+xml',
  'image/gif'
];

State Persistence and Recovery

Snapshot Directory Structure

When snapshotDir is provided:


~/.prime/agent/ipython/
├── namespace.pickle          # Serialized globals

├── history.jsonl             # Execution history

└── attachments/              # Saved plots/images

    ├── plot_001.png
    └── chart_002.svg

Restore on Boot

// Inside IpythonKernelProvisioner.ensure()
if (this.snapshotDir && fs.existsSync(this.snapshotDir)) {
  await this.kernelManager.restoreState(this.snapshotDir);
  reportStartupProgress({ phase: 'restored', elapsedMs: Date.now() - start });
}

This enables long-running computational sessions—a data analysis pipeline can survive agent restarts with dataframes and trained models intact.

Terminal UI Rendering

The IPythonCellComponent transforms kernel output into rich terminal displays:

// Simplified usage from ipython-cell.ts
import { IPythonCellComponent } from "./ipython-cell";

const component = new IPythonCellComponent({
  code: codeString,
  result: toolResult,
  executionStarted: timestamp,
  isPartial: false,  // True for streaming output
  diff: fileDiff,    // Optional file change visualization
});

const lines = component.render(terminalWidth);
// Returns formatted lines with ANSI styling, image placeholders, status icons

Key rendering features:

  • Streaming output: Real-time stdout/stderr updates via isPartial
  • Image display: Terminal-compatible representations (sixel, kitty graphics, or placeholders)
  • Diff blocks: Side-by-side or inline file modifications
  • Status icons: ⏳ running, ✅ completed, 🔄 restarted, ❌ error

Key Source Files Reference

File Lines of Interest Purpose
packages/coding-agent/src/core/tools/ipython.ts 1–400+ Tool definition, provisioner, bootstrap, execution
packages/coding-agent/src/core/tools/ipython-cell-code.ts parse functions %%bash magic parsing
packages/coding-agent/src/kernel/index.ts KernelManager class ZMQ process management, execute(), listNamespaceNames()
packages/coding-agent/src/utils/mime.ts IMAGE_MIME_TYPES Output type filtering
packages/coding-agent/src/modes/interactive/components/ipython-cell.ts Render methods TUI component implementation

Summary

  • Prime Agent's IPython kernel integration centers on createIpythonToolDefinition in ipython.ts, which bridges the model's tool calls to a persistent notebook environment.
  • The IpythonKernelProvisioner handles lazy boot, state restore from snapshotDir, and graceful degradation when kernels hang or crash.
  • Bootstrap code injection (RLM_BOOTSTRAP_BASE_CODE + buildRlmBootstrapCode) prepares a reproducible execution environment with nest_asyncio, disabled colors, and requested skill imports.
  • Shell magic rewriting ensures %%bash cells execute with consistent environment settings.
  • Rich terminal output via IPythonCellComponent delivers images, diffs, and streaming execution status to the user.

Frequently Asked Questions

How does Prime Agent handle kernel crashes during execution?

The executeWithBusyKernelChoice function detects unresponsive kernels and presents three options: wait for completion, force-kill and restart, or cancel the request. Killing triggers KERNEL_RESTART_NOTICE insertion so the model understands state was reset. The provisioner then spawns a fresh KernelManager instance.

Can the IPython kernel persist variables between agent sessions?

Yes. When snapshotDir is configured, the provisioner calls restoreState() on boot to reload pickled namespace data. Variables, imports, and defined functions survive agent restarts. The bootstrap code re-executes after restoration to ensure environment consistency.

What image formats does Prime Agent support from kernel output?

According to [packages/coding-agent/src/utils/mime.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/utils/mime.ts), the system recognizes PNG, JPEG, SVG, and GIF attachments. These are extracted from kernel messages and rendered in the terminal UI via imageBlocksFromAttachments in the tool result handler.

How does Prime Agent prevent kernel state pollution between unrelated tasks?

Each agent session receives exactly one KernelManager via the provisioner's singleton pattern. For complete isolation, users can configure separate snapshotDir paths per workflow or omit persistence entirely. The busy-kernel handler also allows intentional state reset through kernel restart when execution context drifts.

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 →