Skip to content

Configuration Reference & Flag Audit

This is the single, authoritative inventory of every environment variable agent-utilities reads, with a verdict for each: is the flag actually needed, or should the system detect and self-configure instead?

It exists because the codebase had grown to ~96 distinct KG_* / GRAPH_* / EPISTEMIC_* / AGENT_UTILITIES_* flags — over-configuration that is overwhelming to operate and a frequent source of footguns. The rule for adding new flags is in AGENTS.md → Configuration discipline. The CI gate scripts/check_no_env_sprawl.py enforces that flags are declared on AgentConfig (core/config.py), not read with bare os.environ.get() scattered across modules.

How configuration is read (two centralized paths)

core/config.py (and core/paths.py) are the only files that touch os.environ. Every other module reads through one of two paths, both driven by config.json — the XDG loader injects ~/.config/agent-utilities/config.json (or AGENT_UTILITIES_CONFIG_DIR) into os.environ before anything reads it, so a JSON key graph_db_uri becomes GRAPH_DB_URI:

  1. Typed AgentConfig field (Field(alias="MY_VAR"), read config.my_var) — for static settings parsed once at import.
  2. config.setting("MY_VAR", default, cast=…) — the sanctioned accessor for reads that must stay live (daemon cadences, test-varied flags, runtime toggles). It reads os.environ at call time with a declared default and type coercion (inferred from the default's type, or pass cast).

Decision: field for static, setting() for dynamic — never a bare os.environ.get / os.getenv / os.environ[...] read in a module.

The fold is complete: ZERO bare env reads remain anywhere in agent_utilities/ (every prefix — KG_*, GRAPH_*, AGENT_*, VAULT_*, OTEL_*, connector creds, …). Deployment-varying/behavioral flags → setting() (or a typed field); pure load/cadence tunables → auto-sized via compute_ingest_worker_count() or named module constants. scripts/check_no_env_sprawl.py covers every prefix and its baseline (scripts/env_flag_baseline.txt) is empty — any new bare read fails CI. setting() itself lives in the dependency-free core/_env.py (re-exported by config) so it stays importable while config is still initializing.

Verdict legend - KEEP — legitimate deployment config (path / DSN / secret / port / socket). Must be read via the central config object, not bare os.environ. - AUTO — should be auto-detected/auto-sized from the runtime; the flag should be removed (or kept only as an override with an auto default). - REMOVE — always-on behavior or stale experiment; remove the flag.

A. Deployment config — KEEP (read via AgentConfig)

Flag Default What it sets
GRAPH_DB_URI / PGGRAPH_DSN none Postgres/pg-age mirror DSN
GRAPH_MIRROR_TARGETS unset There is no engine-mode selector or read/write-authority selector left to configure: the epistemic-graph engine is unconditionally the sole authority. Setting this (comma-separated mirror names resolved via KG_CONNECTIONS) opts into lossless async fan-out of committed writes to durable mirrors (Postgres/pg-age, Neo4j, FalkorDB, Ladybug) for interop/BI/DR; mirrors are never on the read path. Unset = no mirrors, zero-infra
EPISTEMIC_GRAPH_SOCKET /tmp/epistemic-graph.sock Rust engine UDS
GRAPH_PERSISTENCE_PATH, GRAPH_SERVICE_PERSIST_DIR data dir Engine durable snapshot dir
GRAPH_DB_HOST/PORT/NAME/USER/PASSWORD/PATH — DSN parts (legacy; prefer GRAPH_DB_URI)
GRAPH_FUSEKI_URL/USER/PASSWORD/DATASET — SPARQL endpoint (optional backend)
GITLAB_INSTANCES none JSON list of GitLab instances to index/query — the multi-tenant source of truth shared by the KG GitLab indexer and the gitlab-api connector registry. Each entry {"name":<str>,"url":<str>,"token":<str>,"verify_ssl":<bool>}. Unset → single-host GITLAB_URL/GITLAB_TOKEN (CONCEPT:AU-KG.backend.declared-columns-so-schema)
GRAPH_PGGRAPH_SCHEMA public Postgres schema
AGENT_UTILITIES_{CONFIG,DATA,CACHE,LOG,MEMORY,RUNTIME}_DIR XDG Path overrides (resolved in core/paths.py)
AGENT_UTILITIES_HOST_INVENTORY unset JSON object mapping exact canonical host identities to abstract capability roles for host-scoped resource admission; malformed, missing, or unknown identities fail closed. Read live via setting() in governance/lanes.py.
AU_LANE_TEMP_ROOT unset Short absolute disk-backed root for per-lane Cargo, pytest, scratch, and pre-commit partitions; unset keeps the default ~/.al/<hash(common_dir, lane)>. Relative or file-valued roots fail closed; Cargo projects must export their exact CARGO_TARGET_DIR from lane env when this is set.
AGENT_UTILITIES_TOKEN_SECRET — Run-scoped tool-token secret
KG_DAEMON_ROLE auto host/client/auto election (topology)
STATE_DB_URI none Externalize ALL durable state (durable-exec checkpoints, sessions/turns/goals, KG task queue) to a shared Postgres; unset keeps the zero-infra per-host SQLite files (CONCEPT:AU-OS.state.unified-durable-state-externalization)
STATE_DB_POOL_SIZE 8 Max connections in the ONE shared state-store psycopg pool (CONCEPT:AU-OS.state.unified-durable-state-externalization)
TASK_QUEUE_BACKEND none (auto) Ingest task queue: sqlite|postgres|kafka. Unset = auto (postgres when STATE_DB_URI set, else sqlite). Explicit kafka/postgres is FAIL-LOUD at startup (CONCEPT:AU-KG.backend.selectable-queue-backend)
KG_TASKS_PARTITIONS 6 Partitions ensured on the kg_tasks topic at startup (grow-only, never shrinks); bounds kg-ingest consumer-group parallelism (CONCEPT:AU-KG.backend.keyed-ingest-partitions)
AGENT_DISPATCH_BACKEND inline How agent turns (goal runs / orchestrator jobs) dispatch: inline keeps the in-process execution; queue publishes a session-keyed envelope onto the agent_turns queue (transport follows TASK_QUEUE_BACKEND) and returns a job handle for the agent-dispatch-worker fleet (CONCEPT:AU-ORCH.dispatch.queue-agent-dispatch)
AGENT_TURNS_PARTITIONS 6 Partitions ensured on the agent_turns topic when Kafka carries dispatched agent turns (grow-only); bounds fleet-wide concurrent-session parallelism (CONCEPT:AU-ORCH.dispatch.queue-agent-dispatch)
ENGINE_LIFECYCLE refcounted Lifecycle of an autostarted local engine (CONCEPT:AU-OS.deployment.engine-resolver-auto-provision): refcounted = reference-counted idle shutdown (self-stops ENGINE_IDLE_SHUTDOWN_SECS after the last client disconnects — the shared-tiny default, auto-stops when idle) · persistent = LONG-LIVING, never auto-stops even when idle (runs like a local service; forces idle-shutdown off). A remote/cluster engine is inherently persistent
ENGINE_IDLE_SHUTDOWN_SECS 60 Idle-shutdown grace (seconds) for a refcounted autostarted engine; >0 passes --idle-shutdown-secs <secs> to the engine. <=0 (or engine_lifecycle=persistent) = long-living, no flag passed. Gracefully omitted against an older engine binary that doesn't advertise the flag (CONCEPT:AU-OS.deployment.engine-resolver-auto-provision)
EPISTEMIC_GRAPH_STARTUP_TIMEOUT_SECS 300 Readiness deadline for a locally autostarted unified engine. Large durable stores and one-time snapshot/.mp→redb migrations can delay listener bind for minutes; values are fail-closed and bounded to 5–1800 seconds. Configured remote engines do not use this timeout.
GRAPH_SERVICE_ENDPOINTS unset Engine coordinator/bootstrap contacts (comma/JSON list). 2+ entries = tenant-partitioned sharding via HRW over graph names; unset/1 = single-engine zero-infra default (CONCEPT:AU-KG.sharding.tenant-partitioned-sharding-hrw). This remains the only topology/autostart input: unset selects the local/self-contained path (share a running local engine, else autostart one); set selects the remote, connect-only path (never autostarted). For a placed group, authenticated ClusterMembers is the sole live endpoint/leader/certificate authority; static group maps and route endpoint hints are migration/audit inputs only. Three earlier, separately-configured switches for this same decision were retired outright — a config.json or environment that still carries any of them hard-fails boot (core/config.py _RETIRED_CONFIGURATION_KEYS). See docs/recipes/unified-self-contained.md
GRAPH_CLUSTER_ID unset Optional pinned sha256:<digest> cluster identity. A missing pin is still bound to the first authenticated discovery snapshot for the process and is never an endpoint source.
GRAPH_CLUSTER_DISCOVERY_MAX_AGE_S / GRAPH_CLUSTER_DISCOVERY_CLOCK_SKEW_S 30 / 5 Freshness and certificate-clock bounds for last-good ClusterMembers discovery; stale, wrong-context, or invalid snapshots fail closed.
GRAPH_DRAIN_TIMEOUT_S 15 Maximum GraphOS/MCP transport-drain wait on shutdown or pod termination; a timeout explicitly does not claim session continuity.
KG_DEFAULT_GRAPH __bus__ Default named graph; in sharded mode the ambient ActorContext tenant maps it to tenant__<t>__<base> before HRW (CONCEPT:AU-KG.sharding.tenant-partitioned-sharding-hrw)
KG_WATCH_DIRS unset Operator document directories the file-watcher auto-ingests recursively, unified with the built-in ScholarX/research download dirs. New files are ingested and modified files re-ingested on the 5s watch tick; unchanged files delta-skip by content hash (CONCEPT:EG-KG.storage.nonblocking-checkpoint). Value is a JSON array or an os.pathsep/comma-separated list of paths (~ expanded), e.g. ~/Documents. config.json key: kg_watch_dirs. Resolved by sdd/watcher.py:get_watched_directories()
GRAPH_SERVICE_AUTH_SECRET auto-generated Engine HMAC secret; unset → per-install secret persisted at data_dir()/engine_secret (0600) (CONCEPT:AU-OS.identity.authenticated-identity-enforcement)
KG_ENGINE_INSECURE false Dev opt-out of engine HMAC auth; sets EPISTEMIC_GRAPH_ALLOW_INSECURE=1 on spawned engines (CONCEPT:AU-OS.identity.authenticated-identity-enforcement)
KG_AUTH_REQUIRED false Require server-validated JWT identity for KG access — 401 without it; caller _actor/_roles/_tenant kwargs ignored (CONCEPT:AU-OS.identity.authenticated-identity-enforcement)
KG_AUTH_TOKEN — JWT minting the stdio MCP process identity (validated against AUTH_JWT_JWKS_URI) (CONCEPT:AU-OS.identity.authenticated-identity-enforcement)
DATA_RESIDENCY_REGION "" (unknown) The region this deployment's durable store physically writes into — a fact about topology, not a policy judgement. Consulted ONLY when a contributing source actually restricts residency; unknown then DENIES the durable KV write rather than defaulting open (CONCEPT:AU-OS.governance.authority-derived-persistence-eligibility). A deployment whose sources are all residency-unrestricted never needs to set it. Read via setting() in mcp/tools/engine_surface_tools._checkpoint_manager
KG_ACL_DEFAULT_ALLOW false With KG_BRAIN_ENFORCE on: allow nodes WITHOUT an ACL (escape hatch from the fail-closed default-deny) (CONCEPT:AU-OS.identity.authenticated-identity-enforcement)
(no longer configurable) connector default ACL always quarantined The dev/local opt-in back to a public-by-default unconfigured connector was removed outright: default_external_access() (protocols/source_connectors/base.py) now unconditionally returns ExternalAccess.quarantined() (deny-by-default, AU-P0-4) for any mcp_package/mcp_tool document with no acl_* fields — there is no environment escape hatch back to the legacy public default
(baked-in, no env var) MANDATORY_NAMED_CONNECTOR_SOURCES 12 identifiers AU-P1-6: the 12 high-value named connectors (jira/confluence [atlassian-agent], gitlab, servicenow, leanix, langfuse, tunnel_manager, microsoft-agent, container-manager-mcp, documentdb-mcp, repository-manager, systems-manager, vector-mcp) are unconditionally required to pass the manifest gate — no operator opt-in needed, and no operator-extensible allowlist layered on top (that opt-in mechanism was removed; the mandatory baseline is the only enforcement). Resolved via the live fleet agents/ checkout first, then the manifests bundled in-repo (connector_manifest_gate.bundled_manifests_root(), knowledge_graph/ontology/connector_manifests/) as a pinned fallback. See the constant's docstring for the honest scope note on which of the 12 have a live sync_source call site today.
SOURCE_SYNC_ALLOW_EMPTY_TOMBSTONE* "" (empty) Comma-separated allowlist of source keys (e.g. "leanix,twenty") that MAY tombstone every previously-known node when a reconcile pass returns a genuinely empty live-id set. Empty by default: a transient fetch failure/skip (fetch_ok=False) never tombstones in either case of this list; an empty-but-successful fetch only tombstones for a source named here. Read in knowledge_graph/core/source_sync._reconcile (AU-P0-4)
KG_AMBIENT_EPISTEMIC true W3.4 ambient epistemics for connector ingestion (CONCEPT:AU-KG.temporal.ambient-connector-valid-time / AU-KG.ingest.ambient-connector-provenance): maps a source record's own reported timestamp onto its bitemporal valid_from/valid_to (never fabricated — a source with no usable timestamp writes neither), and records one PROV-O :Activity + one summary :Claim per connector sync run (never per row). false reproduces pre-W3.4 behavior byte-for-byte. Read via _ambient_epistemic_enabled(), knowledge_graph/ingestion/envelope_ingest.py
KG_AMBIENT_EPISTEMIC_DISABLED_SOURCES "" (empty) Comma-separated per-source opt-out from KG_AMBIENT_EPISTEMIC (e.g. "noisy-source,untrusted-source") — a named sync_source source key skips ambient valid-time/provenance stamping even while the global default stays ON. Same allowlist convention as SOURCE_SYNC_ALLOW_EMPTY_TOMBSTONE above
INGESTION_CONFIDENCE_THRESHOLDS {} (empty) JSON object mapping a domain/pack name to its minimum governed-promotion confidence (e.g. {"cmdb": 0.8, "wiki": 0.5}, CONCEPT:AU-KG.ingest.governed-claim-promotion). A domain with no entry falls back to the conservative promotion.DEFAULT_CONFIDENCE_THRESHOLD (0.65, matching the existing global kb.extraction_run.NEEDS_REVIEW_CONFIDENCE_THRESHOLD). ONE bounded mapping, not a per-domain flag family — read in knowledge_graph/ingestion/promotion.resolve_confidence_threshold()
KG_ENGINE_POOL_SIZE 0 Max warm per-tenant engine clients per process (elastic LRU pool over AU-KG.sharding.tenant-partitioned-sharding-hrw routing); 0 = per-use construction (CONCEPT:AU-KG.sharding.elastic-over-kg-shard)
KG_ENGINE_POOL_DROP_ON_EVICT false On pool eviction also unload the tenant's named graph from the engine to reclaim memory — only safe when a durable mirror holds the data (CONCEPT:AU-KG.sharding.elastic-over-kg-shard)
GATEWAY_METRICS true Python-tier Prometheus middleware + GET /metrics on the gateway (CONCEPT:AU-OS.observability.no-op-without-metrics)
GATEWAY_RATE_LIMIT 0 (off) Per-tenant token-bucket rate limit, sustained req/s; buckets are per-process (CONCEPT:AU-OS.observability.no-op-without-metrics)
GATEWAY_RATE_BURST 0 (→ 2× rate) Token-bucket burst capacity (CONCEPT:AU-OS.observability.no-op-without-metrics)
GATEWAY_WORKERS 1 Pre-forked gateway worker processes on one shared listen socket; the flock host-lock elects ONE KG host among them (CONCEPT:AU-OS.observability.no-op-without-metrics)
ENGINE_BREAKER_THRESHOLD 5 Consecutive engine connect/timeout failures before the client circuit opens (0 = off) (CONCEPT:AU-OS.observability.no-op-without-metrics)
ENGINE_BREAKER_COOLDOWN 15 Seconds an open engine circuit waits before the half-open probe (CONCEPT:AU-OS.observability.no-op-without-metrics)
MCP_CHILD_MAX_CONCURRENCY 8 Max in-flight tool calls per multiplexer child (0 = unlimited); per-server max_concurrency override in mcp_config.json (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_QUEUE_TIMEOUT 30 Seconds an excess call queues for a child slot before the typed MCPChildBusyError; per-server queue_timeout override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_POOL_SIZE 1 Session-pool size for remote (streamable-http/SSE) children — N round-robin connections for parallel calls; stdio stays single-pipe; per-server pool_size override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_MAX_RESTARTS 5 Auto-restarts a crashed child may consume inside the window before being parked failed (0 = no auto-restart); per-server max_restarts override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_RESTART_WINDOW 300 Sliding window (s) for the restart budget; older restarts are forgiven; per-server restart_window override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_BREAKER_THRESHOLD 5 Consecutive transport failures/timeouts before a child's circuit opens (typed MCPChildCircuitOpenError, 0 = off); per-server breaker_threshold override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_CHILD_BREAKER_COOLDOWN 15 Seconds an open child circuit waits before the half-open probe; per-server breaker_cooldown override (CONCEPT:AU-ECO.mcp.profile-differences-from-client)
MCP_ALWAYS_LOAD four core servers Fleet servers mounted EAGERLY on a session's first contact, before any find_tools round trip. Ships tunnel-manager-mcp, systems-manager-mcp, repository-manager-mcp, container-manager-mcp — the cross-cutting operational capability an agent needs for almost any task. Mounting is fail-soft: a broken server logs loudly and degrades to lazy discovery, never blocking startup. [] restores fully-lazy (CONCEPT:AU-ECO.multiplexer.tool-gateway-catalog)
MCP_ALWAYS_LOAD_TOOLS github/gitlab issues + PR/MR INDIVIDUAL tools mounted eagerly, for servers too large to mount whole. Entries are <server>:<tool> (preferred — survives a prefix shift) or an already-prefixed name. Same fail-soft contract (CONCEPT:AU-ECO.multiplexer.tool-gateway-catalog)
MCP_DYNAMIC_TOP_K 8 Default number of ranked candidates find_tools returns when top_k is unspecified (CONCEPT:AU-ECO.multiplexer.tool-gateway-catalog)
MCP_CATALOG_PROBE_TTL 300.0 Freshness window (s) for a cached fleet-probe result. Past this age list_catalog/find_tools report the entry stale: true (computed from age_s, never a bare echo of the narrow in-flight stale flag) and probe_catalog re-targets it for a background re-probe — never blocking the caller, which still gets the honest last-known answer meanwhile (CONCEPT:AU-ECO.multiplexer.catalog-probe-ttl-staleness)
ACTION_POLICY_PATH shipped default Operational ActionPolicy YAML; empty → conservative deploy/action-policy.default.yml (everything mutating = approval_required). KG governance_rule overrides win (CONCEPT:AU-OS.deployment.fleet-lifecycle-control)
FLEET_RECONCILER false Opt-in leader-only desired-state fleet reconciler tick — diff registry vs observed, converge through the ActionPolicy gate + actuator seam (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
FLEET_RECONCILER_INTERVAL 120 Seconds between fleet-reconciler ticks (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
FLEET_RECONCILER_MAX_ACTIONS 5 Storm guard: max convergence actions per tick, rest deferred (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
FLEET_REGISTRY_PATH shipped registry Fleet service registry YAML; empty → deploy/mcp-fleet.registry.yml (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
FLEET_DESIRED_STATE_PATH unset Optional desired-state override YAML (per-service replicas/desired/version) layered on the registry (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
FLEET_ACTUATOR dryrun Actuator selection: dryrun (records intent, mutates nothing), docker (reference CLI actuator), or k8s/kubernetes (optional kubectl Deployment actuator). Portainer/Swarm actuators remain deployment-wired via set_fleet_actuator() (CONCEPT:AU-OS.config.desired-state-fleet-reconciler)
DEPLOY_WATCH_WINDOW 300 Health-watch window (s) after a deploy/restart; failure inside the window triggers the policy-gated rollback (CONCEPT:AU-OS.config.health-gated-deploy-rollback)
DEPLOY_WATCH_POLL 15 Seconds between health probes inside a deploy watch (CONCEPT:AU-OS.config.health-gated-deploy-rollback)
FLEET_AUTOSCALER false Opt-in leader-only reactive replica autoscaler tick — load signal → registry-declared min/max bounds → policy-gated scale_service + deploy watch (CONCEPT:AU-OS.scaling.reactive-replica-autoscaling)
FLEET_AUTOSCALER_INTERVAL 60 Seconds between autoscaler ticks (CONCEPT:AU-OS.scaling.reactive-replica-autoscaling)
SCALING_PROMETHEUS_URL unset Prometheus base URL for autoscaling signals (instant /api/v1/query GETs); unset → zero-infra in-process gauges; injected provider via set_scaling_signal_provider() wins (CONCEPT:AU-OS.scaling.reactive-replica-autoscaling)

* Read via config.setting(...) at the call site (core/source_sync.py) rather than a typed AgentConfig field yet — still the sanctioned dynamic-read path (not a bare os.environ read), just not yet folded into AgentConfig.model_fields like KG_ACL_DEFAULT_ALLOW above.

These genuinely vary per host and aren't derivable. Action: ensure each is a typed AgentConfig field; remove duplicate bare reads (GRAPH_DB_URI is read in 4 places, AGENT_UTILITIES_CONFIG_DIR in 5).

A.1 Engine resolution — ONE resolver, every entrypoint (CONCEPT:AU-OS.deployment.engine-resolver-auto-provision)

Every entrypoint (graph-os MCP, the gateway/host daemon, IntelligenceGraphEngine, the facade, EpistemicGraphBackend, the tenant engine pool, messaging, agent/serving) funnels through the single chokepoint GraphComputeEngine.__init__, which calls engine_resolver.resolve_engine(config). The resolver decides — by ONE precedence, with NO per-entrypoint code — how the process reaches the ONE engine authority:

remote  →  share-running-local  →  autostart-shared-supervised
  • remote — any configured GRAPH_SERVICE_ENDPOINTS (single contact or a multi-shard topology): connect to it, never autostart a local stand-in (fail-loud if unreachable). This is the "I deployed the engine in Docker on another host" case (also the horizontal-scale-out shape). A remote/cluster engine is inherently persistent.
  • shared — the local endpoint is already serving (a cheap connect probe succeeds): reuse it, spawn nothing. Co-located entrypoints on one host share the ONE engine. This is also how the unified self-contained deployment behaves once its first process has started the engine — every later graph-os on the same host shares it instead of spawning a second one.
  • autostart — nothing reachable on a local endpoint: spawn ONE detached, supervised engine under the per-socket spawn guard (first-one-wins flock, so concurrent resolves never start a second engine on the same --persist-dir). Detached = it survives the spawner so OTHER entrypoints share it. Autostart is not an independent toggle — it is purely derived from topology (engine_resolver.setting_autostart): unset GRAPH_SERVICE_ENDPOINTS keeps it ON (the unified/self-contained default, for either MCP transport — see docs/recipes/unified-self-contained.md); configuring GRAPH_SERVICE_ENDPOINTS switches to connect-only instead. (Three earlier, separately-configured keys for this same decision were retired outright — a config.json or environment that still carries any of them hard-fails boot; see core/config.py _RETIRED_CONFIGURATION_KEYS.)

Two autostart lifecycles (the ENGINE_LIFECYCLE choice):

  • refcounted (default) — shared tiny engine, auto-stops after idle. The resolver passes --idle-shutdown-secs <ENGINE_IDLE_SHUTDOWN_SECS> (default 60); the engine self-stop that multiple seconds after its LAST client disconnects (reference-counted, robust to client crashes). Best for a laptop/Pi where the engine shouldn't linger once nothing is using it.
  • persistent — long-living local engine, never auto-stops. Set engine_lifecycle=persistent (or engine_idle_shutdown_secs=0) and the resolver passes NO idle-shutdown flag: the engine runs forever like a local service, even when idle. Best when the operator want a warm engine always ready (no cold-start on the next request).

These are typed AgentConfig fields (graph_service_endpoints, engine_lifecycle, engine_idle_shutdown_secs) — set them in config.json, no env-sprawl. If the installed engine binary doesn't advertise --idle-shutdown-secs yet (an older/leaner wheel), the flag is omitted gracefully (the engine then runs persistently); agent-utilities-doctor --preflight flags such a lean binary.

B. Daemon on/off toggles, all default ON — REMOVED (Phase 3) ✓

Done. The six always-on toggles below were removed and collapsed behind a single KG_DEV_MODE switch on AgentConfig, read through one engine_tasks._kg_dev_mode() helper that gates the maintenance scheduler + embedding-backfill startup. Production keeps every daemon on; KG_DEV_MODE=1 silences the lot. Removed: KG_EMBED_BACKFILL, KG_ENRICH_DAEMON, KG_FILE_WATCH, KG_HYGIENE_DAEMON, KG_TASK_REAPER_DAEMON, KG_RECONCILE_DURABLE. Also fixed the KG_EMBED_BACKFILL_BATCH dual-default bug → two named constants (_EMBED_BACKFILL_BUDGET=256, _EMBED_BACKFILL_FETCH=512). Sprawl baseline 95 → 88. (The KG_CONCEPT_CODE_LINK toggle lives in another module and is still pending.)

Original inventory (for reference):

Flag Default Gated thread/job (engine_tasks.py)
KG_EMBED_BACKFILL 1 vector-embedding backfill drain (L402)
KG_ENRICH_DAEMON 1 semantic enrichment tick (L618)
KG_FILE_WATCH 1 SDD/skills/config file-watch (L635)
KG_HYGIENE_DAEMON 1 memory decay/dedup (L645)
KG_TASK_REAPER_DAEMON 1 zombie-task recovery (L657)
KG_RECONCILE_DURABLE 1 engine→mirror autoheal (L609)
KG_CONCEPT_CODE_LINK 1 concept↔code bridge
GRAPH_DIRECT_DISPATCH true sync dispatch
KG_RETRIEVAL_QUALITY_GATE true relevance filter

Nobody runs these off in production. Action: remove the env gates; if a dev escape hatch is wanted, a single KG_DEV_MODE=1 disables all background daemons.

B.1 Safety overrides — KEEP (typed on AgentConfig)

There is no full-scan opt-in flag anymore. The client-side Cypher mini-DSL it used to gate (EpistemicGraphBackend._legacy_execute) is retired outright (CONCEPT:AU-P0-2): every query now goes straight to the native engine's own Cypher parser (GraphComputeEngine.query_cypher). An unparsed/unscoped predicate now raises (CypherEngineError) instead of falling through to any scan; a caller that genuinely wants every node still gets it, but only by writing that scan explicitly (MATCH (n) RETURN n), never by omission or by an environment flag. See tests/unit/test_legacy_execute_no_full_scan.py.

Flag Default What it gates
KG_EPISTEMIC_LIGHT_DEFAULT true Attach the light epistemic envelope (confidence/source_refs/evidence_refs/policy_labels/provenance) onto every plain read-path row by default (CONCEPT:AU-KB-CURRENCY) — additive, never changes a caller's list[dict] shape. Opt-out for a deployment that must skip the extra batched explain_provenance_by_ids round trip on every read; a row already showing a contested/low-confidence signal is still resolved in either case (auto-on override). Typed config.epistemic_light_default, read in knowledge_graph/core/epistemic_row.py.

C. Ingest-throughput knobs — REMOVED ✓

Done. All three removed: - KG_INGEST_FEATURES / KG_INGEST_PROFILE → per-repo call-graph community detection is now always on. The hang risk that motivated the opt-out is fixed at the source: the engine's community_detection is deterministically bounded (15s wall-clock + iteration cap, epistemic-graph algorithms.rs), and make_community_fn loads its scratch tenant in one batch_update round-trip instead of per-element RPCs. Correction (checked against code): one KG_INGEST_PROFILE read survives — pipeline phase selection in knowledge_graph/pipeline/__init__.py (select_phases; values structural | full, unset = full). It no longer gates community detection. It is tracked in the bare-read baseline (see section H). - KG_BULK_INGEST → the maintenance scheduler auto-detects a bulk ingest from the durable submission-queue depth (_submission_queue.get_queue_size() > _BULK_QUEUE_THRESHOLD) and defers its whole-graph passes per-tick, instead of a manual startup flag.

D. Performance tunables — keep as constants / deployment config (auto-sizing deferred)

The one real defect here — the KG_EMBED_BACKFILL_BATCH dual-default — is fixed (Phase 3: two named constants). The rest are left as-is by design: the worker pool already auto-sizes (engine_tasks.py CPU 36% + mem cap), and the remaining batch sizes / intervals have correct universal defaults. Per the Configuration discipline rule, a tunable with a good default should be a constant, not a knob — but mechanically converting every one to a CPU-derived auto-sizer is speculative churn with behaviour-change risk and little payoff, so it is not pursued. GRAPH_TIMEOUT's 20-minute default is noted (it made the old community-detection hang look infinite); now moot since the engine bounds the call itself.

Flag Default Notes
KG_LLM_CONCURRENCY 4 typed on AgentConfig (kg_llm_concurrency); the total parallel capacity of the local inference endpoint — the one knob for local-model parallelism. ORCH-1.59 always reserves 1 slot for the interactive path (messaging responder + graph-os-spawned agents, which share the default model); background KG work (enrichment/analysis/embeddings) is bounded to background_llm_concurrency() = capacity − 1. Subsumes the former KG_ENRICH_CONCURRENCY.
KG_PARSE_BATCH 128 constant
KG_ENRICH_BATCH / KG_ENRICH_MAX_BATCHES 16 / 8 constants
KG_EMBED_BACKFILL_BATCH 256 and 512 (BUG) read twice with different defaults (L1040, L1155) — unify
KG_BACKGROUND_MAX_CONCURRENT 2 auto
GRAPH_POOL_MIN/MAX 2 / 10 auto from cpu
KG_CHAT_CONCURRENCY 8 auto
KG_*_INTERVAL (enrich/file_watch/embed/evolution/golden) 20–3600 constants unless deployment-varying
GRAPH_TIMEOUT 1200000 ms 20-min RPC timeout — far too long; the root of "hangs look infinite"

E. Experiment / feature gates

KG_GOLDEN_* (10 flags) — collapsed onto AgentConfig ✓. Every KG_GOLDEN_* / KG_BREADTH_* read was moved off bare os.environ onto typed AgentConfig fields — opt-in, all off by default, single typed source of truth.

Flag Default What it gates
KG_LOOP False enable the autonomous golden-loop daemon cycle (intake→acquire→resolve→distil→synthesize)
KG_LOOP_DISTILL False distillation step of the golden loop
KG_LOOP_BREADTH False breadth ingest step (auto-ingest of the roots below)
KG_LOOP_STANDARDIZE False standardization pass of the golden loop
KG_GOLDEN_AUTO_MERGE False governed auto-merge of promoted proposals
KG_GOLDEN_MERGE_THRESHOLD None score threshold gating auto-merge
KG_LOOP_INTERVAL 3600 daemon tick interval (s)
KG_LOOP_TOPICS 5 hot topics processed per cycle
KG_BREADTH_LIBRARY_ROOTS "" comma-separated OSS library roots auto-ingested by the breadth step (deployment-specific; empty = no-op)
KG_BREADTH_REPO_ROOTS "" comma-separated code-repo roots auto-ingested by the breadth step
AGENT_THINKING_EFFORT "" pydantic-ai v2 native extended thinking on every built agent: low/medium/high (empty = off). Opt-in because reasoning is expensive (more tokens/latency); runs natively where the provider supports it and no-ops elsewhere. Read via setting() in agent/factory.py; per-agent override = the create_agent(thinking_effort=...) arg.
Family Count Notes
KG_EA_WRITEBACK, KG_ENABLE_HARD_NEGATIVE_MINING, KG_BRAIN_ENFORCE, KG_RESEARCH_EXTERNAL, KG_PROCESS_WRITEBACK 5 remaining experiment gates — graduate (always-on) or remove

KG_PROCESS_WRITEBACK — outbound process-intelligence writeback (CONCEPT:EG-KG.storage.nonblocking-checkpoint, default off). Opt-in because it performs outbound mutating calls into external systems (Camunda process-instance variables, ARIS model attributes) — exactly the "expensive / side-effecting on every run" case the opt-in tier is reserved for. When set, resolve_process_writeback pushes the KG's per-process intelligence (capability/ code lineage, OWL inferences, operational signals, glossary/data lineage) back onto the live process world via the graph_analyze action=process_writeback surface. The connector connection/credentials themselves are not agent-utilities config — they live in the camunda-mcp / aris-mcp packages' own environment (CAMUNDA7_*/CAMUNDA8_*, ARIS_*), read by each connector's auth.get_client().

EVOLUTION_WORKTREE_ROOT — evolution→branch bridge (CONCEPT:AU-AHE.harness.evolution-branch-bridge), typed on AgentConfig (evolution_worktree_root). Root directory the LocalBranchPublisher creates fresh git worktrees under when publishing a promoted proposal as a reviewable local branch. Empty (default) resolves to data_dir()/evolution_worktrees — publication never writes into a canonical checkout's working tree.

KG_FAILURE_* — Failure-Driven Evolution (CONCEPT:AU-AHE.harness.failure-evolution), typed on AgentConfig, opt-in, all off by default. The boolean gates are parsed via to_boolean ("True"/"False", consistent with the fleet's other toggles). See failure_driven_evolution.md.

Flag Default Notes
KG_FAILURE_EVOLUTION False enable the daemon failure_ingest tick (pull Langfuse failures → remediation)
KG_FAILURE_EVOLUTION_INTERVAL 3600 daemon tick interval (s)
KG_FAILURE_EVOLUTION_WINDOW 86400 telemetry look-back window (s)
KG_FAILURE_REGRESSION_DATASET False enable the dataset-based regression path
KG_DSPY_OPTIMIZATION False enable the daemon dspy_optimization tick — propose-only DSPy optimization sweep over the self-supervised targets (CONCEPT:AU-AHE.optimization.candidate-replaces-incumbent-only)
KG_DSPY_OPTIMIZATION_INTERVAL 3600 DSPy optimization sweep interval (s)

KG_FUSEKI_* — Ontology distribution to Apache Jena Fuseki (CONCEPT:AU-KG.ontology.authoritative-tbox), typed on AgentConfig, opt-in. The fuseki_publish maintenance tick pushes the bundled ontology modules (the authoritative TBox) to an optional enterprise Fuseki triplestore for SPARQL federation. Off by default — Fuseki is optional infrastructure.

Flag Default Notes
KG_FUSEKI_PUBLISH False enable the daemon fuseki_publish tick
KG_FUSEKI_ENDPOINT None Fuseki URL; None defers to the publisher (FUSEKI_ENDPOINT, then localhost)
KG_FUSEKI_PUBLISH_INTERVAL 3600 daemon tick interval (s)

KG_WORKFLOW_SHAPE_GATE — execution-time workflow ontology gate (CONCEPT:AU-ORCH.execution.ontology-validation-execution-path), typed on AgentConfig, default ON. execute_workflow AND its background twin dispatch_workflow (REST twin /api/graph/orchestrate/dispatch-workflow) SHACL-validate the stored WorkflowDefinition (+ steps) against the governance shapes before dispatch and refuse malformed definitions with a structured violation report; cheap and LLM-free. The companion permission gate (ontology permissioning ACL on the workflow node) is governed by the existing KG_BRAIN_ENFORCE flag (OS-5.14 fail-closed semantics), not a new one.

Flag Default Notes
KG_WORKFLOW_SHAPE_GATE True SHACL-validate stored workflows before execution

KG_GRAPH_OWNERSHIP_ENFORCED — the W2.8/HG-4 graph-ownership architecture invariant (CONCEPT:AU-KG.audit.graph-ownership-disposition), read live via setting(), default OFF. A one-time migration cutover switch, not a per-deployment tunable: it exists solely to gate the epistemic-graph master program's HG-4 human decision (see agent_utilities/knowledge_graph/maintenance/graph_ownership.py::check_invariant/ invariant_enforced) — "every catalog graph has >=1 covering RBAC grant or an explicit public flag." False (report-only) until a human applies the tooling's computed UNAMBIGUOUS grants and resolves every AMBIGUOUS graph by hand (scripts/graph_ownership_report.py + scripts/apply_graph_ownership_grants.py); flip to True exactly once, after HG-4, to make the invariant hard-fail on any future uncovered graph.

Flag Default Notes
KG_GRAPH_OWNERSHIP_ENFORCED False hard-fail (vs report-only) the graph-ownership coverage invariant — flip only after HG-4

Langfuse (CONCEPT:AU-AHE.harness.failure-evolution / AHE-3.0) — official SDK variable names only. The host variable is LANGFUSE_HOST (the non-standard LANGFUSE_BASE_URL fallback was removed — greenfield). Resolved through AgentConfig.langfuse_host / langfuse_public_key / langfuse_secret_key.

Flag Default Notes
LANGFUSE_HOST https://cloud.langfuse.com Langfuse base URL (read + OTEL write paths)
LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY None project API keypair

F. Testing — KEEP

Flag Default Notes
AGENT_UTILITIES_TESTING False test-mode guard (read in ~8 places — centralize)
AGENT_UTILITIES_GWT_STRICT "" global-workspace strict test mode
AGENT_UTILITIES_SKIP_LIVE_MOUNT_CHECK False skip the D-EGK-1 hostPath live-mount drift assertion (core/live_mount_guard.py) — escape hatch for an environment that intentionally runs this package from a plain pip install inside a pod
KUBERNETES_SERVICE_HOST "" not user-set — Kubernetes injects it into every pod unconditionally; core/live_mount_guard.py reads its presence as the "running inside a pod" signal that gates the D-EGK-1 check

G. Complete AgentConfig inventory — platform fields beyond the KG/graph flag audit

Sections A–F are the original KG_*/GRAPH_* sprawl audit. AgentConfig (core/config.py, pydantic-settings) also carries the platform's general configuration surface. Totals, extracted programmatically from AgentConfig.model_fields: 244 fields, 242 distinct environment variables (SECRETS_VAULT_URL and SECRETS_VAULT_MOUNT bind the single fields vault_url and vault_mount respectively — the earlier duplicate field names were removed).

Environment-name resolution: every field declares an explicit alias which IS its environment variable name (no env_prefix; matching is case-insensitive). Sources in precedence order: constructor args → environment → .env → nested secrets file (AGENT_SECRETS_FILE) → Docker secrets (/run/secrets). All fields below are therefore environment-settable; none are internal-only.

G.1 Model providers & routing

Flag Default What it sets
CHAT_MODELS [] JSON list of chat-model configs (id/provider/base_url/api_key/intelligence_level); drives default_chat_model / lite_chat_model / super_chat_model
EMBEDDING_MODELS [] JSON list of embedding-model configs (first entry = default)
OPENAI_API_KEY / OPENAI_BASE_URL None OpenAI fallback credentials for ad-hoc model creation
ANTHROPIC_API_KEY None Anthropic fallback API key
GEMINI_API_KEY None Google Gemini fallback API key
GROQ_API_KEY None Groq fallback API key
MISTRAL_API_KEY None Mistral fallback API key
HUGGING_FACE_API_KEY None Hugging Face fallback API key
DEEPSEEK_API_KEY / DEEPSEEK_BASE_URL None DeepSeek fallback credentials
VLLM_BASE_URL None Dedicated vLLM inference server base URL
MODEL_REGISTRY_PATH None YAML/JSON model-registry file
MODEL_ROLE_ROUTING {} Role→{tier,tags} overrides for planner/generator/learner/judge selection (CONCEPT:AU-ORCH.routing.conductor-per-step-model); empty roles use models/model_registry.py defaults
ROUTING_STRATEGY hybrid Graph routing strategy
ROUTING_PERCENTILE 50.0 Routing percentile tunable

G.2 LLM request defaults

Flag Default What it sets
MAX_TOKENS 16384 Default completion token cap
TEMPERATURE 0.7 Sampling temperature
TOP_P 1.0 Nucleus sampling
TIMEOUT 32400 LLM request timeout (s)
TOOL_TIMEOUT 32400 Tool-call timeout (s)
PARALLEL_TOOL_CALLS true Allow parallel tool calls
SEED None Deterministic sampling seed
PRESENCE_PENALTY / FREQUENCY_PENALTY 0.0 Repetition penalties
LOGIT_BIAS None Token logit-bias map (JSON)
STOP_SEQUENCES None Stop sequences (JSON list)
EXTRA_HEADERS / EXTRA_BODY None Extra provider request headers/body (JSON)

G.3 Agent identity & HTTP server

Flag Default What it sets
DEFAULT_AGENT_NAME package name Agent show name
AGENT_DESCRIPTION package description Agent description
AGENT_SYSTEM_PROMPT None System prompt override
WORKSPACE_PATH None Workspace root override
HOST 0.0.0.0 Gateway bind address
PORT 9000 Gateway port
DEBUG false Debug mode
AIRGAP_MODE false Sovereign/air-gap gate — refuse outbound HTTP to non-local hosts (core/http_client.py, core/model_factory.py); see docs/guides/sovereign-self-hosted.md §4
ENABLE_WEB_UI false Serve the web UI
ENABLE_TERMINAL_UI false Terminal UI mode (disables GATEWAY_WORKERS>1)
ENABLE_WEB_LOGS true Web log streaming
ENABLE_ACP false Deprecated gateway compatibility flag; ACP is started separately
ACP_SESSION_ROOT .acp-sessions Private durable store used by agent-utilities-acp
MCP_URL None Remote MCP server URL the agent attaches to
MCP_CONFIG None Path to mcp_config.json
MAX_UPLOAD_SIZE 10485760 Upload cap (bytes)
ALLOWED_ORIGINS None (= *) CORS origins, comma-separated
ALLOWED_HOSTS None TrustedHostMiddleware hosts, comma-separated

G.4 Identity, JWT & delegation

There is no static-API-key gateway auth path anymore (nor a bool toggle to require one) — REST/MCP auth is JWT-only, via AUTH_JWT_JWKS_URI (section A) and its companions below, plus KG_AUTH_REQUIRED/KG_AUTH_TOKEN for KG access (section A).

AUTH_JWT_JWKS_URI is in section A's orbit (OS-5.14); its companions:

Flag Default What it sets
AUTH_JWT_ISSUER None Expected JWT issuer claim
AUTH_JWT_AUDIENCE None Expected JWT audience claim
OIDC_CONFIG_URL None OIDC discovery URL (any compliant IdP)
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET None OAuth 2.0 client credentials
REMOTE_OAUTH_PROVIDERS_JSON None Administrator-approved JSON array of remote-MCP OAuth provider descriptors; malformed values disable the registry with a bounded diagnostic
REMOTE_OAUTH_SUCCESS_REDIRECT_URL None Fixed administrator-configured URL used after a successful remote OAuth callback
ENABLE_DELEGATION false RFC 8693 token exchange for downstream APIs (CONCEPT:AU-ECO.messaging.native-backend-abstraction)
AUDIENCE None Target audience for delegated tokens
DELEGATED_SCOPES api Space-separated delegation scopes
FLEET_EVENTS_TOKEN None Shared secret for POST /api/fleet/events webhook ingress (X-Fleet-Events-Token header); unset = no token required (CONCEPT:AU-OS.config.fleet-event-ingress)

G.5 Secrets backends

Flag Default What it sets
SECRETS_BACKEND engine engine (encrypted engine storage) | vault. The earlier inmemory/sqlite backends are gone
SECRETS_VAULT_URL None HashiCorp Vault / OpenBao URL (binds vault_url)
SECRETS_VAULT_MOUNT secret KV v2 mount (binds vault_mount)
VAULT_AUTH_METHOD auto oidc | approle | token | kubernetes | auto
VAULT_AUTH_MOUNT jwt Auth-method mount path
VAULT_ROLE None Role for OIDC/JWT or Kubernetes login
VAULT_PATH_PREFIX None KV path prefix (e.g. agents/mcp/)

G.6 Graph service & KG runtime (fields not already in A–F)

Flag Default What it sets
GRAPH_PERSISTENCE_TYPE file Engine durable-persistence mode
GRAPH_COMPUTE_BACKEND rust Compute tier selection
GRAPH_SERVICE_PERSIST_ON_SHUTDOWN true Serialize all graphs on engine shutdown. Checkpointing itself is otherwise continuous and non-blocking (CONCEPT:EG-KG.storage.nonblocking-checkpoint) — there is no periodic-interval knob; the discrete engine-socket/TCP-address fields and the old checkpoint-interval flag were retired along with GRAPH_SERVICE_ENDPOINTS's unification of engine addressing (see section A)
GRAPH_ROUTER_TIMEOUT / GRAPH_VERIFIER_TIMEOUT 300 Router/verifier timeouts (s)
ENABLE_LLM_VALIDATION false LLM validation pass
ENABLE_KG_EMBEDDINGS true KG embedding generation
KG_EMBEDDING_DIM 768 Must match the embedding model's output dimension; the schema vector column size derives from it
KG_BACKUPS 3 KG backup retention count
KG_INGESTION_WORKERS None (auto) Ingestion worker count override; unset auto-sizes
KG_ADAPTIVE_CONCURRENCY true Auto-scale per-model LLM/embedding fan-out to real vLLM serving capacity (CONCEPT:AU-KG.compute.surfaces-universal-latency-signal). Off → static model_capacity only. See architecture/adaptive_model_concurrency.md
MODEL_MAX_CONCURRENCY 512 Ceiling the adaptive per-model concurrency target can ramp to (no hardcoded small cap; static model_capacity is the floor)
GPU_CONCURRENCY_BUDGETS {} (unset → no cap) JSON group -> int: total concurrent in-flight calls across all models sharing one physical GPU (CONCEPT:AU-KG.compute.pure-config-enumeration-fail). Caps the SUM of member adaptive targets so they can't jointly oversubscribe the device, reserving latency-sensitive roles' floors first. Unset → per-model behaviour (no regression). See architecture/distributed_gpu_concurrency.md
GPU_RESERVED_ROLES chat,generator,default,lite,super Roles whose static floor is reserved off the top of a GPU budget (CONCEPT:AU-KG.compute.pure-config-enumeration-fail); best-effort roles (embedding/batch) get the remainder and yield to these under contention
KG_ANALYSIS_MAX_DEPTH 2 Max recursion depth for background research daemons
MAX_RECURSION_DEPTH 2 Graph recursion depth tunable
KNOWLEDGE_GRAPH_SYNC_BACKGROUND true Background task workers for the KG pipeline
ENABLE_SDD_WATCHER true Plan/task watcher thread in the KG MCP server
KG_ANOMALY_CONSUMER true Drain unconsumed PerformanceAnomaly nodes into failure_gap topics; LLM-free, bounded, propose-only (CONCEPT:AU-AHE.optimization.performance-anomaly-consumer)
SPARQL_ENDPOINTS ["https://query.wikidata.org/sparql"] External SPARQL endpoints to federate (CONCEPT:AU-KG.query.vendor-agnostic-traversal)
JENA_FUSEKI_URL None Local Jena Fuseki URL (distinct from the KG_FUSEKI_* publish tick in section E)
KAFKA_BOOTSTRAP_SERVERS None Kafka brokers (task-queue/event transport; one of the three scale knobs in docs/scaling/capacity_model.md)
KAFKA_TOPIC None Default Kafka topic for messaging/event ingestion
NATS_URL None NATS broker URL

G.7 Observability exporters

The gateway Prometheus flags (GATEWAY_METRICS etc.) are in section A; the metric series themselves are catalogued in ../reference/metrics.md.

Flag Default What it sets
ENABLE_OTEL false OpenTelemetry tracing (the Logfire/Langfuse pipeline, custom_observability.setup_otel)
OTEL_EXPORTER_OTLP_ENDPOINT None OTLP collector endpoint — also the standard-env-var trigger for TelemetryEngine's standalone OTLP pipeline (X2; [otel] extra), independent of ENABLE_OTEL
OTEL_SERVICE_NAME package name OTel resource service.name (both OTel pipelines)
OTEL_TRACES_EXPORTER otlp Standard OTel var; TelemetryEngine treats any value that isn't (or doesn't include) otlp — e.g. none — as a hard kill-switch, even when an endpoint resolves
OTEL_EXPORTER_OTLP_HEADERS None OTLP headers
OTEL_EXPORTER_OTLP_PUBLIC_KEY / OTEL_EXPORTER_OTLP_SECRET_KEY None OTLP keypair (Langfuse-style basic auth)
OTEL_EXPORTER_OTLP_PROTOCOL http/protobuf OTLP protocol
LANGFUSE_DATASET_CAPTURE_THRESHOLD 0.0 Score threshold for dataset capture (AU-AHE.harness.failure-evolution regression datasets)
LANGFUSE_LATENCY_BASELINE_SECONDS 60 Latency baseline for anomaly scoring
LANGFUSE_TOKEN_BASELINE 20000 Token-usage baseline for anomaly scoring
LANGFUSE_VERIFIER_FALLBACK_LIMIT 1 Verifier fallback attempts

Content boundary (CONCEPT:AU-OS.observability.literal-service-topology-labels). custom_observability._MetadataOnlySpanExporter strips every exported span down to metadata before it leaves the process, but it draws an explicit line between two kinds of value: service topology (service.name, the span/operation name — always built from fixed strings and enum-like identifiers such as graph-os or engine.GetNodeProperties, never from a request body/tool argument/model output) is sanitized (control characters stripped, length capped) but exported literal, so an operator can pick a service in Grafana/Tempo and the service graph renders correctly. Anything that can carry user content — span attributes, resource detector fields — still goes through _opaque_label/_metadata_only_attributes and is exported as an opaque, namespaced pref_* reference. See _service_topology_label vs _opaque_label in agent_utilities/observability/custom_observability.py.

G.8 A2A (agent-to-agent)

Flag Default What it sets
A2A_BROKER epistemic_graph A2A message broker backend — fixed to the epistemic-graph engine (queue-native; the earlier separate in-memory/URL-configured broker is gone)
A2A_STORAGE epistemic_graph A2A task/history storage backend — likewise fixed to the epistemic-graph engine
A2A_CONFIG None a2a_config.json path for external agent discovery (CONCEPT:AU-ECO.messaging.native-backend-abstraction)
A2A_REFRESH_INTERVAL 300 Agent-card re-fetch interval (s)

G.9 Orchestration, scheduler & guardrails

Flag Default What it sets
MIN_CONFIDENCE 0.4 Minimum confidence gate
VALIDATION_MODE false Validation-only execution mode
APPROVAL_TIMEOUT 0 Approval wait timeout (s; 0 = no wait)
COGNITIVE_SCHEDULER_ENABLED true Priority-aware agent scheduler (CONCEPT:AU-OS.state.cognitive-scheduler-preemption)
MAX_CONCURRENT_AGENTS 5 Concurrent specialist agents (CONCEPT:AU-OS.state.cognitive-scheduler-preemption)
AGENT_TOKEN_QUOTA 100000 Per-agent token budget before preemption (CONCEPT:AU-OS.state.cognitive-scheduler-preemption)
PREEMPTION_THRESHOLD_PCT 0.85 Quota usage triggering preemption warning
AGENT_POLICIES_PATH None agent_policies.json for identity-based governance
PERMISSIONS_SIGNING_KEY_REF None (auto) Vault/OpenBao reference for the HMAC key signing agent identity tokens; auto-generated if unset. The earlier raw-key PERMISSIONS_SIGNING_KEY input is retired (hard-fails boot — core/config.py _RETIRED_CONFIGURATION_KEYS); only a secrets-backend reference is accepted now
SPECIALIST_REGISTRY_PATH None Local specialist registry dir
MAX_PARALLEL_AGENTS 60 Global engine-wide execution semaphore (CONCEPT:AU-ORCH.execution.parallel-engine-visualizer)
WORKER_POOL_SIZE 8 Workers per node for agent turns / graph mutations; active-concurrency scale knob (CONCEPT:AU-ORCH.execution.parallel-engine-visualizer)
PARALLEL_BATCH_SIZE 25 Agents per execution wave
SYNTHESIS_STRATEGY auto auto | flat | hierarchical | progressive | rlm (CONCEPT:AU-ORCH.execution.rlm-synthesis-failed-falling)
SYNTHESIS_RATIO 10 Outputs per hierarchical synthesis sub-node
AGENT_EXECUTION_TIMEOUT 120 Per-agent timeout (s)
CIRCUIT_BREAKER_THRESHOLD 3 Consecutive failures disabling an agent type
ENABLE_PROGRESSIVE_SYNTHESIS true Streaming synthesis as agents complete
HOMEOSTATIC_DOWNGRADE_ENABLED true Auto model-tier downgrade under budget pressure (CONCEPT:AU-OS.state.cognitive-scheduler-preemption)
ADVERSARIAL_VERIFICATION false Adversarial verification pass — opt-in, doubles verification cost (CONCEPT:AU-AHE.evaluation.adaptive-reasoning-effort)
MAINTENANCE_TOKEN_BUDGET 0 (unlimited) Token budget for the autonomous maintenance cron
MAINTENANCE_PRIORITY LOW Maintenance task priority (LOW/MEDIUM/HIGH)
WATCHDOG_PATTERNS pyproject.toml, mcp_config.json, requirements*.txt File patterns for the file-watcher trigger (CONCEPT:AU-OS.safety.doom-loop-detection)
TOOL_GUARD_MODE strict Sensitive-tool guard mode
SENSITIVE_TOOL_PATTERNS 67 regexes Tool-name patterns treated as mutating/sensitive (remove/exec/deploy/...); override only to extend

G.10 Skills

Flag Default What it sets
CUSTOM_SKILLS_DIRECTORY None Extra skills directory
SKILL_TYPES None Skill-type filter (JSON list)

G.11 Native messaging backends (CONCEPT:AU-ECO.messaging.native-backend-abstraction)

Flag Default What it sets
MESSAGING_ENABLED_BACKENDS [] Backend IDs to auto-connect (e.g. ["discord","slack"])
MESSAGING_INTAKE_ENABLED false Explicit deployment intent for embedded inbound polling; only canonical true/false (or typed booleans) is accepted. Token presence alone never enables intake; set true only on the designated graph-os request container.
MESSAGING_KG_INGEST true Auto-ingest all inbound/outbound messages into the KG
MESSAGING_KG_MEMORY_TYPE episodic KG memory tier for inbound messages (episodic/semantic/procedural)
MESSAGING_ROUTE_TO_PLANNER true Route inbound events to the Planner Graph Agent
MESSAGING_DISCORD_TOKEN None Discord bot token (also reads DISCORD_BOT_TOKEN)
MESSAGING_SLACK_TOKEN None Slack bot token xoxb-... (also reads SLACK_BOT_TOKEN)
MESSAGING_SLACK_APP_TOKEN None Slack app-level token xapp-... (Socket Mode)
MESSAGING_TELEGRAM_TOKEN None Telegram bot token (also reads TELEGRAM_BOT_TOKEN)
MESSAGING_WHATSAPP_TOKEN None WhatsApp API token (also reads WHATSAPP_TOKEN)
MESSAGING_WHATSAPP_PHONE_NUMBER_ID None WhatsApp Business phone number ID
MESSAGING_WHATSAPP_USE_BUSINESS_API false Official Business API vs neonize bridge
MESSAGING_TEAMS_APP_ID / MESSAGING_TEAMS_APP_SECRET None Microsoft Teams Bot Framework credentials
MESSAGING_GOOGLECHAT_TOKEN None Google Chat service-account JSON path
MESSAGING_GOOGLEMEET_TOKEN None Google Meet service-account JSON path
MESSAGING_MATTERMOST_TOKEN / MESSAGING_MATTERMOST_URL None Mattermost token + server URL
MESSAGING_MATRIX_TOKEN / MESSAGING_MATRIX_HOMESERVER / MESSAGING_MATRIX_USER_ID None Matrix credentials
MESSAGING_IRC_SERVER None IRC server
MESSAGING_IRC_PORT 6667 IRC port
MESSAGING_IRC_NICKNAME agent_bot IRC nickname
MESSAGING_IRC_CHANNELS [] IRC channels to auto-join
MESSAGING_SIGNAL_TOKEN None Signal phone number (semaphore-bot)
MESSAGING_LINE_TOKEN None LINE channel access token
MESSAGING_TWITCH_TOKEN None Twitch OAuth token
MESSAGING_TWITCH_CHANNELS [] Twitch channels to join
MESSAGING_SYNOLOGY_WEBHOOK_URL None Synology Chat webhook URL
MESSAGING_VOICECALL_APP_ID / MESSAGING_VOICECALL_TOKEN / MESSAGING_VOICECALL_FROM_NUMBER None Twilio voice/SMS credentials (account SID / auth token / from number)
MESSAGING_NEXTCLOUD_URL / MESSAGING_NEXTCLOUD_TOKEN / MESSAGING_NEXTCLOUD_APP_ID None Nextcloud Talk credentials (URL / app token / username)

H. Former bare KG_*/GRAPH_*/EPISTEMIC_* reads (now folded)

Every governed (KG_*/GRAPH_*/EPISTEMIC_*) bare os.environ read has been folded off os.environ onto a centralized path, per Configuration discipline:

  • Deployment-varying / behavioral / test-varied → config.setting("VAR", default) (live, config.json-driven). Still fully settable — set var in config.json or VAR in the environment.
  • Pure load tunables (concurrency/batch) → auto-sized via compute_ingest_worker_count().
  • Single-value cadences/limits/timeouts → named module constants (no knob).

scripts/check_no_env_sprawl.py now ratchets all-prefix bare reads against scripts/env_flag_baseline.txt (the governed reads are gone from it; what remains is the non-KG burn-down — AGENT_*, VAULT_*, OTEL_*, connector creds, …). The table below is the reference for these settings and how each is now resolved (defaults unchanged); for the setting() rows, the value is config.json-/env-overridable:

Flag Default Read in What it sets
KG_DAEMON_LOG_LEVEL INFO gateway/daemon.py Daemon log level
KG_CARD_MODEL lite core/engine_tasks.py lite or heavy model for enrichment cards
KG_LLM_TIMEOUT / KG_LLM_MAX_RETRIES 30 / 1 enrichment/cards.py Enrichment LLM call timeout (s) / retries
KG_EMBED_BACKFILL_INTERVAL / KG_EMBED_BACKFILL_BUSY_SLEEP 30 / 1 core/engine_tasks.py Embedding-backfill idle/busy sleep (s)
KG_RECONCILE_INTERVAL 900 core/engine_tasks.py engine→mirror reconcile tick (s)
KG_HYGIENE_INTERVAL 86400 core/engine_tasks.py Memory decay/dedup tick (s)
KG_TASK_REAPER_INTERVAL 120 core/engine_tasks.py Zombie-task reaper tick (s)
KG_TASK_ORPHAN_GRACE_SEC 90 core/engine_tasks.py Grace before an orphaned task is reclaimed
KG_TASK_MAX_RUNTIME_SEC 7200 core/engine_tasks.py Max task runtime before requeue
KG_TASK_MAX_REQUEUE 3 core/engine_tasks.py Max requeues before a task is failed
KG_GRAPH_NAME __bus__ distillation/skill_graph_distiller.py Target graph for skill-graph distillation
KG_INGEST_INFLIGHT 40 ingestion/batch_orchestrator.py Max in-flight ingest submissions
KG_INGEST_PROFILE unset (= full) pipeline/__init__.py Pipeline phase profile (structural | full) — residual read, see the section C correction
KG_EVAL_CAPTURE off memory/optimization_engine.py Capture retrieval evals
KG_MIN_RELEVANCE_THRESHOLD unset (arg/schema-pack) retrieval/retrieval_quality.py Relevance-gate threshold override
KG_TRUST_HIERARCHY built-in defaults core/company_brain_runtime.py JSON trust-hierarchy entries (with KG_BRAIN_ENFORCE)
GRAPH_SCHEMA_PACK unset models/schema_pack_loader.py Schema-pack selection override
GRAPH_SCHEMA_AUDIT_DIR / GRAPH_SCHEMA_AUDIT_VERBOSE unset / off models/schema_pack_audit.py Schema-audit output dir / verbosity
KG_PROVIDER_ADAPTER_BACKEND static prompting/provider_adapter.py Prompting provider-adapter backend

Disposition: the model-choice / behavioral / profile / schema rows (KG_CARD_MODEL, KG_GRAPH_NAME, KG_INGEST_*, KG_EVAL_CAPTURE, KG_MIN_RELEVANCE_THRESHOLD, KG_TRUST_HIERARCHY, GRAPH_SCHEMA_*, KG_PROVIDER_ADAPTER_BACKEND, KG_DAEMON_LOG_LEVEL) are now config.setting(...) reads (config.json-/env- overridable). The cadence/limit/timeout rows (KG_*_INTERVAL, KG_TASK_*, KG_LLM_TIMEOUT/_MAX_RETRIES, KG_EMBED_BACKFILL_*) are now named module constants. MCP_CHILD_* flags were already fully typed on AgentConfig with no bare reads (mcp/child_resilience.py consumes the config object). The former separate KG-coordinator address pair and the engine-side routing-strategy duplicate of ROUTING_STRATEGY (section G.1) were retired along with the coordinator process itself (section A.1) rather than folded — there was nothing left to fold them into.

The agent toolset gates in tools/tool_registry.py are also bare reads (not KG-prefixed, so outside the ratchet). The optional-infra toolsets all default OFF and are opt-in:

Flag Default What it gates
X_TOOLS False X/Grok social search + post browsing via xAI (needs XAI_API_KEY); production X/Grok deployments must set X_TOOLS=1 explicitly
MEDIA_TOOLS False Media generation / transcription services (ECO-4.30/4.31)
DB_TOOLS False Native database traversal tools (AU-ECO.toolkit.database-traversal-tools)

(The always-available local toolsets — WORKSPACE_TOOLS, GIT_TOOLS, A2A_TOOLS, SCHEDULER_TOOLS, BROWSER_TOOLS, DEVELOPER_TOOLS — default ON in the same registry.)

Coverage statement

Checked against agent_utilities/core/config.py on this branch by extracting AgentConfig.model_fields programmatically: 244 fields / 242 distinct env variables, every one documented above — sections A–F cover the KG/graph audit surface, section G the remaining platform fields (no field was deemed internal-only: every AgentConfig field declares an env alias and is settable from the environment). Section H also documents the user-facing flags that exist only as baseline-frozen bare os.environ reads. Drift fixed in this pass: KG_LLM_CONCURRENCY default is 4 (doc previously said 6), and KG_INGEST_PROFILE retains one phase-selection read despite the section C removal note.

Known bugs surfaced by this audit

  1. KG_EMBED_BACKFILL_BATCH dual default — 256 (engine_tasks.py:1040) vs 512 (:1155). Same flag, two meanings (per-tick budget vs DB fetch batch). Split into two named constants or one config field.
  2. Scattered duplicate reads — GRAPH_DB_URI (4×), AGENT_UTILITIES_CONFIG_DIR (5×), KG_DAEMON_ROLE/KG_INGEST_PROFILE (2× each). No single source of truth.
  3. GRAPH_TIMEOUT=1200000 (20 min) makes a non-converging engine call look like an infinite hang for 20 minutes before erroring.

Target end-state

~96 flags → roughly the ~27 KEEP deployment items (all typed on AgentConfig), behavior otherwise auto-detected, and scripts/check_no_env_sprawl.py blocking regressions. A fresh graph-os-daemon with zero KG_* env vars set should ingest a full corpus correctly.