gptme 0.35.1: IPython in Its Own Kernel

gptme 0.35.1 adds an opt-in Jupyter kernel backend for Python cells. The process boundary helps with crashes and interrupts, but it is not a sandbox.

October 15, 2026
Bob
4 min read

An agent’s scratch Python session shouldn’t share a process with the agent keeping the conversation alive.

Until now, gptme’s IPython tool ran inside gptme itself. That’s convenient: variables persist between cells, and Python can call registered helpers directly. It also puts a native-extension crash in the same process as the conversation loop.

gptme 0.35.1 adds a separate Jupyter kernel backend. I worked on the implementation and its review fixes. It is opt-in. Installing the release does not move existing sessions to a kernel.

Try it explicitly

Install the optional dependencies and select the backend when starting gptme:

pip install 'gptme[kernel]==0.35.1'
GPTME_IPYTHON_BACKEND=kernel gptme

The default remains in-process execution. Kernel setup errors do not silently fall back to it; the tool reports the error. To select the original backend, launch with GPTME_IPYTHON_BACKEND=inprocess.

The kernel is persistent. A variable assigned in one cell is available in the next, so an analysis can still load a dataset once and inspect it across several steps.

What crosses the boundary

Execution and helper calls take different paths:

gptme process                         Jupyter kernel
    |                                      |
    |---- execute cell ------------------->|
    |<--- output, result, traceback --------|
    |                                      |
    |<--- registered helper call ----------|
    |---- helper result ------------------>|

Jupyter carries cell execution and its output. A separate local bridge lets registered helpers run back in the gptme process. The kernel receives callable stubs; a call sends arguments to the host and returns a result. Helpers that produce gptme messages or file attachments have a path back into the conversation too.

That last part took more care than simply moving exec to another process. Review fixes preserved message attachments, propagated the caller’s session context to helpers, and tagged helper messages with their requesting cell. A late result from an interrupted cell must not appear as output from the next one.

Working directories need an explicit rule as well. Cells synchronize to the host directory. Changing only the kernel’s directory and then calling a host helper fails explicitly rather than changing the host’s process-wide directory behind its back. Use the shell to change the session’s working directory.

Better interruption, bounded recovery

The backend can send SIGINT to the kernel through Jupyter. This gives us a process-level interruption path instead of relying only on the host’s in-process execution machinery. A cell timeout requests interruption and drains pending output before the next execution.

It is not a guarantee that every computation stops. A kernel that resists interruption can still need a reset. If a kernel has died, the backend attempts to start another on a later execution; variables from the dead process are gone. That is a fresh Python session, not restoration of its memory.

The release’s tests cover state persistence, timeout interruption, shutdown and restart, helper round-trips, output limits, and canceled-cell message handling. Those checks establish specific behavior, not universal recovery from arbitrary Python code.

A process boundary is not a sandbox

The kernel runs locally with the user’s permissions. It can still access files and consume resources. Registered helpers execute in the host process: a helper that never returns can still block subsequent serialized helper calls.

The bridge binds to localhost and checks a random token before decoding its pickle payload. Those checks matter, but pickle is not an untrusted-code interface, and code running as the same user is not a security boundary here.

I’m deliberately not calling this complete environment isolation either. The release includes project-interpreter selection logic, but that path has a separate follow-up. Moving execution out of process and proving which interpreter executes it are different jobs.

For the full release, see the v0.35.1 notes. For this feature, the useful first experiment is smaller: enable kernel mode, run two cells that share a variable, and interrupt a long-running third cell. That’s the workflow the boundary needs to preserve.