Python kernel
RLM mode: a persistent Python interpreter on the tool belt. State survives between calls, IPython when available, opt-in and off by default.
Copy & share
Loading sections…
Connect MCP or install the Empryo skillSection exports contain only that heading’s content. Markdown and text links fetch the selected content directly, without the rest of the page.
python_kernel is one Python interpreter, alive for as long as your workspace is. A variable bound in one call is still bound in the next.
That is the whole difference from shell. Every python -c is a fresh process, so a script that loads a dataframe pays for the load again on every question asked about it — and the agent has to re-derive its own context each time. With a kernel the agent loads once and interrogates across a whole turn:
python_kernel(code: "import pandas as pd; df = pd.read_csv('sales.csv'); df.shape")
→ (48211, 17)
python_kernel(code: "df.groupby('region').revenue.sum().sort_values().tail(3)")
→ region
EMEA 1840221.55
APAC 2110984.10
NA 3922015.77The second call never re-read the file.
Turning it on
Off by default. It executes arbitrary code with your privileges, which is the same power shell has, so it waits to be asked:
"agentFeatures": { "pythonKernel": true }- TUI —
/agent-features→ Python Kernel - Desktop — Settings → Router → Behaviors → Python kernel
- One run —
EMPRYO_PYTHON_KERNEL=1 empryo --headless "…"
Requires python3 on PATH. Without one the tool is not added to the belt at all, so a model never offers to use something that cannot run.
Parameters
| Field | Type | What it does |
|---|---|---|
code | string | Python to run. The last expression's value comes back, like a REPL |
reset | boolean | Clear every variable first (or on its own, to clear and stop) |
timeoutMs | number | Give up after this many ms — default 120000, max 600000 |
Returns stdout, stderr and the value of the last expression. An exception comes back as a failure with the traceback, and the interpreter stays alive.
Behaviour worth knowing
- IPython when it is importable — rich reprs,
display,_. Plain CPython
otherwise; nothing to install either way.
- One kernel per workspace. Two tabs in the same repo share their globals,
which is the point: the state belongs to the work, not to the chat lane.
- cwd is the workspace root, so relative paths mean what they look like.
- A runaway loop is killed at the timeout and the kernel restarts, rather
than the turn hanging. The reply says so — the variables are gone with it.
- Not a Jupyter client. The protocol is JSON over the child's own stdio, so
there is no jupyter_client, no ZMQ, and nothing to install before the first call works.
When not to use it
Reach for shell for one-shot commands (pytest, ruff, a script you already have) — a kernel buys nothing there and costs you a process that outlives the call. Reach for project for lint/typecheck/test, which already know your toolchain. The kernel earns its place when step N+1 depends on what step N left in memory.