A provider backend answers one question: where should this bundle run? Remote calls decide which function runs. Bundles decide what code exists in the sandbox. Providers decide where the image is started and how it is cleaned up.

Use a Backend

The Docker backend is the local development path:
In code, construct a provider, open a session with a SandboxConfig, and call remote directly on the returned live sandbox handle.
provider.session(...) creates the sandbox on entry, closes the runtime connection, and deletes the container on exit. For manual lifecycle control, create and delete the sandbox yourself:
Host-side plugin namespaces register on the sandbox before the first remote call:
For plugin-agnostic code where the backend name comes from config or an environment variable, look the provider class up by name through the registry instead of a concrete import:
To discover what is installed, from agentix import providers; providers().all() returns {name: ProviderClass} for every registered backend. If the bundle was built for a non-default architecture, pass the same Docker/OCI platform so the task image and runtime overlay match:

Backend Plugins

SandboxProvider packages register classes in the agentix.provider entry point group.
pyproject.toml
After installation, the backend name becomes available through the registry:

Backend Protocol

Backends subclass SandboxProvider, implement three async methods, and inherit session().
my_provider/__init__.py
Most backends construct with no arguments, reading API keys, regions, and templates from environment variables so CLI and code paths behave the same way. A backend MAY accept its own config object — e.g. DockerProvider(DockerProviderConfig(container_engine="podman")) selects the container runtime, network, GPU args, and so on. Backend-neutral settings (image, bundle, env, resource) belong in SandboxConfig, not the backend.

CAPE

The cape backend targets a lease-based GPU capacity pool driven by a submitter-side cape CLI. One sandbox maps onto exactly one long-lived CAPE request inside a per-sandbox session: the request bind-mounts the bundle’s /nix tree read-only, prints an AGENTIX_ENDPOINT marker to stdout, and execs /nix/runtime/bootstrap.sh; the provider discovers the endpoint by polling cape status / cape logs for that marker and health-checks it. No second command is ever submitted into the session.
For this backend SandboxConfig.bundle is an opaque node-visible path to an already-extracted bundle tree — there is no agentix deploy cape yet, because bundle transport to CAPE nodes is still an open question. Contract status: the CAPE CLI surface this backend emits is an assumed contract, reverse-documented from a sibling project’s adapter and only ever exercised against fakes and emulators. Verify it against the real cape CLI before production use — see the checklist in plugins/providers/cape/README.md.

Configuration

The daytona and e2b backends are placeholders today: they validate configuration but their lifecycle methods raise NotImplementedError pending integration. docker/podman, apptainer, and uv are the working backends. The uv backend materializes the runtime from a local uv venv with no container — no isolation, but the fastest path to run the runtime/RPC stack on a bare host for local dev, CI, or trusted eval (see plugins/providers/uv/README.md). Fail fast in __init__ when required configuration is missing. The error should surface before the backend starts creating infrastructure.

Boundary

SandboxProvider backends should not know about agent wrappers, dataset scorers, or remote-call targets. They only stage bundles, start sandboxes, and return the runtime endpoint.