airmux runtime commands read YAML from --config, then AIRMUX_CONFIG. Gateway commands use
./.airmux/airmux.yml, falling back to a shared ./airmux.yml when the standalone file is absent. Control-plane
commands use ./airmux.yml. The airmux image uses deploy/docker/airmux.yml.
Docker Compose variables
YAML structure
References
References must occupy the whole YAML scalar. The loader does not discover
.env files or mutate the process environment;
CLI startup owns optional .env loading. Relative file references and runtime paths resolve against the containing
configuration file. A local bundle resolves its taxonomy and key references against the bundle file.
Bundle sources
Remote defaults are 30 seconds for poll and heartbeat intervals. Local bundle reload defaults to 2 seconds.
Outbound HTTP connections
The data plane creates one outbound HTTP client per worker. Configure its connection limits underdata_plane.http:
max_connections: 256
can have up to 1,024 active outbound connections.
Outbound requests use HTTP/1.1, including over TLS. Connect and pool acquisition share a 5-second timeout; response
reads have a 120-second idle timeout. There is no overall inference deadline. Budget refreshes have a 5-second total
timeout. Responses stream with backpressure, and closing a stream releases its connection slot immediately.
Provider cookies are never stored, and redirects are not followed. aiohttp honors HTTP_PROXY, HTTPS_PROXY, and
NO_PROXY when a proxy is configured at startup. Without a configured proxy, environment and netrc lookups are disabled
to avoid thread-pool work on each request. Changing these settings requires restarting the gateway.
Application logs
Both planes write application logs to stderr. Outside dev mode, each log record is JSON. Writes are batched until 100 records or 65,536 characters accumulate, or a 100 ms timer expires, whichever happens first. A single large record is written intact. Timer delivery depends on the event loop being able to run; a blocked output stream can still block that loop. Error and critical records flush the pending batch immediately. Application shutdown and normal process exit flush remaining records. Logging outside an active event loop is immediate. Formatting happens when the event is logged, so timestamps and request IDs retain the original request context. Abrupt termination can lose buffered lines. Failed writes use Python logging’s error handling and discard the failed batch rather than retrying potentially partial output. These diagnostic logs are separate from the usage-event outbox and do not change its accounting or persistence behavior. Dev mode keeps immediate plain-text application logs. Gateway HTTP access logs remain enabled only in dev mode.Event outboxes
SQLite export defaults to every 5 seconds. Its cache directory defaults to
.airmux beside the configuration file,
and the outbox writes events.db there. Workers sharing one gateway cache directory coordinate through that outbox.
The file sink resolves path relative to the configuration file, creates missing parent directories, and creates new
files with mode 0600. It appends one complete usage event per line, and processes sharing a local file serialize their
writes. Restarting appends to the existing file. It has no export queue, deduplication, rotation, or fsync guarantee.
Use it on a local POSIX filesystem. A file write failure terminates the worker instead of silently discarding usage.
SQLite and file requests do not wait for local persistence. If the outbox cannot accept an event, the gateway returns
503 metering_capacity_exhausted before starting that provider attempt. Graceful shutdown writes accepted events to
local storage. SIGKILL, machine failure, power loss, or storage failure can lose events not yet written.
Budget backends
Budget configuration is independent of the bundle source and event outbox. The
control_plane backend is best effort;
missing, mismatched, or expired state allows requests. With budget.kind set to none, budget rules always allow requests.
Secret stores
The environment store checks
AIRMUX_SECRET_PROVIDER_<PROVIDER> before <PROVIDER>_API_KEY. Scope and credential name
are not part of its lookup, so it cannot isolate tenant-specific values.