Production Deployment¶
This guide walks through deploying Agentomatic to production: multiple agents, each with its own inbound authentication, its own authenticated databases and vector stores, custom APIs that call other authenticated APIs, plus caching, observability, monitoring, and a control plane — all with as little glue code as possible.
It is written around a concrete target: five independent agents sharing one deployment, where every agent authenticates callers, talks to different backing services (each with its own credentials), and is fully observable.
Read these first
This guide ties together features documented in depth elsewhere: Per-Agent Connections, Custom Endpoints, Security & Zero Trust, Observability, and the Control Plane. Here we focus on how they fit together for a real deployment.
Architecture at a glance¶
flowchart TB
Client[Clients / other services] -->|Bearer JWT| GW[Agentomatic app]
subgraph GW[Agentomatic ASGI app]
MW[Middleware chain:\nJWT → Zero-Trust → Rate-limit → Metrics → Maintenance]
subgraph agents[Agents]
A1[fraud_agent]
A2[billing_agent]
A3[rag_agent]
A4[support_agent]
A5[ops_agent]
end
EP[Custom endpoints\nmulti-model fan-out]
CP[Control plane\n/api/v1/control]
end
A1 -->|scoped conn| DB1[(fraud DB)]
A2 -->|scoped conn| DB2[(billing DB)]
A3 -->|scoped conn| VS[(vector store)]
A4 -->|scoped conn| MEM[(memory DB)]
A3 -.->|cache| REDIS[(redis)]
EP -->|OAuth2| ML1[model A]
EP -->|OAuth2| ML2[model B]
GW -->|/metrics| PROM[Prometheus]
GW -->|OTLP traces| OTEL[OTel Collector]
PROM --> GRAF[Grafana]
Everything above is configured declaratively — agents in folders, connections
in connections.py, endpoints in endpoint.py, and a handful of platform
flags. No custom FastAPI wiring is required.
Project dependencies in the generated image¶
agentomatic deploy builds with uv, pinned via ARG UV_VERSION so the
image is reproducible, and installs your project's own dependencies as well
as agentomatic itself.
Declare what your project needs — a vendor LLM driver, a vector client, an
in-house package — in requirements.txt next to main.py:
# Keep the exact framework pin generated by `agentomatic new`.
agentomatic[all]==<released-version>
# This project's agents talk to a local OpenAI-compatible model server,
# so it needs that client library.
langchain-openai>=0.3
Replace <released-version> only when you intentionally upgrade and re-run
the repository verification gates. The scaffold writes the concrete version
that created the project, so generated projects do not contain this placeholder.
The generated Dockerfile installs agentomatic first (at its pinned version) and your requirements second, so a looser pin in your file cannot downgrade the framework.
This is how a provider driver reaches the image
The all extra deliberately excludes the vendor LLM drivers — openai,
azure, vertex — because the platform is provider-agnostic: you install
the SDK for the backend you actually use. requirements.txt is where that
happens. A stack configured for openai_compatible (which is what oMLX,
llama.cpp, vLLM and LM Studio all speak) needs langchain-openai there,
or the platform will refuse to start rather than answer with a fake model.
Reproducible builds with a lockfile¶
If your project keeps a pyproject.toml and a uv.lock, the generated
Dockerfile installs from the lock instead:
That installs the exact resolved versions the lock pins rather than
re-resolving at build time. Regenerate the lock with uv lock whenever you
change a dependency.
1. Install for production¶
Install only the extras you use. Common production combinations:
# Core + Postgres (async) + JWT auth + metrics/tracing
pip install 'agentomatic[db,security,metrics,telemetry]'
# Add a vector store client for RAG agents (pick your provider)
pip install qdrant-client # or chromadb, weaviate-client, pinecone-client
# Add redis for caching
pip install redis
| Extra | Brings in | Needed for |
|---|---|---|
db |
SQLAlchemy async + drivers | Database connections, SQL memory store |
security |
PyJWT + JWKS | Inbound JWT/OAuth2, zero-trust |
metrics / telemetry |
Prometheus client / OpenTelemetry SDK + OTLP exporters | Metrics + tracing |
ui |
Chainlit | Optional chat debug UI |
Async database drivers
Database URLs must use an async driver:
postgresql+asyncpg://…, mysql+aiomysql://…, sqlite+aiosqlite:///….
1b. Generate production containers (CLI)¶
Agentomatic is both a dev platform and a production deploy target. Generate rootless / distroless images, compose, and a stack-derived env file::
agentomatic stack use remote
agentomatic deploy --stack remote --distroless --out deploy/generated
agentomatic stack export --env .env.production
# HTTPS + global auth at runtime
agentomatic run --stack remote \
--ssl-certfile /certs/fullchain.pem \
--ssl-keyfile /certs/privkey.pem \
--require-auth-globally
Deploy profiles: --profile full|minimal¶
agentomatic deploy picks how much of the platform the image runs. Both
profiles drive the same env-driven main.py (via AGENTOMATIC_* env vars
baked into the Dockerfile + compose) — there is one code path, not two images.
| Feature | full (default) |
minimal |
|---|---|---|
Core agent REST API (/api/v1/...) |
✅ | ✅ |
Swagger / OpenAPI (/docs, /redoc, /openapi.json) |
✅ | ✅ (always on) |
Health / readiness (/health, /readiness) |
✅ | ✅ |
| Metrics / observability | ✅ | ✅ |
| Auth wiring (API-key / JWT / zero-trust) | ✅ | ✅ |
Studio debug UI (/studio/ui) |
✅ | ❌ |
| Verbose/dev logging | ✅ (INFO) |
❌ (WARNING) |
# Production-lean image (Studio off, quieter logs; Swagger still served)
agentomatic deploy --profile minimal --stack remote --distroless
agentomatic deploy --minimal --stack remote # shorthand
Distroless images pin Python 3.11
gcr.io/distroless/python3-debian12 is Debian 12's Python 3.11, so the
distroless build stage uses python:3.11-slim and installs dependencies
with pip --target=/app/deps (on PYTHONPATH) rather than into a
virtualenv — a venv's bin/python points at the build stage's
interpreter, which does not exist in the runtime image. If you customise
the generated Dockerfile, keep the two Python versions in step.
Swagger is always available
--profile minimal never disables /docs, /redoc, or
/openapi.json. It only sets AGENTOMATIC_ENABLE_STUDIO=0 and
AGENTOMATIC_LOG_LEVEL=WARNING; the REST API, health, metrics, and auth
stay enabled. The image still installs agentomatic[all], so no required
functionality is dropped — minimal just doesn't mount the Studio routes.
Local Docker with a host oMLX server¶
On Apple Silicon, oMLX runs natively on the host rather than inside the Linux
container. The repository's root docker-compose.yml is configured for that
topology: it publishes Agentomatic on port 8010 to avoid oMLX's usual host
port 8000, and connects to host.docker.internal:8000/v1 from the container.
# Start your local oMLX OpenAI-compatible server first.
export OMLX_API_KEY="your-local-omlx-key"
# Agentomatic uses the provider-prefixed model spec, even though oMLX itself
# advertises the raw model id from /v1/models.
export AGENTOMATIC_LIVE_MODEL="omlx/Qwen3.5-9B-MLX-4bit" # optional override
export AGENTOMATIC_API_KEY="$(openssl rand -hex 32)"
export AGENTOMATIC_CONTROL_TOKEN="$(openssl rand -hex 32)"
docker compose up --build
The Compose stack is deliberately fail-closed: it requires an API key and a
separate control-plane token, enables global authentication, and turns on
rate limiting. Put the variables in a local .env file (never commit it) for
repeatable starts. Health checks remain public; all Studio and API calls need
the API key.
The compose file mounts agents, plugins, endpoints, and ingestors read-only so
a fresh checkout has a runnable verification deployment. Pipeline definitions
are the deliberate exception: /app/pipelines is read-write because Studio's
validated visual builder saves and runs the exact YAML draft there. Mount a
durable, access-controlled directory for it in production; a read-only mount
returns a clear 409 rather than pretending that a builder save succeeded.
Mount your own agent directory before deployment:
Verify the API and the model route independently:
curl http://localhost:8010/health
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" http://localhost:8010/api/v1/agents
docker compose exec platform /app/.venv/bin/python -c '
import asyncio
from agentomatic.optimize.llm_caller import LLMCaller
print(asyncio.run(LLMCaller.call("omlx/Qwen3.5-9B-MLX-4bit", "Reply with OK.", max_tokens=8)))
'
deploy/ also includes a ready observability stack
(deploy/observability/) with Prometheus + OTel + Grafana.
Vendor backends stay yours
Register custom vector / embedding / store backends with
register_vector_provider, register_embedding_provider, and
register_store_provider. Agentomatic provides the ops; you bring the
SDK (Cosmos, proprietary search, …).
2. Keep secrets out of code¶
Every config value that touches a credential supports ${ENV} interpolation,
resolved at connection/endpoint build time — so your connections.py,
endpoint.py, and platform code stay secret-free and reviewable.
Provide the values via your orchestrator (Kubernetes Secret, Docker
--env-file, Vault sidecar, etc.). A .env file is convenient for local and
staging; never commit real secrets.
# Inbound auth (JWKS from your IdP)
JWT_JWKS_URL=https://idp.example.com/.well-known/jwks.json
JWT_ISSUER=https://idp.example.com/
JWT_AUDIENCE=agentomatic
# Per-agent databases
FRAUD_DB_URL=postgresql+asyncpg://fraud:***@db-fraud:5432/fraud
BILLING_DB_URL=postgresql+asyncpg://billing:***@db-billing:5432/billing
SUPPORT_MEMORY_DB_URL=postgresql+asyncpg://support:***@db-support:5432/memory
# Vector store for the RAG agent
QDRANT_URL=https://vector.example.com:6333
QDRANT_API_KEY=***
# Cache
REDIS_URL=redis://cache:6379/0
# Outbound model APIs (OAuth2 client-credentials)
MODEL_A_URL=https://models.example.com/a
MODEL_B_URL=https://models.example.com/b
MODEL_TOKEN_URL=https://idp.example.com/oauth2/token
MODEL_CLIENT_ID=***
MODEL_CLIENT_SECRET=***
# Control plane
CONTROL_TOKEN=***
3. Inbound authentication (who may call an agent)¶
Agentomatic separates authentication (validating the caller's token) from authorization (which agents/tools that caller may reach).
JWT / OAuth2 validation¶
Enable JWT validation once at the platform level. Tokens are verified against
your IdP's JWKS; decoded claims land on request.state.jwt_claims.
from agentomatic import AgentPlatform
from agentomatic.security import JWTConfig
platform = AgentPlatform.from_folder(
"agents/",
enable_jwt_auth=True,
jwt_config=JWTConfig(
enabled=True,
jwks_url="${JWT_JWKS_URL}", # resolved from env by your process
issuer="${JWT_ISSUER}",
audience="${JWT_AUDIENCE}",
algorithms=["RS256"],
),
)
Per-agent authorization (zero trust)¶
Turn on zero-trust and declare per-agent policies in each agent's manifest. A caller must satisfy the policy (roles/scopes) for the specific agent — one token does not grant access to all five agents.
platform = AgentPlatform.from_folder(
"agents/",
enable_jwt_auth=True,
jwt_config=JWTConfig(enabled=True, jwks_url="${JWT_JWKS_URL}"),
enable_zero_trust=True,
)
security:
require_auth: true
allowed_roles: ["billing", "admin"]
allowed_scopes: ["billing:read", "billing:write"]
See Security & Zero Trust for tool-level policies and claim
mapping. Effective policies are visible at runtime via the
control plane (GET /api/v1/control/agents).
4. Outbound connections (what an agent may reach)¶
Each agent declares its own authenticated resources in connections.py.
Connections are scoped to the agent, so credentials and pools never leak
across agents. Tag each with a purpose so features can find backends by
intent (MEMORY, RAG, VECTOR, CACHE, …).
from agentomatic.connections import (
ConnectionPurpose,
DatabaseConnectionConfig,
HttpConnectionConfig,
)
from agentomatic.endpoints import AuthType, UpstreamAuthConfig
CONNECTIONS = [
DatabaseConnectionConfig(
name="main",
url="${FRAUD_DB_URL}",
purpose=ConnectionPurpose.GENERAL,
pool_size=10,
),
HttpConnectionConfig(
name="scoring_api",
base_url="${FRAUD_SCORING_URL}",
auth=UpstreamAuthConfig(
type=AuthType.OAUTH2_CLIENT_CREDENTIALS,
token_url="${MODEL_TOKEN_URL}",
client_id="${MODEL_CLIENT_ID}",
client_secret="${MODEL_CLIENT_SECRET}",
scope="scoring:invoke",
),
),
]
from agentomatic.connections import (
ConnectionPurpose,
CustomConnectionConfig,
VectorConnectionConfig,
)
CONNECTIONS = [
VectorConnectionConfig(
name="kb",
provider="qdrant",
url="${QDRANT_URL}",
api_key="${QDRANT_API_KEY}",
collection="knowledge_base",
dimension=1536,
purpose=ConnectionPurpose.RAG,
),
# Zero-class cache: point at any factory, no wrapper needed
CustomConnectionConfig(
name="cache",
factory="redis.asyncio.from_url",
args=["${REDIS_URL}"],
purpose=ConnectionPurpose.CACHE,
),
]
Use them at runtime with almost no code:
from sqlalchemy import text
from agentomatic.connections import get_connections
conns = get_connections("fraud_agent")
# Authenticated SQL
async with conns.database("main").session() as session:
total = (await session.execute(text("SELECT count(*) FROM cases"))).scalar_one()
# Authenticated HTTP (token acquired + cached automatically)
result = await conns.http("scoring_api").post("/score", payload={"amount": 42})
# Vector search for RAG
kb = get_connections("rag_agent").vector("kb")
hits = await kb.client.search(collection_name=kb.collection, query_vector=vec, limit=5)
# Cache (native redis client, initialised on demand)
redis = await get_connections("rag_agent").client("cache")
await redis.set("k", "v", ex=60)
Conversation memory on an agent's own database
Reuse an agent's authenticated DB as its memory store — the store shares the same engine/pool:
See Per-Agent Connections for vector providers, registering custom types, and purpose-based lookups.
5. Custom APIs that call authenticated model APIs¶
When an agent needs context from one or more deployed models, expose a custom endpoint that fans out over authenticated upstreams and aggregates the results. The endpoint itself becomes a first-class route and is usable from pipelines.
from agentomatic.endpoints import (
AggregationStrategy,
AuthType,
BaseEndpoint,
UpstreamAuthConfig,
UpstreamConfig,
)
class EnsembleEndpoint(BaseEndpoint):
name = "ensemble"
description = "Fan out to two model APIs and aggregate."
aggregation = AggregationStrategy.MAJORITY
upstreams = [
UpstreamConfig(
name="model_a",
base_url="${MODEL_A_URL}",
auth=UpstreamAuthConfig(
type=AuthType.OAUTH2_CLIENT_CREDENTIALS,
token_url="${MODEL_TOKEN_URL}",
client_id="${MODEL_CLIENT_ID}",
client_secret="${MODEL_CLIENT_SECRET}",
),
),
UpstreamConfig(
name="model_b",
base_url="${MODEL_B_URL}",
auth=UpstreamAuthConfig(
type=AuthType.OAUTH2_CLIENT_CREDENTIALS,
token_url="${MODEL_TOKEN_URL}",
client_id="${MODEL_CLIENT_ID}",
client_secret="${MODEL_CLIENT_SECRET}",
),
),
]
Feed the aggregated result to an agent inside a pipeline:
name: enrich
steps:
- endpoint: ensemble # calls both models, aggregates
input: {payload: "$.input"}
output: context
- agent: fraud_agent # receives enriched context
input: {query: "$.input.query", context: "$.context"}
See Custom Endpoints for aggregation strategies, per-upstream auth types, and schema control.
6. Wire the whole platform¶
Put it together in a single entrypoint. This is the complete production configuration for the five-agent deployment:
from agentomatic import AgentPlatform
from agentomatic.security import JWTConfig
platform = AgentPlatform.from_folder(
"agents/",
title="Acme Agents",
version="1.0.0",
# Discovery of custom endpoints (defaults to "endpoints/")
endpoints_dir="endpoints/",
# --- Inbound auth ---
enable_jwt_auth=True,
jwt_config=JWTConfig(
enabled=True,
jwks_url="${JWT_JWKS_URL}",
issuer="${JWT_ISSUER}",
audience="${JWT_AUDIENCE}",
),
enable_zero_trust=True,
# --- Hardening ---
enable_rate_limit=True,
rate_limit_requests=100,
rate_limit_window=60,
cors_origins=["https://app.example.com"],
# --- Observability ---
enable_metrics=True, # /metrics (Prometheus)
enable_telemetry=True, # OpenTelemetry traces (OTLP)
# --- Operations ---
enable_control_plane=True,
control_token="${CONTROL_TOKEN}",
)
app = platform.build() # an ASGI app — serve with uvicorn/gunicorn
Run it:
Scaffolded main.py matches agentomatic run
Projects created with agentomatic init --project (and containers built by
agentomatic deploy) ship a main.py whose module-level app is feature-
identical to agentomatic run: it discovers every component directory and
turns Studio, docs, health, and metrics on by default. Auth, control plane,
and rate limiting are driven by AGENTOMATIC_* env vars
(AGENTOMATIC_ENABLE_AUTH, AGENTOMATIC_ENABLE_JWT, AGENTOMATIC_REQUIRE_AUTH,
AGENTOMATIC_ENABLE_CONTROL_PLANE, AGENTOMATIC_ENABLE_RATE_LIMIT,
AGENTOMATIC_TITLE, AGENTOMATIC_LOG_LEVEL), so uvicorn main:app in the
generated Dockerfile drops no functionality versus running the CLI.
Turning on verified JWT auth
AGENTOMATIC_ENABLE_JWT=1 alone gives you a middleware with nothing to
verify against. Point it at your identity provider's JWKS endpoint with
AUTH__JWKS_URL (plus AUTH__ISSUER / AUTH__AUDIENCE), or set the same
values in the active stack's auth: block — agentomatic deploy writes
them into the generated .env for you. Environment wins over the stack.
AGENTOMATIC_REQUIRE_AUTH=1
AUTH__JWKS_URL=https://idp.example.com/.well-known/jwks.json
AUTH__ISSUER=https://idp.example.com/
AUTH__AUDIENCE=agentomatic
With AGENTOMATIC_REQUIRE_AUTH=1 and no JWKS, the platform will not accept
unsigned tokens: it enforces with your API key if one is configured
(AGENTOMATIC_ENABLE_AUTH=1 + AGENTOMATIC_API_KEY), and refuses to start
if neither is set.
Rate limiting behind a proxy
The limiter keys on the client address, so behind a reverse proxy every
request looks like it comes from the proxy — set
AGENTOMATIC_RATE_LIMIT_TRUST_PROXY_HEADERS=1 so X-Forwarded-For is used
instead. Leave it off when the platform is exposed directly: the header
is caller-controlled, and rotating it per request would bypass the limiter.
That flag governs Agentomatic's own reading of the header. Uvicorn's
--proxy-headers (on by default) separately rewrites request.client from
X-Forwarded-For for peers in --forwarded-allow-ips (default
127.0.0.1), before any middleware runs. Keep that list limited to your
real proxy — a caller connecting from an allowed peer address can steer
the rate-limit key regardless of the flag above. The generated
nginx.conf sits on that trusted hop, which is why it is the right place
to set the header.
Workers and in-memory state
Connection pools and per-process caches live per worker. Keep shared state (threads, memory, cache) in external services (Postgres, redis) so it is consistent across workers. Control-plane state (maintenance flag, agent drain) is per-process — front it with a shared store or drive it via your orchestrator if you need cross-worker consistency.
Background tasks (async/batch/long-running jobs) are tracked in a
TaskStore. The default is in-memory (per worker), so for -w > 1 — or any
deployment where task status must survive restarts — pass a durable
SQLAlchemyTaskStore so every worker
reads/writes the same task board:
7. Observability & monitoring¶
With enable_metrics=True the app exposes Prometheus metrics at /metrics,
and with enable_telemetry=True it emits OpenTelemetry traces (configure the
OTLP endpoint via standard OTEL_* env vars).
Key metrics emitted out of the box:
| Metric | What it tracks |
|---|---|
agentomatic_endpoint_calls_total / _duration_seconds |
Custom endpoint calls |
agentomatic_upstream_calls_total / _duration_seconds |
Per-upstream model calls |
agentomatic_connection_calls_total |
DB/vector/custom connection acquisitions |
agentomatic_registered_endpoints |
Number of registered endpoints |
A ready-to-run stack (Prometheus + OpenTelemetry Collector + Grafana with a
provisioned dashboard) lives in deploy/observability/:
cd deploy/observability
docker compose up -d
# Grafana → http://localhost:3000 (Agentomatic Overview dashboard)
Point the collector/Prometheus at your app's /metrics and OTLP endpoint (see
deploy/observability/README.md). Full details in the
Observability guide.
8. Operate at runtime (control plane)¶
The control plane (mounted at {api_prefix}/control) lets you inspect and
operate the platform without redeploying. It follows the platform's normal
authentication policy: in the production Compose profile, send
X-API-Key on every control-plane request. Mutating calls additionally
require X-Control-Token when control_token is set.
# Overview + per-agent health, effective auth policy, declared connections
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" https://api.example.com/api/v1/control
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" https://api.example.com/api/v1/control/agents
# Connection health per scope (including durable platform storage), and custom endpoints
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" https://api.example.com/api/v1/control/connections
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" https://api.example.com/api/v1/control/connections/__platform__/storage
curl -H "X-API-Key: $AGENTOMATIC_API_KEY" https://api.example.com/api/v1/control/endpoints
# Drain a single agent (returns 503 for its routes), then re-enable
curl -X POST -H "X-API-Key: $AGENTOMATIC_API_KEY" -H "X-Control-Token: $CONTROL_TOKEN" \
https://api.example.com/api/v1/control/agents/fraud_agent/disable
curl -X POST -H "X-API-Key: $AGENTOMATIC_API_KEY" -H "X-Control-Token: $CONTROL_TOKEN" \
https://api.example.com/api/v1/control/agents/fraud_agent/enable
# Platform-wide maintenance mode
curl -X POST -H "X-API-Key: $AGENTOMATIC_API_KEY" -H "X-Control-Token: $CONTROL_TOKEN" \
-H "Content-Type: application/json" -d '{"enabled": true}' \
https://api.example.com/api/v1/control/maintenance
All of this is also available visually in Agentomatic Studio (Control, Endpoints, and Connections views) when it is enabled. See the Control Plane guide.
9. Containerize¶
FROM python:3.12-slim AS base
ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1
WORKDIR /app
# Install dependencies first for layer caching
COPY pyproject.toml README.md ./
RUN pip install 'agentomatic[db,security,metrics,telemetry]' qdrant-client redis
# App code (agents/, endpoints/, pipelines/, main.py)
COPY . .
EXPOSE 8000
CMD ["gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker", \
"-w", "4", "--bind", "0.0.0.0:8000", "--timeout", "120"]
services:
agentomatic:
build: .
ports: ["8000:8000"]
env_file: [.env]
depends_on: [db-fraud, cache, vector]
healthcheck:
test: ["CMD", "python", "-c",
"import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 15s
timeout: 3s
retries: 5
db-fraud:
image: postgres:16
environment:
POSTGRES_USER: fraud
POSTGRES_PASSWORD: ${FRAUD_DB_PASSWORD}
POSTGRES_DB: fraud
volumes: ["fraud-data:/var/lib/postgresql/data"]
cache:
image: redis:7-alpine
vector:
image: qdrant/qdrant:latest
ports: ["6333:6333"]
volumes:
fraud-data:
10. Health checks & readiness¶
| Endpoint | Purpose | Auth |
|---|---|---|
GET /health |
Liveness (always fast, unauthenticated; status-only diagnostics) | none (skip-path) |
GET /api/v1/{agent}/health |
Per-agent liveness | per policy |
GET /api/v1/control/health |
Aggregate health (agents + connections) | per policy (not control token) |
GET /api/v1/status |
Whole-platform status JSON (all resources + task engine) | per policy |
GET /status |
Human-readable HTML status dashboard | per policy |
Use /health for Kubernetes liveness probes. It intentionally exposes only
resource status signals; use an authenticated control-plane or status request
when an operator needs diagnostics. Use
/api/v1/control/health for a deeper readiness gate. The unified
/status dashboard is the fastest way for operators to see the
health of every agent, plugin, pipeline, endpoint, ingestor, storage, and the
task engine at a glance.
livenessProbe:
httpGet: { path: /health, port: 8000 }
initialDelaySeconds: 10
readinessProbe:
httpGet: { path: /health, port: 8000 }
periodSeconds: 10
Production checklist¶
- Installed only the extras you need (
db,security,metrics,telemetry, provider clients). - All credentials come from
${ENV}— no secrets committed. -
enable_jwt_auth=Truewith a realjwks_url,issuer, andaudience. -
enable_zero_trust=Trueand every agent has an explicitsecuritypolicy. - Rate limiting and a restrictive
cors_originslist are set. - Each agent declares its own scoped
connections.py; pools sized for load. - Shared state (threads/memory/cache) lives in external services, not process memory.
- For
workers > 1or restart-durable tasks, a durabletask_store(e.g.SQLAlchemyTaskStore) is configured. -
/status(and/api/v1/status) reviewed; all resources report healthy. -
enable_metrics=True,/metricsscraped, dashboard imported. -
enable_telemetry=Truewith the OTLP endpoint configured. -
enable_control_plane=Truewith a strongcontrol_token. - Liveness/readiness probes wired to
/health. -
uv run pytest,uv run ruff check, andmkdocs build --strictpass in CI. ```