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.
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.