Python Tool and IPython Runtime
This document describes the current Python execution stack in packages/coding-agent. It covers tool behavior, kernel/gateway lifecycle, environment handling, execution semantics, output rendering, and operational failure modes.
Scope and Key Files
- Tool surface:
src/tools/python.ts - Session/per-call kernel orchestration:
src/ipy/executor.ts - Kernel protocol + gateway integration:
src/ipy/kernel.ts - Shared local gateway coordinator:
src/ipy/gateway-coordinator.ts - Interactive-mode renderer for user-triggered Python runs:
src/modes/components/python-execution.ts - Runtime/env filtering and Python resolution:
src/ipy/runtime.ts
What the Python tool is
The python tool executes one or more Python cells through a Jupyter Kernel Gateway-backed kernel (not by spawning python -c directly per cell).
Tool params:
{
cells: Array<{ code: string; title?: string }>;
timeout?: number; // seconds, clamped to 1..600, default 30
cwd?: string;
reset?: boolean; // reset kernel before first cell only
}The tool is concurrency = "exclusive" for a session, so calls do not overlap.
Gateway lifecycle
Modes
There are two gateway paths:
External gateway (
PI_PYTHON_GATEWAY_URLset)- Uses the configured URL directly.
- Optional auth with
PI_PYTHON_GATEWAY_TOKEN. - No local gateway process is spawned or managed.
Local shared gateway (default path)
- Uses a single shared process coordinated under
~/.pisces/agent/python-gateway. - Metadata file:
gateway.json - Lock file:
gateway.lock - Spawn command:
python -m kernel_gateway- bound to
127.0.0.1:<allocated-port> - startup health check:
GET /api/kernelspecs
- Uses a single shared process coordinated under
Local shared gateway coordination
acquireSharedGateway():
- Takes a file lock (
gateway.lock) with heartbeat. - Reuses
gateway.jsonif PID is alive and health check passes. - Cleans stale info/PIDs when needed.
- Starts a new gateway when no healthy one exists.
releaseSharedGateway() is currently a no-op (kernel shutdown does not tear down shared gateway).
shutdownSharedGateway() explicitly terminates the shared process and clears gateway metadata.
Important constraint
python.sharedGateway=false is rejected at kernel start:
- Error:
Shared Python gateway required; local gateways are disabled - There is no per-process non-shared local gateway mode.
Kernel lifecycle
Each execution uses a kernel created via POST /api/kernels on the selected gateway.
Kernel startup sequence:
- Availability check (
checkPythonKernelAvailability) - Create kernel (
/api/kernels) - Open websocket (
/api/kernels/:id/channels) - Initialize kernel env (
cwd, env vars,sys.path) - Execute
PYTHON_PRELUDE - Load extension modules from:
- user:
~/.pisces/agent/modules/*.py - project:
<cwd>/.pisces/modules/*.py(overrides same-name user module)
- user:
Kernel shutdown:
- Deletes remote kernel via
DELETE /api/kernels/:id - Closes websocket
- Calls shared gateway release hook (no-op today)
Session persistence semantics
python.kernelMode controls kernel reuse:
session(default)- Reuses kernel sessions keyed by session identity + cwd.
- Execution is serialized per session via a queue.
- Idle sessions are evicted after 5 minutes.
- At most 4 sessions; oldest is evicted on overflow.
- Heartbeat checks detect dead kernels.
- Auto-restart allowed once; repeated crash => hard failure.
per-call- Creates a fresh kernel for each execute request.
- Shuts kernel down after the request.
- No cross-call state persistence.
Multi-cell behavior in a single tool call
Cells run sequentially in the same kernel instance for that tool call.
If an intermediate cell fails:
- Earlier cell state remains in memory.
- Tool returns a targeted error indicating which cell failed.
- Later cells are not executed.
reset=true only applies to the first cell execution in that call.
Environment filtering and runtime resolution
Environment is filtered before launching gateway/kernel runtime:
- Allowlist includes core vars like
PATH,HOME, locale vars,VIRTUAL_ENV,PYTHONPATH, etc. - Allow-prefixes:
LC_,XDG_,PI_ - Denylist strips common API keys (OpenAI/Anthropic/Gemini/etc.)
Runtime selection order:
- Active/located venv (
VIRTUAL_ENV, then<cwd>/.venv,<cwd>/venv) - Managed venv at
~/.pisces/python-env pythonorpython3on PATH
When a venv is selected, its bin/Scripts path is prepended to PATH.
Kernel env initialization inside Python also:
os.chdir(cwd)- injects provided env map into
os.environ - ensures cwd is in
sys.path
Tool availability and mode selection
python.toolMode (default both) + optional PI_PY override controls exposure:
ipy-onlybash-onlyboth
PI_PY accepted values:
0/bash->bash-only1/py->ipy-onlymix/both->both
If Python preflight fails, tool creation degrades to bash-only for that session.
Execution flow and cancellation/timeout
Tool-level timeout
python tool timeout is in seconds, default 30, clamped to 1..600.
The tool combines:
- caller abort signal
- timeout abort signal
with AbortSignal.any(...).
Kernel execution cancellation
On abort/timeout:
- Execution is marked cancelled.
- Kernel interrupt is attempted via REST (
POST /interrupt) and control-channelinterrupt_request. - Result includes
cancelled=true. - Timeout path annotates output as
Command timed out after <n> seconds.
stdin behavior
Interactive stdin is not supported.
If kernel emits input_request:
- Tool records
stdinRequested=true - Emits explanatory text
- Sends empty
input_reply - Execution is treated as failure at executor layer
Output capture and rendering
Captured output classes
From kernel messages:
stream-> plain text chunksdisplay_data/execute_result-> rich display handlingerror-> traceback text- custom MIME
application/x-pisces-status-> structured status events
Display MIME precedence:
text/markdowntext/plaintext/html(converted to basic markdown)
Additionally captured as structured outputs:
application/json-> JSON tree dataimage/png-> image payloadsapplication/x-pisces-status-> status events
Storage and truncation
Output is streamed through OutputSink and may be persisted to artifact storage.
Tool results can include truncation metadata and artifact://<id> for full output recovery.
Renderer behavior
- Tool renderer (
python.ts):- shows code-cell blocks with per-cell status
- collapsed preview defaults to 10 lines
- supports expanded mode for full output and richer status detail
- Interactive renderer (
python-execution.ts):- used for user-triggered Python execution in TUI
- collapsed preview defaults to 20 lines
- clamps very long individual lines to 4000 chars for display safety
- shows cancellation/error/truncation notices
External gateway support
Set:
export PI_PYTHON_GATEWAY_URL="http://127.0.0.1:8888"
# Optional:
export PI_PYTHON_GATEWAY_TOKEN="..."Behavior differences from local shared gateway:
- No local gateway lock/info files
- No local process spawn/termination
- Health checks and kernel CRUD run against external endpoint
- Auth failures are surfaced with explicit token guidance
Operational troubleshooting (current failure modes)
Python tool not available
- Check
python.toolMode/PI_PY. - If preflight fails, runtime falls back to bash-only.
- Check
Kernel availability errors
- Local mode requires both
kernel_gatewayandipykernelimportable in resolved Python runtime. - Install with:bash
python -m pip install jupyter_kernel_gateway ipykernel
- Local mode requires both
python.sharedGateway=falsecauses startup failure- This is expected with current implementation.
External gateway auth/reachability failures
- 401/403 -> set
PI_PYTHON_GATEWAY_TOKEN. - timeout/unreachable -> verify URL/network and gateway health.
- 401/403 -> set
Execution hangs then times out
- Increase tool
timeout(max 600s) if workload is legitimate. - For stuck code, cancellation triggers kernel interrupt but user code may still need refactor.
- Increase tool
stdin/input prompts in Python code
input()is not supported interactively in this runtime path; pass data programmatically.
Resource exhaustion (
EMFILE/ too many open files)- Session manager triggers shared-gateway recovery (session teardown + shared gateway restart).
Working directory errors
- Tool validates
cwdexists and is a directory before execution.
- Tool validates
Relevant environment variables
PI_PY— tool exposure override (bash-only/ipy-only/bothmapping above)PI_PYTHON_GATEWAY_URL— use external gatewayPI_PYTHON_GATEWAY_TOKEN— optional external gateway auth tokenPI_PYTHON_SKIP_CHECK=1— bypass Python preflight/warm checksPI_PYTHON_IPC_TRACE=1— log kernel IPC send/receive tracesPI_DEBUG_STARTUP=1— emit startup-stage debug markers