@moontrain/pi-py-exec

pi extension: persistent Python kernel with an isolated uv-managed venv and automatic dependency installation

Packages

Package details

extension

Install @moontrain/pi-py-exec from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@moontrain/pi-py-exec
Package
@moontrain/pi-py-exec
Version
0.1.0
Published
Aug 18, 2026
Downloads
165/mo · 17/wk
Author
moontrain
License
MIT
Types
extension
Size
39.8 KB
Dependencies
0 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "./extensions/py-exec.ts"
  ]
}

Security note

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

README

@moontrain/pi-py-exec

npm License: MIT

A pi extension that gives the agent a persistent Python kernel. Variables, imports, and function definitions survive between calls, the last expression comes back automatically like a REPL, and missing packages install themselves.

The kernel lives in a virtualenv that pi owns. It never touches your system Python and never touches your project's venv.

Install

pi install npm:@moontrain/pi-py-exec

Or try it for one run: pi -e npm:@moontrain/pi-py-exec

Why

The default move for an agent doing quick Python is bash python3 -c "...". Every call is a fresh interpreter: the 400 MB dataframe you just parsed is gone, the import cost is paid again, and any intermediate state has to be re-derived or serialized to disk.

With a persistent kernel the agent loads data once and keeps querying it:

# call 1
import pandas as pd
df = pd.read_csv("sales.csv")
len(df)
# [result] 128394

# call 2 — df is still there
df.groupby("region")["revenue"].sum().sort_values(ascending=False).head()

The py_exec tool

Action Purpose
run (default) Execute code in the kernel
install Install packages into the kernel environment
reset Clear kernel state without restarting the process
status Report interpreter, version, PID, and kernel health

Parameters

Name Type Default Description
action "run" | "install" | "reset" | "status" "run" What to do.
code string Python source, for action: "run".
packages string[] Specs for action: "install", e.g. ["pandas", "requests>=2"].
auto_install boolean true On ModuleNotFoundError, install the missing package and retry once.
timeout number 30 Seconds. Maximum 300.

REPL semantics

The value of the final expression is returned as [result] and bound to _. Use print() for anything else. Output is capped at 50,000 characters.

The /py command

/py status              interpreter, version, PID, kernel health
/py reset               clear kernel state, keep the process
/py restart             kill and respawn the kernel
/py install <pkgs...>   install into the kernel environment
/py guard [on|off]      toggle the inline-python bash guard

The Python environment

On first use the extension creates a virtualenv at ~/.pi/agent/py_exec/venv with uv, based on a uv-downloaded standalone interpreter. Nothing is installed into your system Python and nothing leaks in from it.

Variable Default Effect
PI_PYTHON Force a specific interpreter path. Skips uv entirely.
PI_PYTHON_VERSION 3.12 Python version uv provisions for the venv.
PI_PYTHON_PREFERENCE only-managed Passed to uv --python-preference.
PI_PY_EXEC_GUARD on Set to 0, off, or false to disable the bash guard.

If uv is not installed at all, the extension falls back to the first working python3 / python / py on PATH. Everything still works; you just lose the isolation guarantee and get whatever version that interpreter is.

Auto-install maps common import names to their PyPI package names, so import cv2 installs opencv-python, import PIL installs pillow, import sklearn installs scikit-learn, and so on.

The inline-python bash guard

The extension watches bash tool calls and blocks bare inline Python — a whole-command python -c '...' or python <<EOF — with a message pointing the agent at py_exec.

It is deliberately narrow. It only fires on a self-contained inline script with a bare interpreter name, optionally prefixed by cd X &&. These stay unblocked:

  1. Project venv./.venv/bin/python -c '...' (path interpreter, not a bare name)
  2. Long jobs over the 300 s cap
  3. Existing scriptspython script.py is never blocked
  4. Shell integration — anything with pipes, && chains, or redirection

The block is a nudge, not a wall: re-running the same command succeeds. Turn it off permanently with /py guard off or PI_PY_EXEC_GUARD=0.

How it works

The kernel is a stdlib-only Python script embedded in the extension, written to a temp file and spawned as python -u -X utf8. It speaks NDJSON over stdin/stdout with requests matched by id. There are no Python dependencies to install before the kernel can start.

A timeout or cancellation kills and respawns the kernel — state is lost, and the error message says so explicitly rather than silently returning stale results. Windows kills via taskkill /T /F.

The kernel's working directory is fixed at first use. Call os.chdir() inside your code to move it.

Security

py_exec executes arbitrary Python with your user's permissions, the same as the bash tool. The venv isolates dependencies, not capabilities — code in the kernel can read and write any file you can. Review what you run.

License

MIT © Moontrain Technologies