Skip to content

Settings

z4j reads settings from env vars (primary). See env vars for the exhaustive reference; this page groups the operator-facing settings by topic for skimming.

Setting Default Notes
Z4J_DATABASE_URL - (required) postgresql+asyncpg://user:pw@host/db
Z4J_DATABASE_STATEMENT_CACHE_SIZE 50 Per-connection asyncpg prepared-statement cache cap. 0 disables.
Z4J_DATABASE_MAX_INACTIVE_CONNECTION_LIFETIME_SECONDS 60 SQLAlchemy pool_recycle. Shorter values rotate per-connection caches faster under sustained load.
Z4J_AUTO_MIGRATE true Run Alembic head migrations on brain boot. Set false for orchestrators that handle migrations separately.
Z4J_STARTUP_VERIFY_LOCK_TIMEOUT_MS 600000 How long a starting worker waits its turn for the audit-chain startup walk while sibling workers verify the same database. Scoped to that one transaction; the per-request Z4J_DB_LOCK_TIMEOUT_MS is unchanged. See scaling.

The connection pool is configurable through Z4J_DATABASE_POOL_SIZE (default 20) and Z4J_DATABASE_MAX_OVERFLOW (default 10). On PostgreSQL the brain refuses to start when the total is below what its enabled leader-gated workers need, because a pool that cannot seat them deadlocks rather than degrades. See environment variables.

Setting Default Notes
Z4J_SECRET - (required) Master HMAC signing key. Derives the per-project frame HMAC key, hashes agent tokens, and encrypts stored TOTP secrets. It does not sign sessions (that is Z4J_SESSION_SECRET below) and does not sign the audit log (that is Z4J_AUDIT_CHAIN_SECRET). At least 32 bytes; 64 hex chars recommended.
Z4J_SESSION_SECRET - (required) Session-cookie signing key, at least 32 bytes. Independent of Z4J_SECRET.
Z4J_PUBLIC_URL http://localhost:7700 Full public URL (https://z4j.example.com). The default only passes validation when Z4J_ENVIRONMENT is exactly dev; outside dev the value must use https:// (or Z4J_ALLOW_HTTP_PUBLIC_URL must be set), so it is effectively required. Validated: no whitespace, no userinfo, http(s) only.
Z4J_PREVIOUS_SECRETS - Comma-separated previous master secrets still accepted when verifying agent bearer tokens and decrypting stored secrets (TOTP secrets and notification channel configs). Writes use the new Z4J_SECRET. It does NOT cover frame signing, so rotation still requires re-credentialing every agent. Run z4j secrets rewrap to a clean report before dropping an entry; that re-encrypts every stored secret under the current master in one run. See incident response.
Z4J_PREVIOUS_SESSION_SECRETS - Comma-separated previous session secrets still accepted during cookie-rotation.
Z4J_AUDIT_CHAIN_SECRET - (required outside development) Dedicated audit-chain signing key, at least 32 bytes. Independent of Z4J_SECRET, with no fallback: the brain refuses to start without it outside development.
Z4J_AUDIT_CHAIN_PREVIOUS_SECRETS - Comma-separated previous audit-chain keys still accepted by the verifier during rotation. Writes use the current Z4J_AUDIT_CHAIN_SECRET.
Z4J_REDACTION_EXTRA_KEY_PATTERNS [] JSON array of extra key-name regexes the brain's redaction pass applies to every inbound event on top of the built-in patterns. Each entry is validated as a regex when settings load. See redaction.

Z4J_SECRET, Z4J_SESSION_SECRET and Z4J_AUDIT_CHAIN_SECRET must each be at least 32 bytes, and so must every entry in the three previous-secret lists; a shorter value refuses to load. A URL-valued setting that is not itself a secret (Z4J_PUBLIC_URL, Z4J_EXPORT_SINK_S3_ENDPOINT_URL) refuses to load with user:password@ embedded in it, and the read-only settings page strips any such userinfo from every URL it renders.

The audit-log HMAC chain is signed with Z4J_AUDIT_CHAIN_SECRET, deliberately separate from Z4J_SECRET. See HMAC audit chain for why the separation matters and how activation works on an existing deployment.

Setting Default Notes
Z4J_DASHBOARD_IP_ALLOWLIST [] CIDRs the login route and every session-cookie request must come from.
Z4J_API_IP_ALLOWLIST [] CIDRs every Bearer API-key request must come from. Each key can carry its own allowed_cidrs on top; both must admit the request.
Z4J_AGENT_IP_ALLOWLIST [] CIDRs the agent transports (WebSocket and long-poll) must come from.

All three are JSON arrays of IPv4 or IPv6 CIDRs; a bare address means that one host, and a malformed entry refuses to start. An empty list means no restriction. The address matched is the one the brain resolved after Z4J_TRUSTED_PROXIES, so an X-Forwarded-For header only counts when it arrived from a declared proxy; from anywhere else the socket peer is what gets matched. Loopback is never implicitly exempt: a list that omits 127.0.0.1/32 or ::1/128 refuses the brain's own host too. A refusal is 403 with error: "ip_denied", writes an auth.ip_denied audit row, and counts in z4j_auth_ip_denied_total{surface}. See threat model for what the lists do and do not protect.

Setting Default Notes
Z4J_PASSWORD_MIN_LENGTH 12 Default 12; configurable down to the supported floor of 8.
Z4J_ARGON2_TIME_COST 3 OWASP 2024 minimum.
Z4J_ARGON2_MEMORY_COST 65536 64 MiB, in KiB.
Z4J_ARGON2_PARALLELISM 4 Threads.

SMTP servers are not configured via env vars. Each notification channel record carries its own smtp_host, smtp_port (default 587), smtp_user, smtp_pass, smtp_tls, from_addr and to_addrs fields. See notifications and smtp-presets.

Setting Default Notes
Z4J_RECONCILIATION_SWEEP_SECONDS 300 Seconds between reconciliation passes (default 5 min).
Z4J_RECONCILIATION_STALE_THRESHOLD_SECONDS 900 Minimum age of a task still in started, pending or retry before it is eligible for reconciliation, measured from started_at (falling back to received_at, then created_at). 60 to 86400 (default 15 min).
Setting Default Notes
Z4J_EVENT_RETENTION_DAYS 30 Days raw events rows live; on PostgreSQL the partition worker drops the daily partitions past this age. The same value bounds the agent_status_history purge.
Z4J_AUDIT_RETENTION_DAYS 90 Days audit_log rows live before the retention worker or z4j audit prune removes them under the authenticated prune boundary. Minimum 1, no ceiling; above 3650 days the brain logs one startup WARNING and honours the value. Environment only, no write-back. See audit retention.
Z4J_AUDIT_RETENTION_BY_CLASS {} JSON object mapping an action class (auth, command, schedule, ...) to its own window in days; unlisted classes use Z4J_AUDIT_RETENTION_DAYS. Validated when settings load. A longer class window holds every row written after the oldest row it keeps; a shorter one only reaches rows older than every retained neighbour, because the chain only loses a contiguous prefix. See audit retention.
Z4J_AUDIT_CHAIN_VERIFY_ENABLED false Run the scheduled audit-chain verification worker. Off by default: verification walks every retained row, so an operator who has not asked for it does not pay for it. Leader-gated.
Z4J_AUDIT_CHAIN_VERIFY_INTERVAL_SECONDS 86400 Cadence for the scheduled verification. Floor 900 (15 minutes), ceiling 604800 (one week).

Background audit exports of any size and the scheduled chain-head anchor; see audit exports for the full list of sink settings.

Setting Default Notes
Z4J_EXPORT_SINK none none, local (a directory, Z4J_EXPORT_SINK_PATH) or s3 (a bucket, Z4J_EXPORT_SINK_S3_BUCKET, through the optional z4j[s3] extra). none disables export jobs and the head export.
Z4J_AUDIT_HEAD_EXPORT_INTERVAL_SECONDS 0 Write the authenticated chain head to the sink on this cadence, under a stable key plus a dated copy, for z4j audit verify --known-head. 0 disables; otherwise 60 to 604800. Needs a sink.

Off unless Z4J_AUDIT_WEBHOOK_URL is set. A leader-gated worker mirrors every audit row to the receiver from a durable cursor, at least once and in order; see audit webhook forwarding.

Setting Default Notes
Z4J_AUDIT_WEBHOOK_URL - Receiver URL; empty disables. Secret, because SIEM intake URLs embed tokens.
Z4J_AUDIT_WEBHOOK_HMAC_SECRET - Signs every row. Required with the URL, at least 32 bytes.
Z4J_AUDIT_WEBHOOK_BATCH_SIZE 100 Rows per pass; a full batch runs the next pass at once.
Z4J_AUDIT_WEBHOOK_POLL_INTERVAL_SECONDS 5.0 Poll cadence once caught up.
Z4J_AUDIT_WEBHOOK_MAX_BACKOFF_SECONDS 300.0 Ceiling on the doubling wait after consecutive failures.
Setting Default Notes
Z4J_METRICS_AUTH_TOKEN - (auto-minted on packaged SQLite) Bearer for /metrics. Auto-minted into ~/.z4j/secret.env only on the packaged SQLite bootstrap, whenever it is missing there; PostgreSQL deployments must set it explicitly or /metrics answers 401. z4j metrics-token prints; z4j metrics-token rotate rotates.
Z4J_METRICS_PUBLIC false 1 leaves /metrics open. Use only with a firewalled or proxy-authenticated endpoint.

Sentry is opt-in: pip install "z4j[sentry]" and set Z4J_SENTRY_DSN; without a DSN it is off even when the SDK is installed. OpenTelemetry tracing works the same way with z4j[otel] and Z4J_OTEL_EXPORTER_OTLP_ENDPOINT. See the Sentry and OpenTelemetry sections of environment variables. Application logs go to stdout as JSON; ship them with Fluent Bit / Vector / Loki / Datadog.

Setting Default Notes
Z4J_BOOTSTRAP_ADMIN_EMAIL - Skip the setup URL and provision an admin automatically.
Z4J_BOOTSTRAP_ADMIN_PASSWORD - Required with the email above. Eagerly popped from os.environ after use.