@florianguyonnet/pi-rlm

Recursive Language Models for pi: a persistent Python REPL with rlm() sub-agent recursion, as a single extension

Packages

Package details

extension

Install @florianguyonnet/pi-rlm from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@florianguyonnet/pi-rlm
Package
@florianguyonnet/pi-rlm
Version
0.2.0
Published
Aug 9, 2026
Downloads
182/mo · 13/wk
Author
florianguyonnet
License
MIT
Types
extension
Size
79.1 KB
Dependencies
0 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-rlm

Recursive Language Models for pi — as a single extension, no fork required.

The agent gets one tool, ipython: a persistent Python REPL whose namespace doubles as long-term memory. Inside that namespace lives rlm(prompt, context=None), which spawns a recursive sub-agent (a fresh pi process with its own clean context window) and returns its answer as a plain Python string. Because sub-results land in REPL variables instead of the conversation, the agent can fan out over far more text than fits in its own context window.

This is a port of the RLM capabilities of prime-agent (which vendors a whole pi fork to get them) onto pi's public extension API — including the namespace snapshot and the continual harness (/refine).

pi  ── ipython tool ──► KernelProcess (src/kernel.ts)
                            │  unix socket, JSONL
                            ▼
                     rlm_kernel.py  ← persistent namespace (stdlib only)
                            │  rlm("summarize", context=chunk)
                            ▼
                     child pi -e pi-rlm --rlm   (src/child.ts)
                            │  PI_RLM_DEPTH + 1, may recurse further
                            ▼
                     answer returns as a Python string

Install

pi install npm:@florianguyonnet/pi-rlm            # from npm (scoped: the bare `pi-rlm` name is taken)
pi install git:github.com/florianguyonnet/pi-rlm  # from git
pi install /path/to/pi-rlm                        # local checkout
pi -e /path/to/pi-rlm/src/index.ts                # one-shot, no install

Requires Python 3 on PATH (stdlib only — no venv, no pip install). Override with PI_RLM_PYTHON.

Usage

RLM mode — the pure REPL agent. Active tools collapse to ipython only and the system prompt is replaced with the RLM prompt:

pi --rlm "Summarize each chapter of @huge.log and reconcile the totals"

or toggle it mid-session with /rlm. Toggle off to restore the full toolset (ipython stays available).

Light mode — with the extension installed but RLM mode off, ipython + rlm() sit alongside pi's normal tools, and a short addendum documents them.

Inside the kernel:

text = open("huge.log").read()          # big data stays in the REPL
chunks = [text[i:i+50_000] for i in range(0, len(text), 50_000)]
notes = [rlm("Summarize this chunk, keep all numbers", context=c) for c in chunks]
len(notes), sum(len(n) for n in notes)  # repr of trailing expr is returned

user_prompt (the current user request) is injected into the namespace before each turn.

Namespace snapshots

When the session ends, picklable data variables are pickled to ~/.pi/agent/pi-rlm/snapshots/<session-id>.pickle; resuming the session restores them at kernel boot (functions, classes and modules are skipped — re-define those). /new starts fresh, /rlm restart wipes on purpose, ephemeral sessions (--no-session) skip persistence. Snapshots older than 30 days are garbage-collected.

Continual harness (/refine)

pi-rlm ports prime-agent's refinement loop: persistent memories (reusable facts/tactics) and policies (behavior notes) that are injected into the system prompt on every turn.

/refine list                              # show current entries
/refine prefer small diffs over rewrites  # refine now, session-scoped
/refine global always verify with tests   # refine now, cross-session

From inside the kernel: refine("create a memory about X", global_=True) — returns immediately, the refinement runs when the turn settles (never mid-cell).

A refinement spawns a tool-less child LLM that analyzes the recent trajectory and applies structured edits (create/update/delete). Local entries live in the pi session (survive /resume, branch with the session tree); global entries live in ~/.pi/agent/pi-rlm/harness.jsonl.

Recursion depth

Root agent = depth 0; each rlm() child is parent depth + 1. Requests beyond the budget are refused in-kernel (rlm() raises, the model adapts). Default max depth: 2.

Where How
per session /rlm depth 3
per launch pi --rlm --rlm-max-depth 3
environment PI_RLM_MAX_DEPTH=3 (0 disables recursion)

Commands & flags

Command Effect
/rlm toggle RLM mode (persisted in the session)
/rlm status mode, depth, model for children, kernel stats
/rlm restart kill the kernel (next cell reboots with an empty namespace)
/rlm depth <n> session-scoped recursion budget
/refine [global] [instructions] run a harness refinement now
/refine list show harness entries
--rlm start in RLM mode
--rlm-max-depth <n> launch-scoped recursion budget

Design notes

  • No ipykernel, no ZeroMQ. The extension owns both ends of a unix socket; the shim is ~250 lines of stdlib Python. Kernel boot is one python3 spawn, lazily on the first cell.
  • Cells are serialized; stream messages mirror stdout/stderr live to the tool row. Esc sends SIGINT (a KeyboardInterrupt traceback, kernel survives); a grace timer escalates to SIGKILL and the next cell reboots with a fresh namespace.
  • Sub-agents are child pi processes (--mode json -p --no-session --no-extensions -e <this extension> --rlm), the pattern from pi's subagent example. They inherit the session's model and may recurse until the depth budget runs out.
  • Nested usage accounting: child token/cost totals roll up onto the ipython tool result, so footer and /session totals include recursion.
  • Compaction: the kernel survives it; pi-rlm injects a namespace snapshot (variable names/types) after compaction so the model doesn't lose track of REPL state.
  • Snapshots: data survives restarts too — the namespace is pickled per session at shutdown and restored on resume.
  • rlm() results never enter the parent's context — only what cells print. That's the context-engineering point of RLM, and it falls out of the socket design for free.
  • Need packages? The kernel is stdlib-only by design, but nothing stops a cell from import subprocess; subprocess.run([sys.executable, "-m", "pip", "install", "--user", "pandas"]). A managed venv is deliberately out of scope.

What a fork still gets you (and this doesn't)

Honest list, for the prime-agent comparison: child sessions don't appear in pi's /tree or parent accounting UI (we roll usage up manually instead); no fork-server, so each child pays Python + pi cold start; child registry doesn't survive a daemon restart; per-cell cancellation is SIGINT-based and can't interrupt a blocked C call; harness entries cover memories/policies only (no skill/subagent kinds, no rollback history).

Development

npm install          # peers (pi packages) resolve for the typechecker
npm test             # LLM-free kernel protocol smoke test (python3)
npm run typecheck    # tsc --noEmit

End-to-end probes (uses your configured model):

pi -e ./src/index.ts -p --no-session "Use ipython twice: x = sum of squares 0..9, then x*2. Reply with the number."
PI_RLM_MAX_DEPTH=0 pi -e ./src/index.ts --rlm -p --no-session "Try rlm('hi'), tell me what happens"

Releasing

GitHub Actions publishes to npm on version tags (requires the NPM_TOKEN repository secret):

npm version patch        # bumps package.json, commits, tags vX.Y.Z
git push --follow-tags   # the tag triggers the publish workflow

Acknowledgments

  • Recursive Language Models — the RLM concept (Zhang et al.).
  • prime-agent (MIT, © Prime Intellect) — the product this ports to pi's extension API. pi-rlm reimplements the mechanism from scratch (different kernel architecture, rewritten prompts, own refinement store); no prime-agent code is copied.
  • pi (MIT, © Mario Zechner) — the platform; the child-process spawn pattern comes from pi's subagent example extension.

License

MIT