# How the RLM Runtime Handles Persistent IPython State Across Turns in Prime Agent

> Discover how Prime Agent’s RLM runtime uses a JSON harness to maintain persistent IPython state across turns, ensuring continuity and reliable interaction.

- Repository: [Prime Intellect/prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
- Tags: internals
- Published: 2026-08-09

---

**Prime Agent’s RLM kernel maintains IPython continuity across recursive turns by persisting session data in a JSON-backed harness that reloads from disk on every interaction.**

The PrimeIntellect-ai/prime-agent repository implements a deterministic state management layer that allows Python-based skills to survive between `/refine` calls. Unlike standard Jupyter kernels that reset between executions, the RLM runtime handles persistent IPython state across turns by leveraging a file-backed architecture centered in the harness subsystem.

## The Harness Architecture

The persistence mechanism relies on two core components: the kernel shim that interfaces with IPython and the harness manager that handles serialization.

### Kernel Initialization and IPython Integration

In [`prime-agent-runtime/src/rlm/__init__.py`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/prime-agent-runtime/src/rlm/__init__.py), the runtime imports `IPython.get_ipython` when a Jupyter kernel is detected. This module registers Jupyter comm handlers, enabling Python-based skills to communicate bidirectionally with the host process. This integration allows the RLM runtime to manipulate the IPython namespace directly while maintaining the session context required for multi-turn conversations.

### HarnessState Storage Location

The [`prime-agent-runtime/src/rlm/harness.py`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/prime-agent-runtime/src/rlm/harness.py) file implements the `get_harness_state()` function, which resolves storage paths through a hierarchy of environment variables. The resolution order is:

- `RLM_HARNESS_STATE_DIR`
- `RLM_GLOBAL_HARNESS_STATE_DIR`
- `RLM_SESSION_DIR`

If none are set, the system falls back to `~/.prime/agent/harness/harness_state.json` (lines 78-90). This deterministic path resolution ensures that state remains accessible regardless of how the agent process was launched.

## Disk Synchronization Across Turns

To prevent state loss during recursive agent calls, the harness implements an aggressive synchronization strategy that treats the JSON file as the single source of truth.

### The `_sync_from_disk()` Mechanism

Every turn triggers `_sync_from_disk()` before any read or write operations occur. The constructor invokes `load()` immediately upon instantiation, ensuring the in-memory representation reflects the latest disk state. This design accommodates external modifications made by the host process, such as when the `/refine` command updates the harness between turns.

### Mtime-Based Cache Invalidation

The system monitors file modification timestamps to avoid unnecessary reloads. When the on-disk mtime differs from the cached value, the runtime refreshes the in-memory snapshot (lines 86-95). This optimization balances performance with consistency, ensuring that concurrent edits or parent agent updates propagate correctly to child processes.

## Storing IPython State in Memory Entries

The `HarnessState` object organizes data into a dictionary keyed by `HarnessKind`, with valid types including `"prompt"`, `"memory"`, `"skill"`, and `"subagent"`. The `"memory"` kind specifically handles arbitrary Python objects, making it the vehicle for IPython session persistence.

### Persisting Global Variables

Skills upsert memory entries to store namespace data between turns. The following pattern captures the current IPython globals:

```python
from prime_agent_runtime.rlm import get_harness_state

h = get_harness_state()
h.upsert(
    kind="memory",
    title="IPython globals",
    content="Persisted IPython globals",
    id="ipython_state",
    reference={"type": "python", "import": "builtins", "callable": "globals"},
)

```

### Restoring Session Context

On subsequent turns, skills retrieve the stored entry and re-inject values into the running kernel:

```python
from prime_agent_runtime.rlm import get_harness_state, get_ipython

h = get_harness_state()
entry = h.entries["memory"].get("ipython_state")
if entry:
    ip = get_ipython()
    if ip:
        # Restore saved globals into current namespace

        ip.user_ns.update(entry.reference["callable"]())

```

## Practical State Management Examples

### Saving Variables Between Executions

To persist a specific variable across turns:

```python

# ---------- Example: Persisting a variable ----------

from prime_agent_runtime.rlm import get_harness_state

state = get_harness_state()
state.upsert(
    kind="memory",
    title="my_var",
    content="value of my_var",
    id="my_var",
    reference={"type": "python", "import": "builtins", "callable": "repr"},
    arguments={"value": 42},
)

```

### Recovering State in Later Turns

To restore that variable in a future execution:

```python

# ---------- Example: Restoring the variable in a later turn ----------

from prime_agent_runtime.rlm import get_harness_state, get_ipython

h = get_harness_state()
entry = h.entries["memory"].get("my_var")
if entry:
    ip = get_ipython()
    if ip:
        ip.user_ns["my_var"] = entry.arguments["value"]

```

## Summary

- **File-backed persistence**: The RLM runtime stores state in [`harness_state.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/harness_state.json), located via environment variables or a default path in the user's home directory.
- **Cross-turn synchronization**: The `_sync_from_disk()` method and mtime checking ensure fresh state on every turn, supporting concurrent modifications by parent agents.
- **Memory entry system**: Python objects persist through `"memory"` kind entries in the `HarnessState`, allowing skills to save and restore arbitrary data.
- **IPython integration**: The kernel shim in [`__init__.py`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/__init__.py) provides direct access to `get_ipython()`, enabling namespace manipulation for true session continuity.

## Frequently Asked Questions

### Where does Prime Agent store the persistent harness state?

The runtime resolves the storage location through the environment variables `RLM_HARNESS_STATE_DIR`, `RLM_GLOBAL_HARNESS_STATE_DIR`, or `RLM_SESSION_DIR`, defaulting to `~/.prime/agent/harness/harness_state.json` if none are configured. This path is determined in [`prime-agent-runtime/src/rlm/harness.py`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/prime-agent-runtime/src/rlm/harness.py) during `HarnessState` initialization.

### How does the RLM runtime detect external changes to the state file?

Before every read or write operation, the harness calls `_sync_from_disk()` to compare the cached modification time against the filesystem mtime. If they differ, the runtime reloads the JSON content into memory, ensuring that changes made by the `/refine` command or parent processes are immediately visible.

### What types of data can be stored in the harness "memory" entries?

The `"memory"` kind accepts arbitrary Python objects, including dictionaries, lists, and serialized representations of IPython globals. Skills store data by calling `upsert()` with a unique ID, then retrieve it via `h.entries["memory"][id]` in future turns, effectively creating a persistent key-value store for the session.

### Does the IPython integration require a running Jupyter kernel?

While [`prime-agent-runtime/src/rlm/__init__.py`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/prime-agent-runtime/src/rlm/__init__.py) attempts to import `IPython.get_ipython` and register comm handlers, the harness system functions independently. Skills can persist state to disk even without an active Jupyter kernel, though the ability to manipulate `ip.user_ns` requires the IPython environment to be present.