Maniac Docs
Python Runtime

PythonSandboxClient

Configure the Python subprocess worker for local development, packaged applications, and container sidecars.

PythonSandboxClient

PythonSandboxClient implements the Sandbox interface. It spawns the Python worker, frames requests with a length prefix, and handles injected-callable RPC when Python code calls back into TypeScript.

Local repository

When tests or examples run from the monorepo, the client derives the repository root automatically, prefers .venv/bin/python when present, and prepends the repository root to PYTHONPATH:

import { PythonSandboxClient } from "@maniac-ai/agents/runtime";

const sandbox = new PythonSandboxClient();
await sandbox.run("x = 1 + 1\nprint(x)");

Use this mode when Python package sources live beside the TypeScript package.

LocalREPL

LocalREPL is the default execution environment for agent REPL loops:

import { LocalREPL } from "@maniac-ai/agents/runtime";

const repl = new LocalREPL(); // wraps PythonSandboxClient()
const cell = await repl.execute("import json\nprint(json.dumps({'ok': True}))");
console.log(cell.stdout, repl.state.variables);

Pass a custom sandbox to new LocalREPL(customSandbox) for tests or alternate worker paths.

LocalREPL also exposes getVar, setVar, inject, and aclose — mirroring the worker's namespace and injection surface.

Packaged applications

When the worker ships outside the repository layout, pass both the interpreter and the import path that contains runtime.adapters._subprocess_worker:

import { PythonSandboxClient } from "@maniac-ai/agents/runtime";

const sandbox = new PythonSandboxClient({
  pythonExecutable: "/opt/maniac-worker/.venv/bin/python",
  pythonPath: ["/opt/maniac-worker"]
});

If installed under node_modules, auto-detection fails with an explicit error — always pass pythonExecutable and pythonPath in production bundles.

Sidecar or process image

For containers, deploy the Python worker as a sidecar or shared process image:

const sandbox = new PythonSandboxClient({
  pythonExecutable: "/usr/local/bin/python",
  pythonPath: ["/app/python"],
  cwd: "/app/typescript/packages/agents",
  env: { PYTHONUNBUFFERED: "1" }
});

cwd is only used to derive the default repository root when pythonPath is not enough. Prefer explicit pythonExecutable and pythonPath in production.

Client options

OptionPurpose
pythonExecutablePath to the Python interpreter
pythonPathDirectories prepended to PYTHONPATH (joined with path.delimiter)
cwdWorking directory for the spawned process
envExtra environment variables merged into the child process
onSessionErrorCallback when framing desync or unrecoverable reader errors terminate the session

Injected callables

injectCallable(name, fn) registers a TypeScript function the worker can invoke from Python via await name(...). The runner uses this to expose tool handlers and the memory RPC to REPL cells.

Callable arguments and return values must be JSON-serializable. The worker rejects non-serializable values at the boundary.

Agent integration

Set repl on your agent spec:

const result = await runAgent(
  {
    id: "analyst",
    instructions: "Use python_exec for data work.",
    model,
    repl: { namespace_extras: { app_name: "analyst" } }
  },
  "Plot the trend."
);

runAgent constructs LocalREPL(spec.repl?.sandbox ?? undefined) unless you pass RunOptions.repl explicitly.

On this page