config.json under AGENTX_HOME is engine-owned state, not a config
file). Everything has a working default: a bare agentx-server boots SQLite on port 4700
with no keys and no auth.
Core
--port and --db-url are flags of the agentx-server launcher, which translates them into
the PORT / AGENTX_DB_URL environment variables before handing off to the engine;
--engine-bin only tells the launcher which engine executable to start. The Docker image runs the engine binary directly - no launcher in between - so set
the environment variables there.
Deployment tiers
One engine binary, one wire API - the tier is a deployment choice, never a fork:
The repo ships an enterprise reference deployment as
docker-compose.enterprise.yml
(Postgres + ClickHouse + one engine) and a Helm chart at deploy/helm/agentx (build and push
the repo Dockerfile first - no public image is published yet; postgres.externalUrl /
clickhouse.externalUrl point it at managed databases). See
High availability & DR for the topology rules and
engine/docs/deployment-tiers.md in the repo for the full walkthrough, including how to verify
spans actually land in ClickHouse.
Using Postgres
Ingest and rate limits
Monitoring behavior
Quotas
Today’s usage against all three caps is visible read-only in the dashboard (Platform Settings →
Usage & limits) and on the wire (
GET /api/v1/agent-monitoring/usage - { day, resetsAt, traces, onlineJudgeCalls, judgeCalls }, each { used, limit } with limit: null meaning
unlimited). Counters reset at midnight UTC. The caps themselves are deliberately not editable
from the UI - they are cost-control levers, changed where deployments are changed.
Auth and multi-user
The default posture is auth-disabled: a reachable port is a trusted user, and the dashboard connects itself. Everything below only matters once you turn on real accounts - see Authentication for the full model.Social sign-in and SSO
Wire casing
The API’s one wire convention is camelCase (sessionId, latencyMs, judgeScorers).
The trace-ingest write path historically accepted snake_case keys (session_id,
latency_ms, …); those remain accepted as legacy aliases for existing SDKs, and
POST /ingest/traces answers with both traceId (canonical) and trace_id (legacy). New
endpoints and fields are camelCase only.
The project API key
The startup log’sDefault project API key: agtx_local_... is generated once on first run and
reused after that (persisted in $AGENTX_HOME/config.json). It’s what SDK/CI/OTel callers send
as x-api-key. In the default auth-disabled mode the dashboard fetches it automatically from
GET /api/v1/auth/config, so there is nothing to paste. Additional projects (created from the
project switcher) each get their own key, visible in that project’s Settings → API key.
Prometheus metrics
GET /metrics serves Prometheus text format on the engine’s one port - open by default (the
content is deliberately operational-only: queue counters, RSS, uptime; never span content,
keys, or per-project data). Internet-exposed deployments set AGENTX_METRICS_TOKEN and scrape
with Authorization: Bearer <token>:
The audit trail
The engine keeps an append-only audit log of control-plane activity: scorer/judge/pattern create-update-delete, settings changes, API key regenerations, project create/delete, bulk export reads, and (inAGENTX_AUTH=enabled mode) sign-in/sign-up/sign-out attempts with the
attempted email and status. Data-plane traffic (trace ingest, feedback, outcomes) is
deliberately excluded so the trail stays readable, and recorded summaries carry field names
only, never values - scripts, keys, and passwords cannot leak into the log.
audit_events and nothing else - no update or delete surface exists.
Verifying end-to-end
The repo ships a smoke test that runs the real Python SDK against a fresh instance - Trace, Evaluate (judge scoring), and Monitor (built-in + custom pattern detection). It needs anOPENAI_API_KEY (for the judge paths) and Python 3:
OpenRouter
Save an OpenRouter API key (Platform Settings → LLM providers, orOPENROUTER_API_KEY in
the environment) and every model field in the product - the platform model picker, judge
scorers, the playground - can call the full OpenRouter catalog by its vendor/model ids
(anthropic/claude-sonnet-4.5, meta-llama/llama-4-maverick, …). Any model id containing /
routes through OpenRouter’s OpenAI-compatible API with that key; the model picker lists the
live catalog once the key is configured.
Platform model
The engine runs its own LLM operations - topic mapping, suggestions and answer drafts, dataset coverage analysis, prompt/tool proposals, AI analysis, auto-improve reports - on a single default model (gpt-5.6-luna out of the box). Platform Settings → LLM providers → Platform
model changes it instance-wide via a searchable picker: direct OpenAI/Anthropic/Gemini
names, custom endpoints from the pricing catalog, and - with an OpenRouter key - the whole
OpenRouter catalog. This is deliberately separate from judge scorers, which configure their
model per scorer; scorers left without a model keep the built-in judge default.
