Deploy workers / AX

Use an existing AX deployment

Experimental. This guide assumes AX and Agent Substrate are already running. Horde connects to that deployment and creates workers in gVisor. Your Horde controller can stay on your local machine.

Before you start

1. Prepare a Horde runner image

The AX runner is currently built from source; Horde does not yet publish a prebuilt AX image. From a Horde checkout, place an Ubuntu 24.04-compatible Linux AMD64 Horde executable at dist/amd64/horde (see the binary build instructions), then build and push:

docker build --platform linux/amd64 -f containers/ax/Dockerfile \
  -t REGISTRY/horde-ax:experimental .
docker push REGISTRY/horde-ax:experimental
docker inspect --format '{{index .RepoDigests 0}}' REGISTRY/horde-ax:experimental

Replace REGISTRY with a registry your AX workers can pull from. Keep the returned image@sha256:... reference for the next step. The image contains Horde, Git, and the model CLIs. If tasks need Docker or Compose, apply the optional Docker setup before building and creating the worker.

2. Add an AX profile

Add this to the controller’s ~/.config/horde/runtimes.toml. Keep the enrollment settings at the top of the file, before any profile tables; reuse your configured controller CA and address.

issuer_key = "/absolute/path/to/controller/ca.key"
controller_address = "CONTROLLER_ADDRESS:7443"
controller_tls_name = "controller.example.net"

[profiles.ax-worker]
provider = "ax"
project = "PROJECT_UUID"
endpoint = "http://127.0.0.1:9090"
ax_router_endpoint = "http://127.0.0.1:8001"
ax_revision = "d8ed0fe38bceb7842d3c47817d53d16ccdfcb601"
image = "REGISTRY/horde-ax@sha256:IMAGE_SHA256"
ax_egress = ["*:443"]
cpus = 2
memory_mb = 4096
concurrency = 2
executor_roles = ["planner", "worker", "reviewer"]

Replace the placeholders and tunnel ports. Get the project UUID with horde project inspect PROJECT. The listed executor roles must exist in that project’s configuration. Configure credentials through Horde’s managed accounts; ambient CLI logins are not copied into workers. Use a separate profile for each project.

The pinned AX gateway ignores the port in ax_egress, so *:443 permits all outbound traffic. Use explicit hostnames or CIDRs to restrict destinations. CPU and memory settings are sent to AX; per-worker enforcement has not been established by this integration.

3. Create and verify a worker

horde --project PROJECT runtime create ax-1 --profile ax-worker --request-id create-ax-1
horde --project PROJECT runtime inspect ax-1
horde --project PROJECT call runtime_capabilities '{}'

Replace PROJECT with your project slug or UUID. Wait for Horde’s authenticated worker connection to be ready before submitting work. AX reporting its Task ready is only the first part of startup. Capabilities should show gvisor isolation.

4. Run a task

horde --project PROJECT submit --on ax-1 --repo /path/to/repo "Run the tests"

Use a registered repository with a clean checkout and committed changes. Horde transfers the repository and runs the workflow on ax-1. Work selected for that worker waits while it is unavailable; it does not fall back to your local machine.

Stop and resume

horde --project PROJECT runtime stop ax-1 --request-id stop-ax-1
horde --project PROJECT runtime start ax-1 --request-id start-ax-1

Stop drains active work and retains the workspace and worker identity. Reuse a request ID only to retry the same operation; use a new ID for the next stop/start cycle. For image upgrades, create a new runtime with the new image digest. See recovery and upgrades for uncertain operations and cleanup.

Optional Docker and Compose

Docker and Compose work inside AX workers when the deployment supplies the required guest capabilities and gVisor settings. Follow the AX Docker configuration, which includes the pinned AX patch and sandbox setup, then build the Horde runner with --build-arg ENABLE_DOCKER=true.

Create a new worker using that image and verify that runtime_capabilities reports Docker and Compose available. Each worker has its own Docker daemon and persistent image and volume storage; it does not use the host Docker socket. Builds and Compose service networking have passed live tests. Published ports (-p) remain untested.

If Docker fails, Horde stays connected for inspection and draining. Explicitly stop and start the worker to recover Docker. See the full AX reference for configuration details and tested limitations.