Agentix is built around a small execution loop:
Everything else supports that loop or rides side channels on the same Socket.IO connection.

Core Namespaces

Agentix core owns three reserved Socket.IO namespaces: Plugin-specific protocols use their own namespace, conventionally /<package-name>. See Plugins and Side Channels for the extension model.

Systems

Remote Target

The caller passes a normal imported function:
The client encodes the callable as an import-path string:
The runtime worker imports the module, resolves the function, unpickles the arguments, and invokes it. Return values travel back as pickle blobs inside call:result. Because a sandbox may run less-trusted code, the host decodes those blobs through a restricted allowlist loader (agentix.runtime.shared.safepickle) rather than plain pickle.loads, refusing any non-allowlisted global with agentix.RestrictedUnpickleError.

Call Flow

Transports

Bundle Layout

agentix build [path] installs one Python project into the runtime venv with uv (uv owns Python; Nix owns system binaries — there is no pip):
The sync brings in user code, direct dependencies, transitive dependencies, and integration packages declared in pyproject.toml. The runtime tree is the uv venv plus a symlinkJoin of the Nix closures (interpreter, uv, and any system deps):
If the project includes default.nix, the build adds a Nix builder stage and links binaries into /nix/runtime/bin.

Worker Model

The runtime server owns one worker subprocess. The worker handles remote function invocation and keeps the runtime server isolated from user code. For each call, the worker:
  1. resolves the RemoteCallable import path
  2. unpickles (args, kwargs)
  3. calls the callable (awaiting when the return value is awaitable)
  4. pickles the return value
The worker also hosts the sandbox-side agentix.sio bridge. Plugin namespaces register inside the worker and forward events through sio_emit / sio_open / sio_inbound frames on the worker pipe. The runtime server does not implement plugin business logic. It accepts namespace connections, dynamically registers generic forwarders, and relays events between host-side AsyncClientNamespace handlers and worker-side Namespace handlers. The worker uses the same /nix/runtime environment as the runtime server, so anything installed into the bundle can be imported on demand.

SandboxProvider Boundary

A SandboxProvider is a host-side plugin that stages a bundle and starts the sandbox. provider.create(...) returns a live Sandbox handle; call await sandbox.remote(fn, ...) directly. The runtime protocol is the same regardless of where the sandbox is running.
The scoped form constructs the provider, opens a session, and tears down both the runtime connection and the container on exit:
RuntimeClient(runtime_url) still exists as the underlying transport for advanced, direct use against a known runtime_url (for example, an in-process server). The sandbox path uses sandbox.remote rather than a nested RuntimeClient.

Mental Model