Environment Variables
All Hegemony configuration comes from environment variables with the HEGEMONY_* prefix, validated by the Settings model in packages/core/settings.py.
Example env files live in deploy/compose/.env.dev.example and deploy/compose/.env.prod.example.
| Variable | Type | Default | Description |
|---|---|---|---|
HEGEMONY_ENVIRONMENT | str | dev | Deployment environment name (dev, test, or prod); prod enables stricter validation |
HEGEMONY_LOG_LEVEL | str | INFO | Python logging level for all processes (DEBUG, INFO, WARNING, ERROR) |
HEGEMONY_PORT | int | 8000 | TCP port the API process binds to |
HEGEMONY_CORS_ORIGINS | str | http://localhost:5173,http://localhost:3000 | Comma-separated list of allowed CORS origins. Use '*' only in dev. |
HEGEMONY_DATABASE_URL | str | (empty) | Async PostgreSQL connection URL (postgresql+asyncpg://...) |
HEGEMONY_DB_POOL_SIZE | int | 20 | Number of connections to keep open persistently in the pool |
HEGEMONY_DB_MAX_OVERFLOW | int | 30 | Additional connections allowed when pool is exhausted |
HEGEMONY_DB_POOL_TIMEOUT | int | 30 | Seconds to wait for a connection before raising an error |
HEGEMONY_DB_POOL_RECYCLE | int | 1800 | Seconds before a connection is recycled to prevent stale connections |
HEGEMONY_DB_POOL_PRE_PING | bool | true | Verify connections are alive before checkout |
HEGEMONY_TEMPORAL_HOST | str | (empty) | Temporal server address (e.g., temporal:7233) |
HEGEMONY_TEMPORAL_NAMESPACE | str | default | Temporal namespace used for all workflows |
HEGEMONY_TEMPORAL_TASK_QUEUE | str | hegemony-tasks | Temporal task queue shared by workers and workflow starters |
HEGEMONY_SECRETS_DIR | str | /run/secrets | Directory read by the {{ file() }} template helper in platform configuration (secret backend and inventory provider settings); organization content cannot read it |
HEGEMONY_ARTIFACT_DIR | str | /data/artifacts | Filesystem directory for run artifacts when file storage is used |
HEGEMONY_DOCKER_BIN | str | docker | Path to Docker CLI binary. Env: HEGEMONY_DOCKER_BIN |
HEGEMONY_CONTAINER_DOCKER_HOST | str | (empty) | Docker daemon that runs flow container.run steps: the Docker-in-Docker sandbox, which docker-compose.dind.yml provides and points this at (tcp://dind:2375). Required: the worker refuses to start while it is empty, and there is no fallback to the host Docker daemon. The container handler, its cleanup janitor, and egress enforcement point DOCKER_HOST at this daemon on each docker invocation, so flow containers, images, and the lab estate live in the sandbox and never on the host. The override is applied per invocation and never process-wide: the worker-id derivation (apps/worker/run.py) must keep querying the daemon that runs the worker container, not this one. Env: HEGEMONY_CONTAINER_DOCKER_HOST |
HEGEMONY_CONTAINER_DOCKER_WAIT_SECONDS | int (≥ 0) | 120 | How long the worker waits at startup for the sandbox daemon (container_docker_host) to answer before starting its Temporal pollers anyway. Matters at host boot, where the Docker daemon auto-starts every container at once and the dind sandbox can lag the worker by a minute or more; without the wait, container steps dispatched in that window fail on daemon connection errors. Once the daemon answers, the worker attests it against container_sandbox_token and refuses to start on a mismatch. A daemon still silent at the deadline degrades only container steps: the worker starts, refuses every container step, and keeps probing in the background until the daemon answers, then attests it; container steps run from then on, and a failed attestation stops the worker with a non-zero exit. Orphaned flow containers and egress networks are swept only on an attested daemon, at startup or right after a late attestation. 0 disables the wait but not the probe: the worker asks the daemon once, attests it (or refuses to start) if it answers, and otherwise starts at once and attests it in the background the same way. Env: HEGEMONY_CONTAINER_DOCKER_WAIT_SECONDS |
HEGEMONY_CONTAINER_SWEEP_INTERVAL_SECONDS | int (≥ 0) | 60 | How often the worker looks for step containers on the sandbox daemon whose run ended at least two minutes ago, and stops and removes them. A step's own worker removes its container when the step ends or is cancelled; a container still there that long after the run ended belongs to a worker that died, and would otherwise run on (a tf.apply until its step deadline). The sweep sends SIGTERM and waits the container's stop timeout, at most two minutes, before it removes the container. For a tf step that is its stop grace period, and the tool gets the SIGTERM to save its state and unlock. Runs only while the sandbox daemon is attested. 0 disables it. Env: HEGEMONY_CONTAINER_SWEEP_INTERVAL_SECONDS |
HEGEMONY_CONTAINER_SANDBOX_TOKEN | str | (empty) | Deployment-scoped attestation token proving container_docker_host points at the provisioned sandbox daemon. dind-init stamps the same value into the daemon's marker volume label (hegemony.sandbox.token); compose sets both from HEGEMONY_SANDBOX_TOKEN. Required: the worker refuses to start without it, stops on a daemon whose label differs (at startup, or once a sandbox that was late at startup answers), runs no container step before the daemon has attested, and compares the label again before programming any egress firewall rule; the sandbox image-pruning job fails without it or on a daemon whose label differs, pruning nothing. So a mispointed endpoint never runs flow containers or has its firewalling or images mutated. Env: HEGEMONY_CONTAINER_SANDBOX_TOKEN |
HEGEMONY_CONTAINER_EGRESS_HELPER_IMAGE | str | docker:28-dind | Image for the short-lived helper container that programs DOCKER-USER egress rules inside the sandbox daemon's netns. Deliberately the same pinned image as the dind service so the iptables binary and backend cannot diverge from the tables dockerd writes. Env: HEGEMONY_CONTAINER_EGRESS_HELPER_IMAGE |
HEGEMONY_CONTAINER_EGRESS_NFLOG_GROUP | int | 0 | nfnetlink_log group for per-destination egress denial detail. When non-zero, each policied step's accounting mirror gains a rate-limited NFLOG sampler ahead of every drop-role rule, tagged with a per-step prefix, and the egress-nflog sidecar (ulogd2 sharing the sandbox daemon's netns, started with the sandbox by docker-compose.dind.yml) writes the sampled packets as JSON. The compose stack sets 32. 0, the default outside compose, emits no NFLOG rules — reports then carry rule-level counters only. Env: HEGEMONY_CONTAINER_EGRESS_NFLOG_GROUP |
HEGEMONY_CONTAINER_EGRESS_NFLOG_FILE | str | (empty) | Path where the egress-nflog sidecar's JSON stream is readable from inside the worker container (docker-compose.dind.yml mounts the shared volume read-only at /var/log/hegemony-egress). Empty disables the read: enforcement and NFLOG emission are unaffected, the step report simply carries no per-destination denial detail. Deliberately separate from container_egress_nflog_group — the rules and the reader can be rolled out independently. Env: HEGEMONY_CONTAINER_EGRESS_NFLOG_FILE |
HEGEMONY_STACK_NAME | str | (empty) | Deployment stack identifier (compose project name, e.g. hegemony-dev). Step handlers stamp it on flow containers as the hegemony.stack label, and container cleanup skips containers labeled with a different stack, so stacks pointed at one sandbox daemon never reap each other's containers. Empty disables stack scoping. Env: HEGEMONY_STACK_NAME |
HEGEMONY_WORKER_ID | str | (empty) | Stable identifier for this worker host. Used to build the per-host Temporal task queue (hegemony-host-<worker_id>) for shared/explicit execution affinity. When empty, the worker derives a stable Compose container name via the host Docker socket (the socket's only use: container steps run on the sandbox), then falls back to the OS hostname. Env: HEGEMONY_WORKER_ID |
HEGEMONY_SHARED_WORKSPACES_ENABLED | bool | true | Enable shared-workspace execution affinity (worker pinning + per-run shared volume). When disabled, all steps run distributed regardless of their declared affinity. Env: HEGEMONY_SHARED_WORKSPACES_ENABLED |
HEGEMONY_SHARED_WORKSPACE_ROOT | str | /data/shared | Directory inside the worker container that holds per-run shared workspaces (<root>/<run_id>/). Normally the mount point of the shared-workspace Docker volume (see shared_workspace_volume). The worker creates <root>/<run_id> here before each pinned step runs and removes it when the run ends. At worker start, a directory older than 24 hours is removed too, but only once the API reports its run ended, so a run waiting at an approval keeps its workspace however long it waits. Env: HEGEMONY_SHARED_WORKSPACE_ROOT |
HEGEMONY_SHARED_WORKSPACE_VOLUME | str | (empty) | Name of the Docker volume backing per-run shared workspaces. When set, pinned steps mount only their run's subdirectory at /shared via --mount type=volume,...,volume-subpath=<run_id> (requires Docker Engine 26.1+); docker-compose.dind.yml sets it, and dind-init registers the volume on the sandbox daemon. When empty, the worker falls back to bind-mounting shared_workspace_root/<run_id> at /shared, a path the sandbox daemon resolves on its own filesystem rather than the worker's. Env: HEGEMONY_SHARED_WORKSPACE_VOLUME |
HEGEMONY_WORKER_HEARTBEAT_INTERVAL_SECONDS | int (≥ 1) | 15 | Interval at which the worker refreshes its heartbeat row used for shared-worker assignment. Env: HEGEMONY_WORKER_HEARTBEAT_INTERVAL_SECONDS |
HEGEMONY_WORKER_HEARTBEAT_STALE_SECONDS | int (≥ 1) | 60 | Age after which a worker heartbeat is considered stale and the worker is excluded from shared-worker assignment. Env: HEGEMONY_WORKER_HEARTBEAT_STALE_SECONDS |
HEGEMONY_API_BASE_URL | str | http://api:8000 | Base URL workers use to call back into the internal API |
HEGEMONY_DOCS_BASE_URL | str | https://hegemony.sh | Base URL the UI's Help drawer links to for the full documentation site. Point at an internally hosted docs copy for air-gapped deployments, or set to an empty string to hide external documentation links entirely; page-level help is bundled into the UI and works offline regardless |
HEGEMONY_UI_BASE_URL | str | http://localhost:5173 | Base URL for Hegemony UI (used in notification messages for deep links) |
HEGEMONY_SCHEDULE_POLL_INTERVAL_SECONDS | int (≥ 1) | 15 | Polling interval for schedule execution loop |
HEGEMONY_MAINTENANCE_ENABLED | bool | true | Enable the scheduler maintenance loop. Env: HEGEMONY_MAINTENANCE_ENABLED |
HEGEMONY_MAINTENANCE_TICK_INTERVAL_SECONDS | int (≥ 1) | 30 | Polling interval for the scheduler maintenance loop in seconds. Env: HEGEMONY_MAINTENANCE_TICK_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_TICK_TIMEOUT_SECONDS | int (≥ 1) | 120 | HTTP timeout for a single maintenance tick request in seconds. Env: HEGEMONY_MAINTENANCE_TICK_TIMEOUT_SECONDS |
HEGEMONY_MAINTENANCE_JOB_LEASE_SECONDS | int (≥ 30) | 600 | Lease duration for a claimed maintenance job in seconds. Expired leases may be reclaimed. Env: HEGEMONY_MAINTENANCE_JOB_LEASE_SECONDS |
HEGEMONY_MAINTENANCE_RUN_STATUS_SYNC_INTERVAL_SECONDS | int (≥ 0) | 300 | Interval for run status reconciliation in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_RUN_STATUS_SYNC_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_RUN_STATUS_SYNC_BATCH_SIZE | int (≥ 1, ≤ 1000) | 200 | Maximum runs reconciled per run status sync job execution. Env: HEGEMONY_MAINTENANCE_RUN_STATUS_SYNC_BATCH_SIZE |
HEGEMONY_MAINTENANCE_APPROVAL_TIMEOUTS_INTERVAL_SECONDS | int (≥ 0) | 300 | Interval for approval timeout reconciliation in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_APPROVAL_TIMEOUTS_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_APPROVAL_TIMEOUTS_BATCH_SIZE | int (≥ 1, ≤ 1000) | 200 | Maximum pending approvals scanned per approval timeout job execution. Env: HEGEMONY_MAINTENANCE_APPROVAL_TIMEOUTS_BATCH_SIZE |
HEGEMONY_MAINTENANCE_STALE_MONITORS_INTERVAL_SECONDS | int (≥ 0) | 300 | Interval for stale monitor cleanup in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_STALE_MONITORS_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_STALE_MONITORS_BATCH_SIZE | int (≥ 1, ≤ 5000) | 500 | Maximum stale monitors stopped per job execution. Env: HEGEMONY_MAINTENANCE_STALE_MONITORS_BATCH_SIZE |
HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_INTERVAL_SECONDS | int (≥ 0) | 0 | Interval for RunEvent pruning in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_FILE_REPOSITORY_BACKFILL_INTERVAL_SECONDS | int (≥ 0) | 3600 | Interval for the per-org internal file-repository backfill in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_FILE_REPOSITORY_BACKFILL_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_RUN_EVENT_RETENTION_DAYS | int (≥ 1) | 90 | RunEvent retention window in days for terminal runs. Env: HEGEMONY_MAINTENANCE_RUN_EVENT_RETENTION_DAYS |
HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_BATCH_SIZE | int (≥ 1, ≤ 50000) | 5000 | Maximum RunEvent rows deleted per pruning batch. Env: HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_BATCH_SIZE |
HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_MAX_BATCHES | int (≥ 1, ≤ 100) | 5 | Maximum RunEvent pruning batches per job execution. Env: HEGEMONY_MAINTENANCE_RUN_EVENT_PRUNING_MAX_BATCHES |
HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_INTERVAL_SECONDS | int (≥ 0) | 86400 | Interval for the audit log retention job in seconds. 0 disables the job; it is also a no-op while HEGEMONY_AUDIT_RETENTION_DAYS is unset. Env: HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_BATCH_SIZE | int (≥ 1, ≤ 50000) | 5000 | Maximum audit log rows deleted per retention batch. Env: HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_BATCH_SIZE |
HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_MAX_BATCHES | int (≥ 1, ≤ 100) | 20 | Maximum audit log retention batches per job execution. Env: HEGEMONY_MAINTENANCE_AUDIT_LOG_RETENTION_MAX_BATCHES |
HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_INTERVAL_SECONDS | int (≥ 0) | 86400 | Interval for the inventory sync history retention job in seconds. 0 disables the job; it is also a no-op while HEGEMONY_INVENTORY_SYNC_HISTORY_RETENTION_DAYS is 0. Env: HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_BATCH_SIZE | int (≥ 1, ≤ 50000) | 5000 | Maximum inventory sync history rows deleted per retention batch. Env: HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_BATCH_SIZE |
HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_MAX_BATCHES | int (≥ 1, ≤ 100) | 20 | Maximum inventory sync history retention batches per job execution. Env: HEGEMONY_MAINTENANCE_INVENTORY_SYNC_HISTORY_RETENTION_MAX_BATCHES |
HEGEMONY_MAINTENANCE_SANDBOX_IMAGE_PRUNING_INTERVAL_SECONDS | int (≥ 0) | 21600 | Interval in seconds for reclaiming dangling images and build cache on the Docker-in-Docker sandbox daemon, which otherwise grow without bound (design-dind-sandbox.md §6.4). 0 disables the job. It deletes nothing unless container_docker_host points at a tcp:// daemon that attests with container_sandbox_token; a missing endpoint or token, or a daemon that does not attest, fails the job run rather than skipping it, so a sandbox that is never pruned shows in platform health. Env: HEGEMONY_MAINTENANCE_SANDBOX_IMAGE_PRUNING_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_SANDBOX_PRUNE_BUILD_CACHE | bool | true | Prune the sandbox daemon's build cache alongside dangling images. The cache is regenerable, so dropping it costs a slower next docker build and nothing else. Env: HEGEMONY_MAINTENANCE_SANDBOX_PRUNE_BUILD_CACHE |
HEGEMONY_PLATFORM_SYNC_ENABLED | bool | true | Enable Platform Sync API surface and scheduled jobs. Env: HEGEMONY_PLATFORM_SYNC_ENABLED |
HEGEMONY_PLATFORM_SYNC_PLAN_TTL_SECONDS | int (≥ 60) | 1800 | Plan validity window in seconds. Env: HEGEMONY_PLATFORM_SYNC_PLAN_TTL_SECONDS |
HEGEMONY_PLATFORM_SYNC_MAX_BUNDLE_FILES | int (≥ 1) | 50000 | Maximum files allowed in a sync bundle. Env: HEGEMONY_PLATFORM_SYNC_MAX_BUNDLE_FILES |
HEGEMONY_PLATFORM_SYNC_MAX_FILE_BYTES | int (≥ 1) | 1048576 | Maximum bytes per bundle file. Env: HEGEMONY_PLATFORM_SYNC_MAX_FILE_BYTES |
HEGEMONY_PLATFORM_SYNC_CLONE_TIMEOUT_SECONDS | int (≥ 1) | 120 | Git clone/fetch timeout in seconds. Env: HEGEMONY_PLATFORM_SYNC_CLONE_TIMEOUT_SECONDS |
HEGEMONY_PLATFORM_SYNC_LOCK_TIMEOUT_SECONDS | int (≥ 1) | 5 | Advisory lock timeout in seconds. Env: HEGEMONY_PLATFORM_SYNC_LOCK_TIMEOUT_SECONDS |
HEGEMONY_CONFIG_EXCHANGE_PLAN_TTL_SECONDS | int (≥ 60) | 1800 | Two-step preview/apply plan validity window for the CX façade in seconds. Mirrors Platform Sync plan TTL. Env: HEGEMONY_CONFIG_EXCHANGE_PLAN_TTL_SECONDS |
HEGEMONY_CONFIG_EXCHANGE_PLAN_INLINE_BYTES | int (≥ 1) | 1048576 | Maximum payload size (in bytes) stored inline in config_exchange_import_plans.content_bytes. Larger payloads are rejected in v1 (object-store key reserved for v2). Env: HEGEMONY_CONFIG_EXCHANGE_PLAN_INLINE_BYTES |
HEGEMONY_CONFIG_EXCHANGE_OPERATIONS_PAGE_SIZE | int (≥ 1, ≤ 500) | 50 | Default page size for the CX operations projection. Env: HEGEMONY_CONFIG_EXCHANGE_OPERATIONS_PAGE_SIZE |
HEGEMONY_BOOTSTRAP_ENABLED | bool | false | Import mounted Configuration Exchange YAML bundles once per database during API startup. Disabled by default so production instances never auto-import mounted files; the demo compose overlay enables it explicitly. Env: HEGEMONY_BOOTSTRAP_ENABLED |
HEGEMONY_BOOTSTRAP_DIR | str | /bootstrap | Directory scanned for instance bootstrap .yaml/.yml bundles. Env: HEGEMONY_BOOTSTRAP_DIR |
HEGEMONY_BOOTSTRAP_ENABLE_SCHEDULES | bool | false | Allow instance bootstrap imports to preserve enabled schedules from YAML. Normal Config Exchange imports still disable schedules by default. Env: HEGEMONY_BOOTSTRAP_ENABLE_SCHEDULES |
HEGEMONY_MAINTENANCE_PLATFORM_SYNC_EXPORT_INTERVAL_SECONDS | int (≥ 0) | 300 | Interval for platform sync export maintenance job in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_PLATFORM_SYNC_EXPORT_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_PLATFORM_SYNC_DRIFT_INTERVAL_SECONDS | int (≥ 0) | 900 | Interval for platform sync drift plan maintenance job in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_PLATFORM_SYNC_DRIFT_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_PLATFORM_SYNC_AUTO_APPLY_INTERVAL_SECONDS | int (≥ 0) | 0 | Interval for platform sync auto-apply maintenance job in seconds. 0 disables the job. Env: HEGEMONY_MAINTENANCE_PLATFORM_SYNC_AUTO_APPLY_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_PLATFORM_SYNC_BATCH_SIZE | int (≥ 1, ≤ 1000) | 10 | Profiles processed per platform sync maintenance tick. Env: HEGEMONY_MAINTENANCE_PLATFORM_SYNC_BATCH_SIZE |
HEGEMONY_MAINTENANCE_INVENTORY_PROVIDER_SYNC_INTERVAL_SECONDS | int (≥ 0) | 60 | Interval for the inventory provider sync maintenance job in seconds. The job scans for provider configs whose per-provider sync_interval_seconds has elapsed. 0 disables the job. Env: HEGEMONY_MAINTENANCE_INVENTORY_PROVIDER_SYNC_INTERVAL_SECONDS |
HEGEMONY_MAINTENANCE_INVENTORY_PROVIDER_SYNC_BATCH_SIZE | int (≥ 1, ≤ 1000) | 20 | Provider configs processed per inventory provider sync maintenance tick. Env: HEGEMONY_MAINTENANCE_INVENTORY_PROVIDER_SYNC_BATCH_SIZE |
HEGEMONY_WEBHOOK_MAX_BODY_BYTES | int (≥ 1024, ≤ 10485760) | 1048576 | Maximum allowed inbound webhook body size in bytes |
HEGEMONY_WEBHOOK_GLOBAL_INGRESS_PER_MINUTE | int (≥ 1, ≤ 1000000) | 6000 | Global ceiling on public webhook requests per minute for this API instance, charged before the endpoint lookup. Shared across all endpoints; a backstop, not a per-endpoint throughput limit. |
HEGEMONY_WEBHOOK_INGRESS_LIMIT_MULTIPLIER | int (≥ 1, ≤ 1000) | 10 | Ingress budget for public webhook deliveries, as a multiple of an endpoint's rate_limit_per_minute. Sized from the endpoint row, so it is charged just after that lookup and before authentication, the body read, the secret backend and any delivery write. |
HEGEMONY_KEYCLOAK_ISSUER | str | (empty) | Keycloak realm issuer URL for API validation (e.g., http://keycloak:8081/realms/hegemony) |
HEGEMONY_KEYCLOAK_PUBLIC_ISSUER | str | (empty) | Keycloak realm URL for browser (e.g., http://localhost:8081/realms/hegemony) |
HEGEMONY_KEYCLOAK_AUDIENCE | str | hegemony-api | Expected audience claim in access tokens |
HEGEMONY_KEYCLOAK_JWKS_CACHE_TTL | int | 3600 | JWKS cache TTL in seconds |
HEGEMONY_AUTH_DISABLED | bool | false | Disable authentication (for local dev only, NEVER in production) |
HEGEMONY_DEFAULT_ORG_SLUG | str | default | Slug of the bootstrap organization: new users auto-join it (when enabled) and platform admins fall back to it when no X-Org-Id header is sent. Env: HEGEMONY_DEFAULT_ORG_SLUG |
HEGEMONY_ORG_AUTO_JOIN | bool | true | Auto-join users with no org memberships to the default org on first login, with a role mapped from their Keycloak realm roles. Disable once multi-org onboarding is managed explicitly. Env: HEGEMONY_ORG_AUTO_JOIN |
HEGEMONY_ORG_IDP_SYNC | bool | false | Derive org memberships from an identity-provider group claim on each login (JIT provisioning), reconciled against the admin-managed IdP mapping table. Works with Keycloak groups and any brokered IdP (Azure AD, Okta, ...) whose groups Keycloak maps into the token. Manual memberships are never touched. Opt-in. Env: HEGEMONY_ORG_IDP_SYNC |
HEGEMONY_ORG_IDP_GROUP_CLAIM | str (length ≥ 1) | groups | Token claim carrying the caller's IdP group/org identifiers used for IdP-driven membership sync. Defaults to the standard Keycloak 'groups' claim. Env: HEGEMONY_ORG_IDP_GROUP_CLAIM |
HEGEMONY_ORG_IDP_SYNC_AUTHORITATIVE | bool | true | When IdP sync is on, treat the IdP as authoritative for IdP-sourced memberships: remove an IdP-granted membership once its mapped group disappears from the token. Set false for additive-only sync (never auto-remove). Env: HEGEMONY_ORG_IDP_SYNC_AUTHORITATIVE |
HEGEMONY_SHARED_ORG_SECRET_SCOPE | str | shared_resources | Which runs may resolve secrets from the designated shared organization's namespace (orgs/<shared-slug>/...). 'shared_resources' (default): only runs that execute a shared-org flow, target a shared-org device, or notify a shared-org destination, plus notifications of such runs or sent to a shared-org destination. 'always': every run and notification in every organization - the behaviour before this setting existed, where any flow author can read any shared-org secret value; set it explicitly to keep it. Env: HEGEMONY_SHARED_ORG_SECRET_SCOPE |
HEGEMONY_BFF_TICKET_STORE | str | memory | Backend for BFF session tickets: 'memory' (single API instance only) or 'redis' (required for load-balanced/multi-replica deployments). Env: HEGEMONY_BFF_TICKET_STORE |
HEGEMONY_BFF_TICKET_REDIS_URL | str | (empty) | Redis connection URL for the BFF ticket store, e.g. redis://redis:6379/0. Required when bff_ticket_store='redis'. Env: HEGEMONY_BFF_TICKET_REDIS_URL |
HEGEMONY_BFF_TICKET_REDIS_SOCKET_CONNECT_TIMEOUT_SECONDS | float (> 0) | 2.0 | Socket connect timeout in seconds for the Redis-backed BFF ticket store. Keep this short so ticket issuance/consumption fails fast when Redis is unreachable. Env: HEGEMONY_BFF_TICKET_REDIS_SOCKET_CONNECT_TIMEOUT_SECONDS |
HEGEMONY_BFF_TICKET_REDIS_SOCKET_TIMEOUT_SECONDS | float (> 0) | 5.0 | Socket read/write timeout in seconds for the Redis-backed BFF ticket store. Keep this short so SSE auth degrades quickly when Redis is unhealthy. Env: HEGEMONY_BFF_TICKET_REDIS_SOCKET_TIMEOUT_SECONDS |
HEGEMONY_AUDIT_RETENTION_DAYS | int | None (≥ 0) | (unset) | Number of days to retain audit log entries. None = keep forever. Set to e.g., 90 for 90-day rolling window. Must be non-negative if set. |
HEGEMONY_AUDIT_STRICT_VOCABULARY | bool | false | Reject audit entries whose action, resource type, or event type is not in the audit vocabulary (AuditAction, AuditResourceType, and the event namespaces in packages.core.audit) instead of logging a warning and storing them as given. On in the test suite; leave off in production so a stray literal never blocks the change it describes. Env: HEGEMONY_AUDIT_STRICT_VOCABULARY |
HEGEMONY_AUDIT_DETAILS_MAX_BYTES | int (≥ 4096) | 65536 | Upper bound in bytes for one audit entry's details. Above it the before/after snapshots are replaced by their sha256 digests and the entry is marked truncated; the field-level changes are always kept. Env: HEGEMONY_AUDIT_DETAILS_MAX_BYTES |
HEGEMONY_TRUST_PROXY_HEADERS | bool | false | Take the client address recorded on audit entries from the first X-Forwarded-For hop. Enable only when the API sits behind a proxy that sets the header, because any client can send one; without it the recorded address is the proxy's. Env: HEGEMONY_TRUST_PROXY_HEADERS |
HEGEMONY_AUDIT_LOG_MIRROR | bool | false | Also write every committed audit entry to the structured log (logger hegemony.audit) for log shipping. Entries lost to a rollback and failed writes are always logged, mirror or not. Env: HEGEMONY_AUDIT_LOG_MIRROR |
HEGEMONY_AUDIT_DENIAL_THROTTLE_SECONDS | int (≥ 0) | 10 | Window in seconds during which repeated access denials by the same caller on the same route are counted instead of each getting an audit entry; the first entry after the window carries the count as suppressed_count. 0 records every denial. Env: HEGEMONY_AUDIT_DENIAL_THROTTLE_SECONDS |
HEGEMONY_KEYCLOAK_UI_CLIENT_ID | str | hegemony-ui | OIDC client ID for the UI (public client). Env: HEGEMONY_KEYCLOAK_UI_CLIENT_ID |
HEGEMONY_INTERNAL_API_TOKEN | str | (empty) | Shared secret token for internal API calls from workers. Env: HEGEMONY_INTERNAL_API_TOKEN |
HEGEMONY_INTERNAL_API_TOKEN_OPTIONAL | bool | false | Allow missing internal API token in dev environments. Env: HEGEMONY_INTERNAL_API_TOKEN_OPTIONAL |
HEGEMONY_TF_STATE_KEY_BACKEND | str | (empty) | Tag of the secret backend whose Transit engine wraps managed state keys (OpenBao or Vault). Empty uses the internal OpenBao when it is set up, otherwise HEGEMONY_TF_STATE_ENCRYPTION_KEY; 'none' always uses that key. A Transit failure is a 503, never a switch to another key. Env: HEGEMONY_TF_STATE_KEY_BACKEND |
HEGEMONY_TF_STATE_ENCRYPTION_KEY | str | (empty) | Base64 of a 32-byte key that encrypts managed state when no Transit backend is configured (no internal OpenBao, or HEGEMONY_TF_STATE_KEY_BACKEND=none). Losing or changing it loses every state encrypted with it: back it up with the database. Env: HEGEMONY_TF_STATE_ENCRYPTION_KEY |
HEGEMONY_TF_STATE_MAX_BYTES | int (≥ 1048576, ≤ 134217728) | 33554432 | Largest managed state accepted, in bytes (uncompressed), at most 128 MiB. The API needs about 2.5 times this in memory for each state saved at once. Env: HEGEMONY_TF_STATE_MAX_BYTES |
HEGEMONY_TF_STATE_KEEP_VERSIONS | int (≥ 0) | 50 | Versions kept per managed state; older ones are deleted when a new one is written. 0 keeps all. Env: HEGEMONY_TF_STATE_KEEP_VERSIONS |
HEGEMONY_TF_STATE_RUN_END_GRACE_SECONDS | int (≥ 0, ≤ 86400) | 600 | How long a run step keeps its managed-state token and lock after its run ends, so a step still stopping after a cancel can save its state. The lock is released as soon as the worker reports the step's container gone; this only bounds a worker that never does. After a worker crash the run can end within minutes while the tool still runs, and the workers' container sweep stops the tool 120 s after the run's end at the earliest, plus up to one HEGEMONY_CONTAINER_SWEEP_INTERVAL_SECONDS, plus its stop timeout (at most 120 s), plus the time its API and Docker calls take. Keep the grace longer than that: at 480 or more with the default sweep interval. A shorter grace can free the lock while the tool still runs. Env: HEGEMONY_TF_STATE_RUN_END_GRACE_SECONDS |
HEGEMONY_SANDBOX_API_BASE_URL | str | (empty) | Base URL step containers use to reach the API (managed state). Empty uses HEGEMONY_API_BASE_URL; the worker resolves its host name and hands the address to the container. Env: HEGEMONY_SANDBOX_API_BASE_URL |
HEGEMONY_PAT_PEPPER | str | (empty) | Server-side pepper mixed into PAT hashing via HMAC-SHA-256. Required in production. Env: HEGEMONY_PAT_PEPPER |
HEGEMONY_PAT_MAX_LIFETIME_DAYS | int (≥ 0) | 365 | Maximum days a PAT can be valid for at creation time. 0 disables the cap. Env: HEGEMONY_PAT_MAX_LIFETIME_DAYS |
HEGEMONY_API_EXTERNAL_URL | str | (empty) | External API URL reachable by network devices. Example: http://192.168.1.100:8000. If not set, constructed from s3_external_url host. |
HEGEMONY_IMAGE_REPO_BASE_URL | str | (empty) | Base HTTPS URL for file downloads (must be worker-reachable) |
HEGEMONY_IMAGE_REPO_MODE | str | http | File repository mode: 'http' or 's3' (v1 supports only 'http') |
HEGEMONY_IMAGE_REPO_LOCAL_CACHE_DIR | str | /data/images | Local cache directory for downloaded files |
HEGEMONY_IMAGE_REPO_REQUEST_TIMEOUT_SECONDS | int | 600 | HTTP request timeout for file downloads |
HEGEMONY_IMAGE_REPO_MAX_IMAGE_SIZE_BYTES | int | 4294967296 | Maximum allowed file size in bytes |
HEGEMONY_RUN_ARTIFACT_MAX_FILE_SIZE_BYTES | int (> 0) | 52428800 | Maximum size in bytes for a downloadable binary run artifact. Generated files larger than this are skipped. Env: HEGEMONY_RUN_ARTIFACT_MAX_FILE_SIZE_BYTES |
HEGEMONY_UPGRADE_DEFAULT_RECONNECT_TIMEOUT_SECONDS | int | 1800 | Default timeout for reconnecting after device reboot |
HEGEMONY_UPGRADE_RECONNECT_POLL_SECONDS | int | 10 | Poll interval when waiting for device reconnection |
HEGEMONY_S3_ENDPOINT_URL | str | http://objectstore:9000 | S3-compatible endpoint URL (the bundled object store in dev) |
HEGEMONY_S3_EXTERNAL_URL | str | (empty) | External S3 URL reachable by network devices (for HTTP transfers). If not set, falls back to s3_endpoint_url. Example: http://192.168.1.100:9000 |
HEGEMONY_S3_REGION | str | us-east-1 | S3 region (the bundled object store uses us-east-1 by default) |
HEGEMONY_S3_ACCESS_KEY_ID | str | (empty) | S3 access key ID (from env, never log) |
HEGEMONY_S3_SECRET_ACCESS_KEY | str | (empty) | S3 secret access key (from env, never log) |
HEGEMONY_S3_BUCKET | str | hegemony | S3 bucket name for file storage |
HEGEMONY_S3_PREFIX | str | files | Object key prefix for stored files |
HEGEMONY_S3_PRESIGN_EXPIRY_SECONDS | int | 3600 | Expiry time for presigned URLs in seconds |
HEGEMONY_S3_EXTRA_BUCKETS | str | (empty) | Comma-separated additional buckets the API creates in the bundled object store at startup, e.g. buckets referenced by extra file repositories seeded via Configuration Exchange. Only with HEGEMONY_S3_INTERNAL_ENABLED. Env: HEGEMONY_S3_EXTRA_BUCKETS |
HEGEMONY_S3_SEED_DIR | str | /seed | Directory whose <bucket>/<key...> tree the API uploads into the bundled object store at startup when it exists (demo golden artifacts). Existing objects of the same size are skipped. Only with HEGEMONY_S3_INTERNAL_ENABLED. Env: HEGEMONY_S3_SEED_DIR |
HEGEMONY_REGISTRY_ENABLED | bool | false | Run the platform's own container registry (the registry compose overlay). Container steps then keep copies of the images they pull in it and pull the copies on later runs, and the authorize route behind the registry proxy answers. Env: HEGEMONY_REGISTRY_ENABLED |
HEGEMONY_REGISTRY_HOST | str | registry.hegemony.internal | Host name image references use for the platform registry, as the sandbox daemon reaches it: a network alias of the registry proxy, which the overlay lists in the daemon's insecure registries. No scheme, no path. Env: HEGEMONY_REGISTRY_HOST |
HEGEMONY_REGISTRY_URL | str | http://registry.hegemony.internal | Base URL the worker reaches the platform registry's HTTP API at, scheme included, no path. Env: HEGEMONY_REGISTRY_URL |
HEGEMONY_REGISTRY_BACKEND_URL | str | http://172.29.241.10:5000 | Base URL the API reaches zot itself at, on the registry overlay's internal network, for the Container Images pages (listing and deleting past the proxy, which lets no one else do that). zot's fixed address there, not its service name, which resolves to its address on the compose network, where it does not listen. Scheme included, no path; only the API uses it. Env: HEGEMONY_REGISTRY_BACKEND_URL |
HEGEMONY_REGISTRY_PROXY_SECRET | str | (empty) | Shared secret the registry proxy sends in X-Hegemony-Registry-Proxy on every authorize request; without it the authorize route answers 404. The API refuses to start without it when the registry is enabled; the worker does not use it. Env: HEGEMONY_REGISTRY_PROXY_SECRET |
HEGEMONY_REGISTRY_BUCKET | str | hegemony-registry | Bucket the platform registry stores images in, created at API startup: with the other buckets when HEGEMONY_S3_INTERNAL_ENABLED, on its own with an external object store (the platform's S3 key then needs CreateBucket, or create the bucket beforehand). Env: HEGEMONY_REGISTRY_BUCKET |
HEGEMONY_GIT_CACHE_MAX_SIZE_MB | int (≥ 1) | 500 | Maximum size of the on-disk git cache in megabytes. Env: HEGEMONY_GIT_CACHE_MAX_SIZE_MB |
HEGEMONY_GIT_CACHE_DIR | str | (empty) | Directory path for on-disk git cache. Env: HEGEMONY_GIT_CACHE_DIR |
HEGEMONY_INVENTORY_CACHE_DEFAULT_TTL_SECONDS | int (≥ 0) | 300 | Default inventory preview cache TTL in seconds. Env: HEGEMONY_INVENTORY_CACHE_DEFAULT_TTL_SECONDS |
HEGEMONY_INVENTORY_CACHE_MAX_ENTRIES | int (≥ 1) | 256 | Maximum process-local inventory preview cache entries. Env: HEGEMONY_INVENTORY_CACHE_MAX_ENTRIES |
HEGEMONY_INVENTORY_MAX_PREVIEW_DEVICES | int (≥ 1) | 500 | Maximum devices returned by inventory preview APIs. Env: HEGEMONY_INVENTORY_MAX_PREVIEW_DEVICES |
HEGEMONY_INVENTORY_MAX_RUN_TARGETS | int (≥ 1) | 10000 | Maximum devices targetable by one run. Env: HEGEMONY_INVENTORY_MAX_RUN_TARGETS |
HEGEMONY_INVENTORY_MAX_PROVIDER_PAGES | int (≥ 1) | 100 | Maximum pages fetched from an inventory provider per operation. Env: HEGEMONY_INVENTORY_MAX_PROVIDER_PAGES |
HEGEMONY_INVENTORY_MAX_GIT_FILES | int (≥ 1) | 50000 | Maximum YAML files scanned by the Git inventory provider. Env: HEGEMONY_INVENTORY_MAX_GIT_FILES |
HEGEMONY_INVENTORY_MAX_GIT_FILE_BYTES | int (≥ 1) | 1048576 | Maximum bytes per Git inventory YAML file. Env: HEGEMONY_INVENTORY_MAX_GIT_FILE_BYTES |
HEGEMONY_INVENTORY_MAX_SELECTOR_DEPTH | int (≥ 1) | 5 | Maximum recursive target selector depth. Env: HEGEMONY_INVENTORY_MAX_SELECTOR_DEPTH |
HEGEMONY_INVENTORY_PROVIDER_ALLOWED_HOSTS | str | (empty) | Optional CSV hostname allow-list for HTTP inventory providers. Env: HEGEMONY_INVENTORY_PROVIDER_ALLOWED_HOSTS |
HEGEMONY_INVENTORY_PROVIDER_ALLOWED_CIDRS | str | (empty) | Optional CSV CIDR allow-list for HTTP inventory providers. Env: HEGEMONY_INVENTORY_PROVIDER_ALLOWED_CIDRS |
HEGEMONY_INVENTORY_WRITE_ENABLED | bool | false | Future inventory provider writeback feature flag. Env: HEGEMONY_INVENTORY_WRITE_ENABLED |
HEGEMONY_INVENTORY_SYNC_HISTORY_RETENTION_DAYS | int (≥ 0) | 30 | Days of inventory sync history kept per provider; older runs are deleted by the inventory_sync_history_retention job. 0 keeps every run forever. Env: HEGEMONY_INVENTORY_SYNC_HISTORY_RETENTION_DAYS |
HEGEMONY_INVENTORY_SYNC_HISTORY_KEEP_LAST | int (≥ 1) | 20 | Newest sync history rows kept per provider regardless of age, so a provider that has not synced in a long time keeps the record of its last runs. Env: HEGEMONY_INVENTORY_SYNC_HISTORY_KEEP_LAST |
HEGEMONY_INVENTORY_SYNC_DEADLINE_SECONDS | int (≥ 0) | 900 | Cumulative time budget for one inventory provider sync's calls to the provider (listing sites, devices and objects). A sync past it is recorded as a timeout error and its claim released for the next run. 0 disables the deadline. Env: HEGEMONY_INVENTORY_SYNC_DEADLINE_SECONDS |
HEGEMONY_OPENBAO_INTERNAL_ENABLED | bool | false | Auto-provision and reconcile the bundled Internal OpenBao backend on API startup. The compose openbao-internal overlay sets this to true. Env: HEGEMONY_OPENBAO_INTERNAL_ENABLED (deprecated alias: HEGEMONY_VAULT_INTERNAL_ENABLED) |
HEGEMONY_S3_INTERNAL_ENABLED | bool | true | Treat the HEGEMONY_S3_* endpoint as the bundled object store: create its buckets, seed it, and auto-provision and reconcile the managed file repository on API startup. Env: HEGEMONY_S3_INTERNAL_ENABLED |