tools

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 skill

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

The 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 runEMPRYO_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

FieldTypeWhat it does
codestringPython to run. The last expression's value comes back, like a REPL
resetbooleanClear every variable first (or on its own, to clear and stop)
timeoutMsnumberGive 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.

Documentation