This page is the source of truth for Agentix public APIs. If an API is not listed here, treat it as internal and subject to change.

Compatibility contract

  • Sandbox.remote(fn, *args, **kwargs) is a stable public API; the same contract holds for RuntimeClient.remote(...).
  • .remote has no default retry behavior.
  • .remote returns the target function result on success, and raises on failure.
  • /rpc, /log, and /trace are reserved by agentix-core.
  • tracing and logging transport details are internal implementation details; users extend them through stdlib logging and trace.Processor.

Core Python API (import agentix)

Top-level names exported by agentix (this list mirrors agentix.__all__): Remote calls and namespaces:
  • RuntimeClient
  • RemoteCallable
  • Namespace
  • AsyncClientNamespace
  • register_namespace
  • request_handler (host-side round-trip helper)
Providers and sandboxes:
  • SandboxProvider
  • Sandbox
  • SandboxConfig
  • SandboxResource
  • SandboxId
  • SandboxInfo
  • providers
  • register_provider
  • BundleDeployer (optional provider deploy hook)
  • DeployedBundle
Failure and result vocabulary (raised by / returned from .remote and .try_remote):
  • RemoteCallError
  • CallCancelled
  • CallTimeout
  • WorkerExited
  • RuntimeUnreachable
  • RemoteSioError
  • RestrictedUnpickleError (a refused return-value global — see Remote Calls)
  • Result, Ok, Failed (the try_remote result union)
Logging and tracing:
  • configure_logging
  • context
  • log (re-exported from agentix.utils.log)
  • trace (re-exported from agentix.utils.trace)
  • __version__
The canonical submodule paths are agentix.utils.log and agentix.utils.trace; the top-level agentix.log / agentix.trace attributes are convenience aliases.

Canonical call path

The common path is a provider session yielding a live Sandbox handle. Call await sandbox.remote(fn, ...) directly — there is no separate RuntimeClient to open.
from agentix import SandboxConfig
from agentix.provider.docker import DockerProvider
from my_project.tasks import run

provider = DockerProvider()
config = SandboxConfig(
    image="python:3.13-slim",
    bundle="dist/my_project.bundle.tar",
)

async with provider.session(config) as sandbox:
    result = await sandbox.remote(run, seed=42)
provider.session(config) closes the runtime connection and deletes the container on exit. For manual lifecycle control:
sandbox = await provider.create(config)
try:
    result = await sandbox.remote(run, seed=42)
finally:
    await sandbox.aclose()                     # close the runtime connection
    await provider.delete(sandbox.sandbox_id)  # remove the container
agentix.RemoteCallable.validate(fn) checks at development time that fn is remote-safe: it returns the wire ref (module::qualname) for an importable top-level function, and raises TypeError for lambdas, closures, and bound methods. RemoteCallError messages now include the sandbox-side traceback (str(exc)); it is also available on exc.error.traceback.

Runtime client API

RuntimeClient is the advanced/direct entrypoint for talking to a known runtime_url (for example, an in-process server). The sandbox path should use sandbox.remote instead of a nested RuntimeClient.
from agentix import RuntimeClient

async with RuntimeClient(runtime_url) as client:
    result = await client.remote(fn, *args, **kwargs)
Also public:
  • RuntimeClient.health()
  • RuntimeClient.register_namespace(ns)

Timeout

The timeout knobs apply to both sandbox.remote and RuntimeClient. RuntimeClient(url, timeout=...) sets the per-request timeout in seconds. The default is 300; raise it for agent workloads (roughly 6001800s), e.g. RuntimeClient(url, timeout=1800). http_sync_ms (default 1000) tunes the inline HTTP fast-path budget for short calls; set http_sync_ms=None to disable it so every call goes over Socket.IO. To bound a single call independently of the request timeout, wrap it in asyncio.wait_for(sandbox.remote(...), deadline).

SandboxProvider API

Core provider lifecycle. provider.session(config) is the scoped form; it yields a live Sandbox and tears it down on exit.
from agentix import SandboxConfig
from agentix.provider.docker import DockerProvider

provider = DockerProvider()

config = SandboxConfig(image="python:3.13-slim", bundle="/home/me/.cache/agentix/bundles/sha256-...")
async with provider.session(config) as sandbox:
    result = await sandbox.remote(fn, ...)
Backends subclass SandboxProvider (from agentix.provider.base), implementing create, delete, and get; session is inherited.
from agentix.provider.base import SandboxProvider

class FooProvider(SandboxProvider):
    async def create(self, config: SandboxConfig) -> Sandbox: ...
    async def delete(self, sandbox_id: SandboxId) -> None: ...
    async def get(self, sandbox_id: SandboxId) -> Sandbox: ...

Discovering backends

agentix.providers() returns the provider registry; providers().all() returns {name: ProviderClass} for every installed backend.
from agentix import providers

providers().all()          # {"docker": DockerProvider, "podman": ...}
There is intentionally no string loader for typed code: import the concrete provider directly so the type is known at construction. For string/CLI-driven selection only, look the class up dynamically with providers().get(name).

Concrete provider examples

Import the concrete provider and instantiate it (optionally with a backend config) to get a usable backend.
from agentix.provider.docker import DockerProvider, DockerProviderConfig

# Defaults (uses the docker CLI).
provider = DockerProvider()

# Same backend driven by podman.
provider = DockerProvider(DockerProviderConfig(container_engine="podman"))

# A config can also build its provider directly.
provider = DockerProviderConfig(container_engine="podman").to_provider()

Namespace extension API

Plugin protocols use plugin-owned namespaces, conventionally /<package-name>. The reserved namespaces /rpc, /log, and /trace belong to agentix-core. Sandbox-side namespace handlers run in the worker:
from agentix import Namespace, register_namespace
Host-side namespace handlers run in the process that owns the Sandbox:
from agentix import AsyncClientNamespace
Register host-side namespaces on the sandbox before the first remote call:
async with provider.session(config) as sandbox:
    sandbox.register_namespace(MyHostNamespace())
    result = await sandbox.remote(fn, ...)
When driving a RuntimeClient directly, register before entering its context:
from agentix import RuntimeClient

client = RuntimeClient(runtime_url)
client.register_namespace(MyHostNamespace())

async with client:
    ...
See Plugins and Side Channels for the full host, server, and worker extension flow.

Logging API

Sandbox code uses stdlib logging. The host side automatically registers the /log consumer.
import logging

logger = logging.getLogger(__name__)
logger.info("message from sandbox")
The worker also captures the process’s raw stdout and stderr (print(), subprocess output, C-extension writes) and replays each line over /log under the logger names agentix.sandbox.stdout / agentix.sandbox.stderr. The same output is appended to a durable $AGENTIX_LOG_DIR/sandbox-<id>.log inside the sandbox (default /tmp/agentix; set the variable empty to disable) so it survives a dropped connection. Host applications can use normal logging handlers and the Agentix convenience configuration helper:
from agentix.utils.log import configure_logging

configure_logging(default_context="host")
Do not register a custom /log namespace.

Tracing API

Trace and span helpers:
from agentix import trace

with trace.trace("rollout"):
    with trace.span("agent.step") as span:
        span.add_event("first_token")
Processor extension API:
from agentix import trace

class MyProcessor(trace.Processor):
    def on_trace_start(self, t: trace.Trace) -> None: ...
    def on_trace_end(self, t: trace.Trace) -> None: ...
    def on_span_start(self, s: trace.Span) -> None: ...
    def on_span_end(self, s: trace.Span) -> None: ...
    def force_flush(self) -> None: ...
    def shutdown(self) -> None: ...

trace.add_processor(MyProcessor())
Do not register a custom /trace namespace.

Plugin APIs (when installed)

These modules are public once their plugin package is installed:
  • agentix.bash
    • run(...)
    • run_stream(...)
  • agentix.files
    • upload(...)
    • download(...)
  • agentix.agents.claude_code
    • run(...)
  • agentix.plugins.datasets.swe
    • prepare_env(...)
    • score(...)
  • agentix.bridge (tunnel an in-sandbox agent’s LLM traffic to the host)
    • Proxy, on, Request, ClientResponse, Client, Handler, TunnelHandle, AbridgeError, DynamicRoutes
    • Forward, SessionForward (forward to a host-side sidecar / gateway)
    • Recorder (record tunnel request/response pairs to JSONL)
    • Sidecar, SidecarError, Command
    • handler clients under agentix.bridge.clients (AnthropicClient, OpenAIClient, AnthropicFromOpenAIClient, AnthropicToOpenAI)
  • provider backends (contribute siblings into agentix.provider)
    • agentix.provider.docker (production; provides docker + podman)
    • agentix.provider.apptainer (production)
    • agentix.provider.uv (local uv-materialized runtime; no container)
    • agentix.provider.daytona (stub)
    • agentix.provider.e2b (stub)

CLI entrypoints

Public command-line entrypoints:
  • agentix build [PATH] — build a deploy-ready bundle from a project root.
  • agentix deploy <backend> <bundle> — deploy a bundle to a backend. --format json prints {"bundle": ..., "platform": ..., "metadata": {...}} so the cache path can be read with jq, e.g. BUNDLE=$(uv run agentix deploy docker dist/x.bundle.tar --format json | jq -r .bundle).
  • agentix plugin list — read-only listing of installed provider backends and their load status.
The bundle’s runtime server is not exposed as a console script; it is launched inside the sandbox container by /nix/runtime/bootstrap.sh, which ships with every bundle. Plugin entrypoints may add their own commands (for example, bridge tooling).