This quickstart walks the shortest end-to-end Agentix flow:
  1. Declare deps in a normal Python project.
  2. agentix build packages the project + every transitive dep into a self-contained bundle — no FROM, nothing installed at run time, just a uv venv plus a Nix closure under /nix/....
  3. Deploy a sandbox: the bundle is bind-mounted onto a task base image at /nix. Different task images, same runtime.
  4. Call a remote function with sandbox.remote(fn, …).

Prerequisites

  • Python 3.11 or newer
  • Docker or Podman for the build executor and local sandbox backend
  • uv (optional) to commit a uv.lock. With a lock the build is reproducible (uv sync --frozen); without one the build container resolves dependencies fresh

One project, two images

The two-image model is the heart of Agentix:
  • bundle — the bundle from agentix build. Generic and reusable. Holds Python, agentixx, every plugin, your code, all transitive deps under /nix/store/... with libc vendored.
  • image — the task-specific base the workload runs in (a SWE-bench task image, a customer environment, plain Ubuntu, …).
DockerProvider mounts the runtime’s /nix into the task container at sandbox-create time. The Python interpreter, the runtime server, your code, and the plugin binaries (bash, coreutils, …) all live under /nix/runtime/bin/ and resolve regardless of the task image’s distribution.

Layout

This is the real in-repo example at examples/hello-world — a flat project: one main.py and one default.nix.

Install + build

agentix deploy --format json prints {"bundle": ..., "platform": ..., "metadata": {...}}, so the cache path reads cleanly with jq -r .bundle instead of parsing log lines. agentix build does, in order:
  1. Stages your project + every plugin’s default.nix (each plugin ships its system deps next to its Python module).
  2. Runs Nix for the interpreter/system closures and installs the Python dependency closure with uv inside the build container:
  3. Writes a portable bundle tar containing manifest.json + nix/.
agentix deploy docker|podman unpacks that tar into a content-addressed host cache. Docker-compatible sandbox runs bind-mount the cached nix/ tree at /nix. The runtime is a plain uv venv at /nix/runtime/venv plus a symlinkJoin of the Nix closures at /nix/runtime/{bin,lib,...} — there is no pip in the bundle and nothing is installed at run time.

Call it

main.py doubles as the host orchestrator: it constructs the Docker provider, opens a sandbox over the deployed bundle, and runs hello() inside it with sandbox.remote(fn, …).
main.py
Run it against the bundle path captured above:
Expected output (the sandbox rg comes from default.nix):
The sandbox is a live handle — await sandbox.remote(fn, …) is the one-call path. There is no separate RuntimeClient to open in the common case; the provider’s session(...) yields a sandbox you call directly, then closes the connection and deletes the container on exit. RuntimeClient(url) still exists for advanced/direct use against a known runtime_url (e.g. an in-process server).

How the overlay works

Under the hood, DockerProvider.create does:
The task container sees /nix/store/... and /nix/runtime/bin/... at their canonical paths. Python’s RPATH (baked at Nix build time) finds its libs under /nix/store/... because that’s exactly where the mounted cache puts them.

Next

Example: hello-world

The complete in-repo project used here (examples/hello-world).

More examples (cookbook)

Larger example: Claude Code on SWE-bench Verified.

Architecture

Bundles, workers, and transports.

CLI Reference

Every agentix build option.