1. The news
On September 20, Google open-sourced AX (Agent Executor) under its own GitHub organization: a declarative orchestration runtime for agent workloads, Apache-2.0, with an API group of ax.io/v1alpha1. It hit number one on Hacker News that day. The project describes itself in one line — declare an agentic task, and AX sandboxes it, wires up its workspace, fences its network, and helps you run it at scale.
Set it next to the other route that landed a week earlier and the contrast is the story. On September 10, OpenAI packaged the Codex harness into the public beta Agents API: sessions, context compaction, model calls and tool coordination are all run by OpenAI, while you supply the model, instructions, tools and environment. The cost is that your orchestration layer is bound to OpenAI's implementation, data residency is US-only during the beta, and Zero Data Retention is unsupported. AX goes the other direction — you run the harness, and Google gives you the runtime that carries it. The cost is equally concrete: a Kubernetes cluster, ko, a container registry your cluster can pull from, and a reachable Agent Substrate Control API (in-cluster default api.ate-system.svc.cluster.local:443).
The line in the AX docs that explains the motive is worth keeping: agents are neither stateless microservices nor run-to-completion batch jobs — they accumulate state, need strict isolation, call out to model APIs and tool servers, and can burn money in a loop if nobody is watching.
For anyone writing multi-model call code every day, though, the part of AX worth reading is not its complaint about Kubernetes. It is the fourth primitive: Model.
2. The technical part
2.1 Four primitives, one file
Everything in AX is expressed as ax.io/v1alpha1 manifests, applied with a single ax apply -f. Each primitive owns one concern:
None of these is novel on its own; the combination is the point. They are declarative and come up together in one multi-document YAML, so a task boots with its repos cloned, its tools wired and its network fenced, skipping a token-burning cold-start bootstrap.
2.2 Model is not a model, it is a named configuration
The official docs are blunt about this: a Model is not a model, it is a named model configuration — which provider to call, which model identifier to use, provider-specific generation parameters, and a reference to the Kubernetes secret holding the API key.
apiVersion: ax.io/v1alpha1
kind: Model
metadata:
name: default-model
atespace: default
spec:
provider: anthropic
model: claude-opus-5
secretKey:
name: anthropic-api-secret
key: ANTHROPIC_API_KEY
parameters:
maxTokens: 16000
temperature: 0.9
The credential itself lands in a Secret with one command:
kubectl create secret generic anthropic-api-secret \
--from-literal=ANTHROPIC_API_KEY="sk-ant-..."
Making it a resource buys cluster-level manageability: the configuration lives in one place rather than scattered across every agent's environment. Rotating a key, pinning a new model version, tightening a parameter — each is one ax apply instead of a hunt through task definitions. AX's own components read it too, for instance when planning a workspace from a goal.
2.3 A sandbox contract you can introspect
AX is just as specific about the sandbox. Every task container starts with ax-task-runner as PID 1, which brings up a metadata and guest-management daemon on port 80, then launches spec.command as a child process and passes the daemon's address in through AX_METADATA_URL (something like http://127.0.0.1:80). Code inside the sandbox can therefore look itself up without any SDK:
curl -s "$AX_METADATA_URL/metadata/v1alpha1/ax/task"
Two more endpoints on that port are worth remembering: /metadata/v1alpha1/ax/workspaces returns every bound Workspace as a multi-document stream in binding order, and /readyz answers 503 while the workspace is initializing, flipping to 200 only once clones, MCP config and skills are all in place — the most reliable signal that a sandbox can actually do work. Add spec.debug: true and the same port also serves Agent Substrate's guest services (process and filesystem), which is what ax ssh rides on. It is off by default, because it amounts to opening arbitrary command execution inside the sandbox.
One more detail: if a Workspace binding carries a goal, the runner hands that goal to an Antigravity agent on first boot to finish environment setup. That agent needs GEMINI_API_KEY in the container and gets ten minutes by default, adjustable via AX_BOOTSTRAP_TIMEOUT. Describing an environment in plain English and letting an agent build it is a platform capability here, not just an orchestrator option.
2.4 Gateway: egress gets modeled
Gateway owns the other half: the network boundary. It declares the listeners a task exposes and an egress allowlist measured on two axes, host and port — host: "*" with port: 443 allows any host on 443:
apiVersion: ax.io/v1alpha1
kind: Gateway
metadata:
name: default-gateway
spec:
listeners:
- name: http
port: 8080
protocol: HTTP
egress:
allowlist:
hosts:
- host: "*" # allow everything on 443; tighten this in production
port: 443
The official example comment says it themselves: tighten this in production. Given that you are executing code a probabilistic model wrote, making egress an explicit allowlist enforced at the infrastructure layer beats relying on the agent's own code to behave.
2.5 The gap worth staring at: no endpoint field in Model
At this point the real issue surfaces. As documented today, Model.spec covers provider, model, secretKey and parameters, and the providers the docs demonstrate are google and anthropic. There is no custom endpoint or base URL field.
That reads less like an oversight in the docs and more like a design stance: "where models come from" is treated as a built-in platform capability. provider is a supported enum value and the credential arrives from a Secret; it is not a string where you can drop an arbitrary gateway address.
Which sets the cost structure for an agent fleet spanning several vendors: N provider values, N Kubernetes Secrets, N hostnames in the Gateway allowlist, N wire-protocol dialects, and N invoices that do not reconcile. To A/B three vendors' models inside one cluster, what you change is not a field but the whole chain.
2.6 It is still alpha
The README carries a warning in plain terms: core concepts, protocols and specifications are still being actively refined, and major breaking changes are likely before a stable release. The other half of the runtime is not an officially supported Google product either.
AX relies on a separate project, Agent Substrate, for sandboxed execution, supporting both gVisor and microVM isolation. A third party that read through that repository notes it states plainly that it is not an officially supported Google product, and that it is still pre-v1 and pre-GA. So read AX as alpha infrastructure: worth reading now, worth waiting on for production dependencies.
3. Where this lands: collapsing N to 1
Put the Model primitive, the host/port-granular egress allowlist and the missing endpoint field together, and the cost structure of multi-model orchestration gets rearranged.
Behind a router such as router.accels.tech, that N collapses to 1:
- One hostname in the egress allowlist. A single router.accels.tech plus 443 entry in Gateway is enough, and the coarse granularity stops mattering — one hostname was all you needed.
- One Secret. Credentials collapse to a single key in a Kubernetes Secret, and switching models turns from "add a provider, add a Secret, rebuild the image" into editing a string. How complete the catalog is decides how many options that path can cover, instead of whatever one vendor's shelf happens to hold.
- One billing view. The hardest question for a fleet is what an eval run cost and to whom. A router consolidates usage across vendors into one metering view, turning a post-hoc spreadsheet merge into a query. The sandbox-side wiring is a few lines — Model still describes which model the platform itself calls, while the runner points the actual traffic at the router (Accels is a Singapore-based company):
import os, yaml, requests
from openai import OpenAI
# The sandbox metadata server returns the current Task's full spec and status
spec = yaml.safe_load(
requests.get(f"{os.environ['AX_METADATA_URL']}/metadata/v1alpha1/ax/task").text
)
client = OpenAI(
api_key=os.environ["ACCELS_API_KEY"],
base_url="https://router.accels.tech/v1",
)
resp = client.chat.completions.create(
model="claude-opus-5",
messages=[{"role": "user", "content": "Write a fix plan for this failed build"}],
)
Complete model coverage means the value in that model slot is not bounded by one vendor's catalog. Stability means this single egress path cannot become the fleet's single point of failure. Unified billing means that after an ax suspend you can say exactly what you saved. In a runtime built around the fact that agents burn money in a loop, all three are operational metrics rather than marketing words.
4. Closing
AX is alpha today, depends on Agent Substrate, will break its API, and should not be anyone's production dependency this month. But it makes one thing explicit: once agents become workloads you schedule, "which model" and "where it may reach" stop being two constants in application code and become configuration objects the platform has to declare, audit and rotate.
That shift puts concrete demands on the calling side — as few egress hosts as possible, as few credentials as possible, as consistent a metering view as possible. If you are choosing that layer for your own agent platform, it is worth counting your current chain against those three and seeing how large N actually is.
Sources
- google/ax — Google's open agentic orchestration runtime
- AX — agentexecutor.io
- AX core concepts: Model / Gateway / Workspace / Task — docs/concepts.md
- AX manifests and full field reference — docs/manifests.md
- Inside the AX sandbox: metadata server and guest services — docs/sandbox.md
- agent-substrate/substrate — the sandboxed execution runtime behind AX
- Introducing the Agents API — OpenAI, 2026-09-10

Top comments (0)