Skip to content

Configuration ​

This page is synchronized from the canonical English documentation. Español navigation is available; commands and product limits are identical in every locale.

Copy .env.example to .env and fill it in.

Where this page says a variable has a code default, that is the value the application uses when the variable is unset. Where it says a deployment default, the value comes from the shipped Compose or Helm manifests and the code has no default of its own.

Required startup credentials ​

VariablePurpose
PRAETOR_API_KEYRequired startup secret in production, and Praetor's credential toward the Action Gateway. Not the inbound request key
PRAETOR_MASTER_KEYMaster key for the encrypted secrets vault. Minimum 32 characters
JWT_SECRETHS256 signing key for access and refresh tokens. Minimum 32 characters; known public defaults are rejected. Always required, in every environment
PRAETOR_CAPABILITY_TOKEN_KEYHMAC key for API-surface capability tokens
PRAETOR_INTEGRITY_KEYHMAC key for WAL event signing. Distinct from PRAETOR_AUDIT_CHAIN_KEY
PRAETOR_EVIDENCE_JWKS_JSONPublic JWKS string used by the API to verify Ed25519-signed action evidence. Required by the base Compose file (${PRAETOR_EVIDENCE_JWKS_JSON:?})
ADMIN_PASSWORDInitial admin password. Minimum 16 characters; the default value is rejected

Enforcement differs by environment. In production, a missing or weak value for these aborts startup with process.exit(1). Outside production, a missing value produces a warning and startup continues — except JWT_SECRET, which is always required. ADMIN_PASSWORD is required only in production or when PRAETOR_API_REPLICAS > 1. DATABASE_URL (connecting as role commander_app) is strictly required by the API server's auth subsystem in all environments.

Generate each secret with openssl rand -hex 32.

Profile and environment ​

These decide which of the guards above apply, so set them deliberately.

VariableDefaultPurpose
PRAETOR_PROFILEresolvedenterprise or standard. Explicit value always wins, even over production detection
PRAETOR_ENV—production or prod marks a production environment
NODE_ENV—production marks a production environment

Resolution order when PRAETOR_PROFILE is unset: production detection (NODE_ENV=production or PRAETOR_ENV=production|prod) resolves to enterprise; otherwise standard.

The enterprise profile changes several behaviours: /api/openapi.json returns 410, legacy execution is blocked, and tenant headers cannot establish identity.

Server ​

VariableCode defaultPurpose
PORT4000API listen port
API_HOST127.0.0.1Listen interface. Docker and Helm set 0.0.0.0
WEB_PORT5173CORS allowlist and OIDC redirect origin only — never a listen port
WEB_ORIGINhttp://localhost:$WEB_PORTOverrides the OIDC redirect origin
CORS_ORIGINSlocalhost onlyComma-separated origins. Never * in production. Unset warns
TRUST_PROXY_HOPStrust no proxyNumber of reverse-proxy hops to trust. A malformed value aborts startup. Set it behind a load balancer or rate limiting keys on the proxy IP
PRAETOR_LOG_PERSISTfalsePersist structured logs to SQLite
PRAETOR_AUTH_PROTECT_HEALTHfalseRequire auth on /health, /health/detailed, /ready, and /metrics
PRAETOR_API_REPLICAS—Replica count. Above 1 forces ADMIN_PASSWORD

Logging levels and format. The logger's built-in level default is info and its format default is pretty. The format is read from LOGFORMAT (no underscore); LOG_FORMAT is not read. LOG_LEVEL is not wired to the environment in the current code — deploy manifests set PRAETOR_LOG_LEVEL, which the logger also does not read. To control log verbosity today you must set it programmatically.

Log persistence degrades under backpressure: once the queue exceeds 10,000 entries, debug and info are dropped while warn, error, and critical are retained; at twice the threshold the oldest entries are also dropped.

Rate limiting ​

The window is fixed at 60 seconds.

VariableDefaultPurpose
API_RATE_LIMIT120Requests per window, default for every scope
API_RATE_LIMIT_USERAPI_RATE_LIMITPer-user limit
API_RATE_LIMIT_TENANTAPI_RATE_LIMITPer-tenant limit
AUTH_MAX_FAILURES5Failed auth attempts before IP lockout
AUTH_LOCKOUT_MS300000Lockout duration (5 minutes)

Tier multipliers are applied on top: health endpoints ×10, reads ×1, writes ×0.25.

The CLI separately limits costly commands to 10 LLM-costly invocations per minute across processes.

Providers ​

Set at least one provider key. Praetor detects which provider you configured. See Providers for the full list of 25 and the exact variable for each — several are not what you would guess (Cohere uses CO_API_KEY, GLM uses ZHIPU_API_KEY, Replicate uses REPLICATE_API_TOKEN).

VariablePurpose
OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY, …Provider credentials
OPENAI_BASE_URL, OPENAI_MODELOverride endpoint and model
AZURE_OPENAI_BASE_URL, AZURE_OPENAI_MODEL, AZURE_OPENAI_API_VERSIONAzure OpenAI
OLLAMA_HOST, VLLM_BASE_URLLocal / self-hosted providers
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGIONAWS Bedrock
PRAETOR_MIN_SENSITIVE_MODEL_TIERModel-tier floor for sensitive steps: eco | standard | power | consensus (default standard)

Adding a provider is one step: append a registerProvider() call in packages/core/src/runtime/providers/providerRegistry.ts. The registry derives the order, env map, default URLs, default models, display names, and API type automatically.

Storage ​

VariableDefaultPurpose
API_STORE_BACKENDsqlitesqlite | memory | postgres
DATABASE_URL—PostgreSQL DSN; implies the postgres backend when API_STORE_BACKEND is unset
PRAETOR_KERNEL_ENABLEDautoEnable the Postgres-backed shared execution kernel
PRAETOR_KERNEL_DATABASE_URLDATABASE_URLKernel DSN
PRAETOR_EVENT_SOURCING_WAL.commander_state/event-sourcing.walWAL path for deterministic replay
PRAETOR_ALLOW_MEMORY_STORE—Explicit opt-in for in-memory stores in production

PRAETOR_KERNEL_ENABLED is not off by default. It is enabled automatically when NODE_ENV=production, when PRAETOR_V2_MODE=1, or when a kernel DSN is present. An explicit 0 or 1 overrides that — and production refuses an explicit 0.

In production the API fails closed (StoreBackendConfigError) when neither API_STORE_BACKEND nor DATABASE_URL is set. Local state lives under .commander_state/; commander_state holds the WAL and is the source of truth for crash recovery.

Multi-tenancy ​

VariableDefaultPurpose
TENANT_CONFIG_PATH—Path to the tenant config file
PRAETOR_DEFAULT_TENANT_IDlocalDefault tenant claim

Tenant mode is selected by the presence of TENANT_CONFIG_PATH: unset or missing file gives the null (single-tenant) provider; a readable file gives the simple static provider. TENANT_PROVIDER is not read by the application — it only appears in the Helm chart, which passes it through.

Event bus and observability ​

VariableDefaultPurpose
PRAETOR_EVENT_BUS_BACKENDmemorymemory or redis
PRAETOR_EVENT_BUS_REDIS_URLnoneRedis URL. redis://redis:6379 is a Compose default, not a code default
OTEL_EXPORTER_OTLP_ENDPOINT—OTLP collector endpoint (e.g. http://jaeger:4318)
PRAETOR_OTEL_ENABLEDenabledSet to false to disable the OTLP exporter
PRAETOR_AUDIT_CHAIN_KEY—Enables HMAC hash-chaining of the security audit log. Opt-in
PRAETOR_AUDIT_MANIFEST_DIR—Enables the RSA-PSS L2 audit manifest. Opt-in
GRAFANA_ADMIN_PASSWORDadminDeployment-only. Change before exposing a dashboard

Worker plane ​

VariablePurpose
PRAETOR_WORKER_BOOTSTRAPModule path exporting createWorkerService(). Required — there is no permissive fallback
PRAETOR_WORKER_AUTH_TOKENWorker registration identity. Required by bootstrap, not merely optional
PRAETOR_WORKER_AUTH_SUBJECTDefault worker:<workerId>
PRAETOR_WORKER_CAPABILITIESCode default agent; Compose and Helm set agent,tool,connector
PRAETOR_WORKER_TENANTSExplicit tenant allowlist. * and empty are rejected at bootstrap
PRAETOR_WORKER_MAX_CONCURRENCYConcurrent step executions per worker (default 10)
PRAETOR_WORKER_LEASE_TTL_MSLease duration (default 30000)
PRAETOR_WORKER_HEARTBEAT_MSHeartbeat interval (default 10000)
PRAETOR_WORKER_POLL_MSPoll interval (default 250)
PRAETOR_WORKER_IDDefault worker-<8 hex>
PRAETOR_WORKER_KINDDefault agent
PRAETOR_OPS_HEALTH_PORTkernel-ops health port (default 8081)
PRAETOR_ADAPTER_OPS_HEALTH_PORTadapter-ops health port (default 8082)
PRAETOR_WORKER_HEALTH_PORTworker health port. No code default — unset disables the health server. 8083 is a Compose/Helm default
PRAETOR_EFFECT_BROKER_SEEDEffect broker seed material

Worker and adapter-ops authority uses Ed25519 PEM/JWKS/key-id (PRAETOR_CAPABILITY_PRIVATE_KEY_PEM, PRAETOR_CAPABILITY_KEY_ID, PRAETOR_CAPABILITY_JWKS_JSON, PRAETOR_EVIDENCE_SIGNING_PRIVATE_KEY_PEM, PRAETOR_EVIDENCE_SIGNING_KEY_ID) — never the HMAC env used by the API surface. See Security and privacy.

Sandbox and safety ​

VariableDefaultPurpose
PRAETOR_ALLOW_NO_SANDBOXfalseFail closed when no OS-level sandbox is available. Forbidden in production
PRAETOR_SANDBOX_ISOLATIONdocker in prod/staging, process otherwiseOnly process, docker, or gvisor. process is rejected in production
PRAETOR_SANDBOX_MODE—Selects a sandbox profile. Can never select full-access
PRAETOR_MCP_ALLOWED_COMMANDSsee belowExtra allowed base commands for MCP stdio servers
PRAETOR_MCP_ALLOW_UVXunsetAllows uvx. Not in the default allowlist despite what .env.example says

The core MCP client allows node, nodejs, python, python3, bun, and deno by default. npx is always forbidden and uvx requires PRAETOR_MCP_ALLOW_UVX=1. The API /mcp discovery path uses a separate hardcoded allowlist of node, python, and python3, and does not read PRAETOR_MCP_ALLOWED_COMMANDS.

Execution mode and legacy surfaces ​

VariableDefaultPurpose
PRAETOR_LEGACY_EXECUTIONunsetSet to 1 to allow legacy /api/runs and /api/orchestrator
PRAETOR_V2_MODEunsetForces the V2 kernel on and disables legacy execution
PRAETOR_V2_BENCH_HARNESSunsetMounts the /v2 benchmark routes. Never enable in production
PRAETOR_ALLOW_ANONunsetAllows anonymous API access. Default is deny
AUTH_DISABLEDunsetReturns 500 in production by design; outside production still requires PRAETOR_ALLOW_ANON=1

Legacy execution requires all of: PRAETOR_LEGACY_EXECUTION=1, NODE_ENV not production, PRAETOR_V2_MODE not 1, and a non-enterprise profile. Otherwise /api/runs returns 410 LEGACY_EXECUTION_GONE and /api/orchestrator is not mounted at all.

Action Gateway and protocols ​

VariablePurpose
PRAETOR_ACTION_GATEWAY_URLGateway base URL. Required in production and enterprise MCP mode, and required by commander action
PRAETOR_A2A_AUTH_TOKENA2A bearer token, minimum 16 characters. Missing it returns 500

OIDC ​

VariableDefaultPurpose
OIDC_ENABLEDpersisted configEnable or disable OIDC
OIDC_ISSUER—Issuer URL. Must be HTTPS
OIDC_CLIENT_ID—Client identifier
OIDC_ROLE_CLAIMrolesClaim carrying roles
OIDC_ADMIN_ROLES['admin']Roles mapped to admin
OIDC_OPERATOR_ROLES['operator','developer']Roles mapped to operator
OIDC_TENANT_CLAIMtenant_idClaim carrying the tenant
OIDC_DEFAULT_TENANT_ID—Fallback tenant
OIDC_ISSUER_HOST_ALLOWLIST—Optional issuer host restriction

Configuration is persisted at .commander/oidc-config.json. Linking an OIDC identity to a local user by email requires email_verified to be true.

Database TLS ​

VariablePurpose
PRAETOR_DATABASE_TLS_CA_FILECA bundle
PRAETOR_DATABASE_TLS_EXPECTED_SERVER_SPKI_SHA256Pinned server SPKI SHA-256 (64 hex chars)

The Postgres DSN must carry exactly sslmode=verify-full. Any other ssl* parameter is rejected, rejectUnauthorized is forced on, and both the CA file and the SPKI pin are required.

MIT licensed.