clikernel gives an LLM agent a persistent Python workbench built from two processes. A jupygate server runs all the time and hosts real Jupyter kernels (ipymini by default); kernels live there and persist until explicitly stopped. clikernel itself starts and stops with each conversation: a small translator the MCP host launches, speaking MCP to the model and the Jupyter kernels API to the gateway. Outputs come back as concise text — a bare 42 for a single result, tagged sections for several, tracebacks ANSI-stripped and capped.
Because kernels outlive conversations, an agent can connect back to yesterday’s kernel (or the user’s live solveit kernel) and find its state intact — and because nothing is ever stopped implicitly, the only way a kernel dies is an explicit stop_kernel. Creating a kernel runs the user’s startup.py and installs their inspectors.py cell-checking rules, delivered as source so remote kernels get the same setup as local ones.
pip install clikernelPlus the resident side: jupygate and a kernel (ipymini by default). Start the gateway (and keep it running, e.g. via launchd/systemd):
jupygate --port 8787Register the stdio server with your MCP host, e.g. for Claude Code:
claude mcp add clikernel -- clikernel-mcpThe tools mirror jupygate’s kernel API plus one composite: connect (create a fresh kernel — running startup.py and installing inspectors — or attach to an existing one by id), execute (run code, get concise text), list_kernels, stop_kernel, restart, and interrupt. Nothing happens until the model calls connect, and nothing is ever stopped except by stop_kernel — a later conversation reattaches to a kernel by id and continues where the last one stopped. $CLIKERNEL_HOST overrides the default gateway (http://127.0.0.1:8787).
Three optional files in $XDG_CONFIG_HOME/clikernel/ (usually ~/.config/clikernel/):
startup.py— run in every kernel clikernel creates, with__file__bound to its path; its output returns as part of theconnectreply.inspectors.py— cell inspectors installed after startup. The file may defineinspectand/or a listinspectors; each is called once per cell before it runs (1-arg: the cell’s AST; 2-arg: AST and raw source). Return a string to print a note before the cell’s output, raiseRuleBlock(provided in the namespace) to block the cell; any other exception warns and the cell runs. Seeexamples/inspectors.py.gateways.toml— named remote gateways, so tokens never appear in tool arguments:
[gateways.solveit]
url = "https://solveit.example.com/gate"
token_env = "SOLVEIT_TOKEN"Run clikernel as a plain CLI process and the same client speaks a delimiter-framed stdin/stdout protocol for token-reading clients: no echo, a cheap . acknowledgement per request, responses ended by a per-process random delimiter, multiline cells framed by -- and the delimiter. The full recipe is announced in the process’s own startup banner. Run bare it creates a kernel and stops it on exit; --kernel <id> attaches to an existing kernel and leaves it as found.