Configuration Reference
Every MERGEN_* environment variable the server reads, classified by who is qualified to decide its value. This reference is generated from the same registry the build enforces; an unregistered setting is a red build, so this page cannot silently fall out of date.
One invariant governs everything here: no setting below can make the gate approve something it would otherwise have blocked, except the explicitly guarded settings, which exist for narrow recovery/migration cases and are surfaced loudly wherever they are active.
Organization policy
Settings a security admin decides: approval rules, retention, quorum, module switches. These are what teams buy Mergen to customize. None of them can weaken a gate verdict.
MERGEN_AUTOPILOT
type: boolean · default: false · module: autopilot
Enable autonomous incident fix execution (Gate B). Off by default; shadow mode is forced on first enable unless explicitly disabled.
MERGEN_AUTOPILOT_LEVEL
type: string · default: unset · module: autopilot
Autopilot autonomy level cap.
MERGEN_SHADOW_MODE
type: boolean · default: unset · module: autopilot
Dry-run the AUTOPILOT (Gate B): diagnose but never execute fixes. Defaults to true when autopilot is first enabled.
MERGEN_BLOCK_BYPASS
type: boolean · default: true
Lets an operator, never the agent, self-issue a single-use terminal token to re-run a BLOCK from an editable rule. This is a recovery valve, not a HOLD-style approval request: nothing is sent to the agent, no one is asked to approve anything. false = every BLOCK is final (stricter). Immutable/hard-safety rules are never bypassable regardless.
MERGEN_BYPASS_TTL_MINUTES
type: int · default: 10
Minutes an operator-issued BLOCK bypass token stays valid before it expires (clamped 1-1440). The window does not extend on use; the re-run must land within it.
MERGEN_APPROVAL_REUSE_MINUTES
type: int · default: 10
Minutes a HITL hold approval is honored for exactly one re-run of that command (clamped 1-1440). Single-use regardless of the window length; see MERGEN_APPROVAL_REUSE_NORMALIZE for how "that command" is matched.
MERGEN_APPROVAL_REUSE_NORMALIZE
type: boolean · default: true
Within the reuse window, also honor an approval when only a leading cd <dir> && differs, and/or leading VAR=value env-var assignments that carry the SAME value on both sides (see commandsMatchForReuse in approval-history.ts): a value that changed, or a variable newly introduced on the retry, still requires a fresh approval. The executable and arguments underneath must always be byte-identical. false reverts to literal exact-string matching only.
MERGEN_APPROVAL_GRANTS
type: boolean · default: true
Allow a human, at HOLD-approval time, to also mint a task-scoped grant covering a narrow, deterministically-matched set of follow-up commands (same exact command / same binary subcommand / same binary, always same workspace) for a bounded window + use-count. Grant relief is HOLD→PASS only — consulted solely inside holdToolCall, so it can never touch a BLOCK or alter a PASS. false disables minting and matching entirely; the single-use MERGEN_APPROVAL_REUSE path is unaffected.
MERGEN_APPROVAL_GRANT_MAX_MINUTES
type: int · default: 15
Ceiling (and default) for a task-scoped approval grant's lifetime in minutes (clamped 1-120). A grant also ends when its use-count is exhausted or a human revokes it.
MERGEN_APPROVAL_GRANT_MAX_USES
type: int · default: 5
Ceiling (and default) for how many in-scope commands a single task-scoped approval grant will cover before it is spent (clamped 1-50). Bounds a runaway retry loop to the count rather than the whole time window.
MERGEN_SECRET_GRACE_PERIOD_MINUTES
type: int · default: 5
Minutes the previous ~/.mergen/secret value is still accepted for request authentication after mergen-server rotate-secret (clamped 0-1440), giving in-flight clients (an open dashboard tab, a mid-flight OAuth callback) time to pick up the new value before the old one stops working. 0 disables the grace period: rotation takes effect immediately. See sensor/secret-manager.ts.
MERGEN_CORPUS_HOLD
type: boolean · default: false · module: override-corpus
Opt-in per-command override-corpus lookup at Gate A: a command matching a prior override/incident escalates to HOLD with a cited reason. HOLD-only, never BLOCK/PASS.
MERGEN_AUTO_CORPUS_PROPOSE
type: boolean · default: true · module: policy-suggester
Every 6h, stage repeatedly-overridden corpus patterns as HOLD-only policy proposals for one-click approval. Never auto-activates, never proposes a BLOCK.
MERGEN_REQUIRE_BROKER_CREDENTIALS
type: enum · values: off · shadow · enforce · default: off · module: credential-broker
Opt-in ambient-credential-bypass detection: a bare, mutating aws/gcloud/az invocation with no matching credential-broker issuance (intelligence/credential-broker.ts) recorded for this session in the last hour escalates PASS→HOLD, never BLOCK: an agent with ambient cloud creds already on the machine (env vars, ~/.aws/credentials, an instance role) can otherwise call the provider CLI directly and skip the broker entirely. A curated read-only allowlist (aws ... s3 ls/describe-/get-caller-identity/list-, gcloud ... list, az ... show/list) is exempt so this doesn't hold routine inspection calls. off (default) skips the check entirely; this is a new interception surface with no field false-positive data yet. shadow computes and logs what WOULD have held (gate-analytics) without ever changing the verdict. enforce is full effect. Deliberately narrow: this does not, and is not intended to, cover every bare cloud-CLI call; see CLAUDE.md's 'bypass gap' section for why a blanket rule was rejected.
MERGEN_CHANGE_GATE_DETECTORS
type: boolean · default: true · module: change-gate
POST /ci/gate (Gate C, Change Authorization): deterministic diff-content detectors: secret introduction, test deletion, auth-bypass, CI-check removal, permission/config weakening. The highest-confidence detectors are BLOCK-eligible; see change-gate.ts for the per-detector severity table.
MERGEN_CHANGE_GATE_SCOPE
type: boolean · default: true · module: change-gate
POST /ci/gate (Gate C, Change Authorization): task-to-diff scope match: keyword/path heuristic comparing the supplied taskDescription/planSummary against changed files, not a semantic review. Capped at REQUIRE_REVIEW; can never itself produce BLOCK or PASS.
MERGEN_CHANGE_GATE_MODE
type: enum · values: off · shadow · enforce · default: enforce · module: change-gate
POST /ci/gate (Gate C): off skips Gate C entirely (corpus/size/blast-radius findings elsewhere in /ci/gate are unaffected). shadow runs every detector and the scope match, populates the API response and PR comment (with a shadow-mode banner and what verdict it WOULD have produced), but never changes the actual verdict, never fails the CI build, and never applies the review label, for measuring false-positive rate on real traffic before enabling enforcement. enforce (default) is full effect.
MERGEN_EDIT_GATE_MODE
type: enum · values: off · shadow · enforce · default: shadow · module: edit-gate
Claude Code, GitHub Copilot CLI, and Windsurf pre-write hooks plus Cursor/VS Code self-heal integrations (the Edit-Time Change Gate): reuses Gate C's deterministic diff-content detectors (secret introduction, auth-bypass, CI-check removal, test deletion, ...) at edit time. shadow (default) computes and logs every finding but never blocks or reverts the write. enforce blocks through pre-write hooks and reverts through post-write integrations on any block-severity finding. off skips detection entirely.
MERGEN_RISK_HOLD_THRESHOLD
type: float · default: unset
Opt-in risk-score escalation: a passing call with composite risk at/above this threshold escalates PASS→HOLD. Unset = off.
MERGEN_SHELL_GATE_MODE
type: enum · values: off · advise · enforce · default: advise
Mode baked into the snippet mergen shell-init <zsh|bash|fish> emits — routes every command typed at an interactive prompt through the same gate-check entrypoint and policy engine the IDE Bash PreToolUse hook uses (no separate shell command filter). advise (default) shows the BLOCK/HOLD banner but the command still runs. enforce (zsh only — an accept-line ZLE widget) keeps a held/denied line in the buffer, unexecuted; bash/fish stay advise regardless. off makes an installed hook inert. Read only by shell-init at snippet-generation time; never consulted by Gate A itself.
MERGEN_SCRIPT_TRUST_WINDOW_SECONDS
type: int · default: 30 · module: script-trust
Script-wrapping evasion guard: scripts modified within this window are auto-held. 0 disables only the freshness check (git-tracked + in-workspace checks stay).
MERGEN_OBSERVATION_WINDOW_DAYS
type: int · default: 14
Length of the first-install gate observation window (Gate A evaluates and logs every call but editable-rule blocks/holds pass through; immutable hard-safety rules still enforce from minute one). Integer days, clamped 1-90; an out-of-range or non-integer value refuses to start rather than silently reverting; below 3 boots with a warning (too little traffic to build trust). Enforcement date is always startedAt + this value, recomputed live, so changing it mid-window shifts the date deterministically instead of extending from "now". MERGEN_POLICY_DRY_RUN=false skips observation entirely regardless of this value; POST /onboarding/promote-enforcement ends it early.
MERGEN_GATE_RECOVERY_COMMANDS
type: csv · default: unset
Additive, exact-match-only extension of the built-in recovery allowlist gate-check exempts from the network round-trip. Entries with shell metacharacters are rejected.
MERGEN_GATE_AUTOSTART
type: boolean · default: true
gate-check auto-starts a missing workspace server (clean unreachable only, never a wedged one) and evaluates the command against the fresh gate. Disabling cannot weaken the gate; unavailability then fails closed per MERGEN_GATE_AVAILABILITY_MODE; a deliberate mergen-server stop pauses auto-start until an explicit start.
MERGEN_HOOK_SELF_HEAL
type: boolean · default: true
On each server boot, repoint an already-installed Claude Code PreToolUse hook whose baked-in CLI path has drifted (Node/nvm upgrade, package-manager switch, moved global prefix) back at this install. Only repairs a hook the user already opted into — never creates one — and never changes a gate verdict. Skipped in cloud mode. Set false to leave hook maintenance to mergen-server setup/doctor --fix only.
MERGEN_REQUIRE_GATE_HEARTBEAT
type: boolean · default: false
Require a fresh gate heartbeat for health to report ok (stricter when true).
MERGEN_TRUSTED_HUMANS
type: csv · default: unset
Principals treated as verified humans for policy conditions.
MERGEN_ACTOR_ROLES
type: string · default: unset
Actor→role mapping consumed by policy rule role conditions.
MERGEN_HITL_QUORUM_RULES
type: csv · default: unset · module: hitl
pattern:count pairs: a hold matching a pattern requires N distinct approvers before the Promise resolves.
MERGEN_LEDGER_RETENTION_DAYS
type: int · default: 90
Durable per-agent action ledger retention (every PASS/HOLD/BLOCK). Rows past the window are pruned hourly; 1M-row hard cap.
MERGEN_RETENTION_HOURS
type: int · default: unset
In-memory/ring-buffer event retention in hours. Distinct from MERGEN_LEDGER_RETENTION_DAYS (the durable gate-decision ledger).
MERGEN_REDACT_KEYS
type: csv · default: unset
Additional key names for the PII shield to redact (additive, stricter).
MERGEN_CAPTURE_TERMINAL_RETAIN
type: enum · values: none · metadata_only · redacted · full · default: redacted
What terminal-command text is written to the durable action ledger, AFTER the PASS/HOLD/BLOCK decision is already made, never a precondition for making one (see docs/internal/CAPTURE_POLICY_DESIGN.md). none/metadata_only retain no command text; redacted/full both pass the command through the PII/secret redaction pass unconditionally: "full" means full operational context subject to mandatory redaction, never byte-for-byte raw capture. No findings_only mode for this category: a bare command has no sub-findings to summarize (see change-gate detector findings for where findings_only applies instead). A tampered or unsigned signed-settings file falls back to 'none' (the strictest mode), not to this default; see capture-policy.ts. NOT RETROACTIVE: changing this value only affects future ledger writes; rows already written (including under the pre-2026-07-25 unconditional-raw default) keep whatever content they were written with. There is no migration or purge tool yet; see docs/internal/CAPTURE_POLICY_DESIGN.md's "Existing installations" section.
MERGEN_CAPTURE_FILECHANGES_RETAIN
type: enum · values: none · metadata_only · findings_only · default: findings_only
What Gate C (POST /ci/gate, Change Authorization) change-detector finding detail is attached to the CI-gate JSON response (changeGate.deterministicFindings/findingsSummary, and the lineHits.hits/policyGate matches from the same evidence category), AFTER the verdict is already computed, never a precondition for computing one (see docs/internal/CAPTURE_POLICY_DESIGN.md). none/metadata_only retain no per-finding evidence text (metadata_only keeps file paths, counts, and detector/severity categories only). findings_only (default) returns the full per-finding shape with evidence passed through the PII/secret redaction pass unconditionally. No redacted/full mode yet for this category: those need diff-hunk-extraction machinery this slice does not build. verdict/riskScore/reasons[] are unaffected by this SETTING at every mode (the free-text detector/reason/line stay raw always, verified fixed templates), but reasons[] entries DO have their file-path token redacted unconditionally, independent of this setting, same baseline-hygiene rule as changeGate.deterministicFindings[].file (a path can embed a secret). A tampered or unsigned signed-settings file falls back to 'none' (the strictest mode), not to this default (which is itself fairly permissive); see capture-policy.ts. NOT RETROACTIVE; see MERGEN_CAPTURE_TERMINAL_RETAIN's note above; the same caveat applies here.
MERGEN_CAPTURE_CLOUD_RETAIN
type: enum · values: local_only · metadata_only · match_local · default: local_only
Second gate applied on top of (never instead of, and never more permissive than) terminal.retain/fileChanges.retain, governing what may leave THIS MACHINE at all: Mergen's own SaaS (the live cloud-approval relay, audit-events sync, approvals sync), the self-hosted fleet-audit sync plane, and any customer-configured SIEM sink. effectiveOutboundMode = stricter(local mode, this ceiling), composed at the moment of each egress attempt, never cached from the local write. local_only (default) ceilings each category at its own most-restrictive local mode (none); metadata_only ceilings at each category's own metadata_only shape; match_local applies no additional ceiling beyond whatever the local retain mode already decided. Defaults to the strictest legal value here (unlike terminal/fileChanges's moderate defaults) because crossing the machine boundary is a materially larger trust boundary than local disk. A tampered or unsigned signed-settings file falls back to local_only (already the strictest legal value); see capture-policy.ts.
MERGEN_SSO_REQUIRED
type: boolean · default: false · module: identity
Require SSO bearer auth on all mutating requests (stricter when true).
MERGEN_SSO_ALLOWED_EMAILS
type: csv · default: unset · module: identity
Allow-list of SSO principals permitted to authenticate.
MERGEN_OIDC_GROUP_ROLE_MAP
type: string · default: unset · module: idp
IDP group→Mergen RBAC role mapping.
MERGEN_SANDBOX
type: enum · values: docker · seatbelt · default: unset · module: sandbox
Sandbox mergen-server exec: docker (container) or seatbelt (macOS). Opt-in; falls back to direct host execution with a loud warning if the backend is unavailable.
MERGEN_SANDBOX_NETWORK
type: enum · values: none · bridge · default: none · module: sandbox
Sandbox network access: none (default) or bridge.
MERGEN_SANDBOX_IMAGE
type: string · default: unset · module: sandbox
Docker backend image (must contain the wrapped command's toolchain).
MERGEN_SANDBOX_EXTRA_WRITE_PATHS
type: csv · default: unset · module: sandbox
Seatbelt backend: extra absolute paths the sandboxed command may write to.
MERGEN_SANDBOX_DOCKER_RUNTIME
type: string · default: unset · module: sandbox
Alternate OCI runtime (e.g. gVisor runsc) for the Docker backend; falls back to runc with a warning if unregistered.
MERGEN_EBPF_VERIFY
type: boolean · default: unset · module: sandbox
eBPF-based execution verification (Linux): cross-checks that what ran matches what was gated.
MERGEN_SLACK_OVERRIDE_LOOP
type: boolean · default: unset · module: override-corpus
Auto-scan the incident channel every 6h for postmortem threads to build override corpus entries.
MERGEN_REQUIRE_GITHUB_WEBHOOK_SECRET
type: boolean · default: false · module: github
Reject all GitHub webhooks instead of accepting unverified ones in local diagnosis-only mode (stricter when true; autopilot/cloud always reject unverified).
MERGEN_GITHUB_POLICY_GATE_FAIL_ON_WARN
type: boolean · default: false · module: github
Make the Mergen Policy Gate check run FAIL (not just neutral) on warn-tier PR policy findings, not only block-tier: lets a team require warn-tier matches to be resolved before merge too, once the check is marked required in GitHub branch protection.
MERGEN_SIEM_LEDGER_VERDICTS
type: csv · default: block,hold · module: siem
Which action-ledger verdicts to stream to SIEM sinks. Every PASS is still recorded locally; this only governs forwarding.
MERGEN_AUTO_WATCH
type: boolean · default: true · module: process-watch
Auto-watch local processes.
MERGEN_AUTO_ATTACH_PORTS
type: csv · default: unset · module: process-watch
Ports to auto-attach the process watcher to.
MERGEN_WATCH
type: boolean · default: unset · module: process-watch
Process watch toggle.
MERGEN_DEGRADATION_WATCH
type: boolean · default: unset · module: degradation-watch
Background degradation watcher.
MERGEN_CAUSALITY_WINDOW_MIN
type: int · default: unset · module: incident-memory
Causal-analysis lookback window in minutes.
MERGEN_SEVERE_ERR_COUNT
type: int · default: unset
Error-count threshold for severe-incident classification.
MERGEN_SEVERE_WINDOW_MS
type: int · default: unset
Window for severe-incident error counting.
MERGEN_SEVERE_DURATION_MS
type: int · default: unset
Duration threshold for severe-incident classification.
MERGEN_DOWNTIME_COST_PER_HOUR
type: float · default: unset
Downtime cost input for impact-report economics.
MERGEN_REVENUE_PER_MINUTE_USD
type: float · default: unset
Revenue-per-minute input for impact-report economics.
MERGEN_TOPOLOGY_MAX_EDGE_AGE_DAYS
type: int · default: unset
Max age of service-graph edges before pruning.
MERGEN_POLICY_MERGE
type: string · default: unset · module: policy-sync
Merge behavior when syncing remote policy with local rules.
MERGEN_GIT_SYNC
type: boolean · default: unset · module: calibration
Sync calibration data via git.
MERGEN_GIT_ADR_SYNC
type: boolean · default: unset · module: override-corpus
Scan git history + ADRs daily for operational constraints to materialize as override corpus entries.
Guarded settings
Settings that weaken enforcement by design. They exist for narrow, legitimate cases (onboarding trials, policy migration, break-glass recovery) and are impossible to miss when active: mergen-server doctor, GET /health/integrations, the startup banner, and audit surfaces all report them. Each entry below states exactly what the dangerous value does.
MERGEN_GATE_AVAILABILITY_MODE
type: enum · values: fail-closed · fail-open · default: fail-closed
gate-check behavior when a decision genuinely cannot be obtained (server unreachable/timeout). Never applies to a computed BLOCK. fail-open is for onboarding trials only.
⚠️ When active: fail-open: a wedged, absent, or timed-out gate ALLOWS tool calls through instead of blocking them. Intended only for initial onboarding/shadow trials; never set as a team default.
MERGEN_POLICY_DRY_RUN
type: boolean · default: false
Policy dry-run: verdicts are computed and logged but NOT enforced. For policy testing before rollout. Explicit false also vetoes the onboarding-window auto-dry-run.
⚠️ When active: policy dry-run: BLOCK/HOLD verdicts are logged but NOT enforced. Every agent action executes. Unset once policy testing is done.
MERGEN_ALLOW_UNSIGNED_POLICY
type: boolean · default: false
Accept an unsigned enterprise-policy.json (migration escape hatch). Refuses to start unless MERGEN_UNSAFE_ALLOW_UNSIGNED=true is also set.
⚠️ When active: unsigned policy accepted: anything with filesystem access (including AI agents) can rewrite live enforcement policy without detection. Unset once policy migration is complete.
Requires
MERGEN_UNSAFE_ALLOW_UNSIGNED=trueto also be set; refuses to activate alone.
MERGEN_UNSAFE_ALLOW_UNSIGNED
type: boolean · default: false
Confirmation flag for MERGEN_ALLOW_UNSIGNED_POLICY; meaningless alone.
⚠️ When active: MERGEN_UNSAFE_ALLOW_UNSIGNED=true is set: unsigned-policy acceptance is armed (active only with MERGEN_ALLOW_UNSIGNED_POLICY=true).
MERGEN_PANIC_BYPASS_UNTIL
type: int · default: unset
Epoch-ms until which the panic bypass suspends gate enforcement (break-glass). Also settable via file; every use is logged and time-bounded.
⚠️ When active: PANIC BYPASS ACTIVE: gate enforcement is suspended until the configured time. If this is not a live break-glass emergency, unset it now.
MERGEN_BUILD_SOURCE_MAP
type: csv · default: unset · module: script-trust
Opt-in build-artifact source-mapping trust for script-trust holds. Entries are <outDir>:<srcDir>:<srcExt> (e.g. server/dist:server/src:.ts): when a script path resolves under outDir AND its mapped source file is git-tracked, clean against HEAD, and not newer than the artifact, the artifact is trusted without a fresh human approval. Explicitly weaker than a human approval or a cryptographic rebuild-and-compare (which would require esbuild or an equivalent as a runtime dependency, verified NOT to be one for the shipped package): mtime ordering is a heuristic, not a proof, and an agent that hand-tampers the artifact directly (leaving the mapped source untouched) while touching the artifact's mtime forward would satisfy this check. Unset by default: a build artifact gets no special treatment and the ordinary content-hash-approval model applies unconditionally, same as any other script.
⚠️ When active: build-source-mapping trust is active for one or more configured outDir rules: a script under a matching path can run without a fresh human approval based on its mapped source file's git status and an mtime-ordering heuristic, not a cryptographic guarantee. An agent that hand-tampers the compiled artifact directly (without touching the source) while touching the artifact's mtime forward would bypass this check. Leave unset for build artifacts where that risk is unacceptable.
MERGEN_TRUST_TEST_INVOCATIONS
type: boolean · default: false · module: script-trust
Opt-in bounded test-runner trust for script-trust holds. When set, a script invocation is trusted WITHOUT the usual freshness/git-clean requirement if ALL of: (1) it matches a recognized test-runner shape (today: only node's own --test flag), (2) the target's filename matches a conventional test-naming pattern (.test., .spec., test_*.py, *_test.py), and (3) the target's containing directory is git-tracked (has at least one other tracked file). Found live (2026-08-13, real-usage friction study of 420 script_trust_hold resolutions): the dominant addressable slice of low-worth repeat holds was ordinary TDD iteration (edit a test file, re-run it) where the freshness check correctly (by design) re-holds on every edit even though a human approving each successive edit provides negligible signal. Unset by default: a test invocation gets no special treatment and the ordinary content-hash-approval model applies unconditionally, same as any other script.
⚠️ When active: test-runner invocation trust is active: a script run via a recognized test-runner shape (currently
node --test <path>) against a conventionally-named test file in a git-tracked directory can run without a fresh human approval, even when freshly edited/uncommitted. An agent with legitimate write access to an established test directory could still name a file to match the test-naming convention and have it trusted without review. Leave unset where that risk is unacceptable.
MERGEN_TRUST_EPHEMERAL_SCRIPTS
type: boolean · default: false · module: script-trust
Opt-in trust for a heredoc/stdin-piped python or node script whose content is provably free of any subprocess/exec, filesystem write, network I/O, dynamic-code-execution, cloud-SDK, or sensitive-path/credential-env-var primitive this scan recognizes; see scriptHasNoSideEffects in script-trust.ts. Found live (2026-08-18 real-usage friction audit): script_trust_hold is 63-65% of all HOLDs Mergen has ever recorded, and the single largest pattern within it is a one-off heredoc debug script with no real side effect. Deterministic keyword/pattern scan only, never a scored classifier: a hit anywhere fails closed to the unchanged HOLD behavior. Bash/sh/etc. excluded entirely (no meaningful side-effect-free subset of a shell script). Accepted residual gaps: reflection/string-concatenation evasion (getattr(os, 'sys'+'tem')) is only partially mitigated, not closed; module-aliasing evasion for the os module specifically (import os as o) is not caught (subprocess/child_process ARE caught even when aliased, since they have no legitimate bare-import use in this shape, unlike os). Unset by default: a heredoc/stdin script gets no special treatment and the ordinary human-approval-per-content-hash model applies unconditionally.
⚠️ When active: ephemeral heredoc/stdin script side-effect scan is active: a python/node heredoc with no matched dangerous primitive can run without a fresh human approval, based on a deterministic keyword scan, not a real interpreter/AST analysis. A sufficiently obfuscated reflection call, or an
osimport aliased to evade the os.* checks, could slip through undetected. Leave unset where that risk is unacceptable.
MERGEN_PANIC_BYPASS_REASON
type: string · default: unset
Operator-supplied reason recorded on panic-bypass audit events.
⚠️ When active: panic-bypass reason is set (informational; MERGEN_PANIC_BYPASS_UNTIL controls activation).
MERGEN_DISABLE_LOOPBACK_TOKEN
type: boolean · default: false
Disable the loopback-token guard on local API requests (for legacy clients / containerized setups where the token file cannot be shared). Weakens local API auth to the pre-token posture.
⚠️ When active: loopback-token guard DISABLED: any local process can call the API without the per-boot token, relying only on the shared-secret guards. Intended for containerized/legacy setups; unset once the token file can be shared.
MERGEN_ZERO_RETENTION
type: boolean · default: false
VPC/regulated mode: no on-disk event retention. Deliberate privacy posture, but it also thins the local audit trail; treat as a conscious trade-off.
⚠️ When active: zero-retention mode: events are not persisted to disk. Audit reconstruction after an incident will be limited to what was forwarded (SIEM/ledger).
MERGEN_GATE_DISABLE_EVALUATE_CATEGORIES
type: csv · default: unset
Comma-separated Gate A rule categories (POLICY_RULE_CATEGORIES, enterprise-policy-engine.ts) excluded from evaluation entirely, the "Evaluate" dimension (docs/internal/CAPTURE_POLICY_DESIGN.md). Only rules with action: "warn" can ever carry a category, so this can never disable a hard BLOCK, sequence-threat/injection/self-protection detection, or the 5 IMMUTABLE_RULE_IDS. Unknown category tokens are ignored, never treated as "disabled."
⚠️ When active: one or more Gate A rule categories have Evaluate disabled: their WARN/HOLD rules are never checked. No BLOCK-tier rule, sequence-threat/injection/self-protection detection, or immutable hard-safety rule is ever affected by this setting. Unset for production use.
MERGEN_GATE_ENFORCEMENT_OVERRIDES
type: csv · default: unset
Comma-separated ruleId:target pairs downgrading an eligible rule's effective enforcement action, the "Enforce" dimension (docs/internal/CAPTURE_POLICY_DESIGN.md). target is "observe" (never affects verdict, still recorded in the audit trail) or "advise" (inform, execution continues, never a HOLD). Only ever settable for a rule whose authored action is "warn": a rule id whose action is "block" is silently ignored, never downgraded, by construction (the override map is never even consulted for it). Unknown rule ids are ignored, never treated as a match.
⚠️ When active: one or more Gate A rules have their enforcement downgraded to Observe or Advise instead of Hold. No block-tier or immutable rule is ever affected by this setting. Unset for production use.
MERGEN_FREE_CAP_MODE
type: enum · values: protect · passthrough · default: protect
What the HTTP gate routes (POST /gate/evaluate, POST /gate/evaluate-edit) do once a Free-plan install has exceeded its 10,000/month included protected-action allotment. "protect" (default) keeps Gate A fully plan-agnostic: every call is evaluated and enforced identically regardless of the cap, and the cap only ever attaches an informational usageLimited nudge to the response (CLAUDE.md's "billing never enforces" invariant). "passthrough" is a deliberate opt-in reversal of that invariant: past the cap the gate routes return PASS WITHOUT calling applyGate / evaluateEditGate at all, no rule evaluation, no HITL hold, no blast-radius check, nothing is blocked, until the plan is upgraded. Only Free is ever affected (every paid plan carries includedToolCallsPerMonth: 0 = unlimited). The local usage counter this reads (sensor/usage-meter.ts) is an unsigned on-machine file a user can edit or delete, so this is not a robust monetization boundary either. Never read inside applyGate / enterprise-policy-engine; the check lives only in the two route files, which already import the usage module.
⚠️ When active: free-cap passthrough is armed: once this Free install passes 10,000 protected actions in a billing period, the gate STOPS EVALUATING: every Bash command and file edit runs unchecked (no policy rules, no HITL, no blast-radius, no hard-safety blocks) until the plan is upgraded. This trades the "the gate never stops protecting" guarantee for an upgrade wall. Set back to "protect" unless an unprotected Free tier past the cap is an explicit, accepted product decision.
Infrastructure
Settings an infrastructure operator decides: ports, paths, URLs, deployment context, and credential material. Changing these describes a different deployment; it does not loosen the gate.
MERGEN_GATE_HOOK_TIMEOUT_MS
type: int · default: 20000
How long gate-check (the PreToolUse hook) waits for a decision before applying the availability mode. Bounded well under Claude Code's ~60s hook-kill budget even at the 2x worst case (one bounded recovery retry on an ambiguous timeout); raising this significantly risks the hook process being killed before it can report HELD, letting the tool call through unblocked.
MERGEN_GATE_HEARTBEAT_INTERVAL_MS
type: int · default: unset
Interval for the gate liveness heartbeat.
MERGEN_GATE_HEARTBEAT_MAX_AGE_MS
type: int · default: unset
Maximum heartbeat age before the gate is considered stale.
MERGEN_MAX_BLUNDERS
type: int · default: unset
Cap on stored agent-blunder records.
MERGEN_MAX_GATE_HISTORY
type: int · default: unset
Cap on stored gate decision history entries.
MERGEN_PORT
type: int · default: 3000
HTTP listen port.
MERGEN_ROUTER_PORT
type: int · default: unset
ADR-017 Phase 1 (experimental, opt-in: started only via mergen-server router, never by mergen-server start): pins the router process's canonical listen port. No default; unset means "auto-scan 3000-3010", the same range mergen-server itself defaults to; a registered default of 3000 here would make an unset value indistinguishable from an explicit pin. Distinct from MERGEN_PORT, which pins a WORKER's own port (including one the router spawns); the two must never be conflated, since a router and a worker are different process kinds.
MERGEN_BIND
type: string · default: 127.0.0.1
Bind address. Non-loopback enables team mode and requires MERGEN_SECRET + MERGEN_PUBLIC_URL.
MERGEN_WORKER_IDLE_REAP_HOURS
type: int · default: 24
ADR-017 router-spawned workers (bound to a port in worker-manager.ts's private 40000-40999 range) self-exit after this many hours with no non-health HTTP request, so an abandoned scratch/benchmark workspace's detached worker does not run forever and squat low ports in that range (found live 2026-08-15: leaked benchmark workers pushed a real workspace's worker up to :40004). "No non-health request" only means genuinely untouched; a workspace with an open VS Code panel or active CLI/hook traffic keeps resetting this on every real poll (app.ts records activity ahead of every route except literal /health), so this never reaps something actually in use. Lowered from the original 168h (2026-08-28, a second lifecycle audit): a week was tuned for the port-squatting bug alone, not for a dev machine's actual memory footprint; each idle worker independently holds a full policy engine + ledger/audit DB connections, and 168h let 17 workers (7.5GB RSS) accumulate over a single week of normal multi-workspace use. 24h still tolerates an overnight/weekday gap; a reaped worker respawns lazily and transparently on the next real request (resolveOrSpawnWorker), so this is a resource-hygiene tuning knob, not a correctness one. Never applies to a classic mergen-server instance on the legacy 3000-3010 range, or an explicit MERGEN_PORT pin outside 40000-40999; those were started by deliberate human action (mergen-server start) and are never auto-reaped. Set to 0 to disable.
MERGEN_HOST
type: string · default: unset
Server host override used by CLI clients to reach the server.
MERGEN_DATA_DIR
type: string · default: ~/.mergen
Data directory for all on-disk stores: license, the enrolled runtime credential, the durable action ledger, HITL hold state, approved-script trust, override corpus. Set this to a path on a volume that survives a rebuild in Docker, Dev Containers, Codespaces, or Gitpod; the default (home directory) is normally INSIDE the container and is wiped on rebuild, which also re-enrolls the workspace as a new Fleet identity and (see onboarding-window.ts) skips the first-install grace period rather than risk silently disabling an existing team's HOLD approvals.
MERGEN_BUFFER_SIZE
type: int · default: unset
Ring buffer capacity (events).
MERGEN_OTLP_BODY_LIMIT
type: string · default: 16mb
Max request body on /v1/* OTLP routes.
MERGEN_TLS_CERT
type: string · default: unset
TLS certificate path (cloud/team mode).
MERGEN_TLS_KEY
type: string · default: unset
TLS private key path (cloud/team mode).
MERGEN_ALLOWED_ORIGINS
type: csv · default: unset
CORS allow-list in team/cloud mode.
MERGEN_PUBLIC_URL
type: url · default: unset
Externally reachable base URL: HITL approve/deny links, Slack OAuth redirect, OIDC issuer. Required in team/cloud mode.
MERGEN_TRUSTED_PROXY
type: string · default: unset
Express trust-proxy setting for deployments behind a reverse proxy.
MERGEN_CLOUD_MODE
type: boolean · default: false
Multi-tenant SaaS deployment mode: Postgres+Redis required, API-key auth, tenant isolation.
MERGEN_PG_URL
type: secret · default: unset
Postgres connection string (cloud mode). May embed credentials.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_REDIS_URL
type: secret · default: unset
Redis connection string (ring-buffer persistence / cloud mode). May embed credentials.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_BULLMQ
type: boolean · default: unset
Use BullMQ (Redis) for background job queues.
MERGEN_WASM_PATH
type: string · default: unset
Path override for bundled WASM artifacts.
MERGEN_MODEL
type: string · default: unset
Model id for the optional LLM spokesperson (advisory summaries only, never in the enforcement path).
MERGEN_API_URL
type: url · default: unset
Activation/licensing backend base URL. On a paid plan this is also the destination for periodic background sync: machine identity/heartbeat, usage counts, resolved approval decisions (including the held command argument), and Agent Blunder Log entries (including blocked command text and reason). None of this is required for local enforcement, and none of it is sent on Free.
MERGEN_SKIP_SIGNIN
type: boolean · default: false
2026-09-05: every plan now requires an account, Free included (no payment for Free) — mergen-server setup blocks on the device-auth sign-in flow by default. This opts a scripted/CI install out of that one-time interactive step (an alternative to MERGEN_TOKEN when the install genuinely has no account and no machine token). Never affects Gate A's PASS/BLOCK/HOLD verdict, which stays plan-agnostic and unauthenticated-safe either way — org/cloud-policy features simply keep refusing to work until a real mergen login runs.
MERGEN_BASE_URL
type: url · default: unset
Base URL override for self-referential links.
MERGEN_DASHBOARD_URL
type: url · default: unset
Dashboard base URL override used in notification links.
MERGEN_TELEMETRY
type: boolean · default: unset
Product telemetry opt-in/out.
MERGEN_TELEMETRY_URL
type: url · default: unset
Product telemetry endpoint override.
MERGEN_LS_VARIANT_MAP
type: string · default: unset
LemonSqueezy variant→plan mapping override (billing metadata only; billing never enforces).
MERGEN_MEMBER_ID
type: string · default: unset
Pin this install's identity in usage reports.
MERGEN_SECRET
type: secret · default: unset
Shared secret for the /ingest endpoint (x-mergen-secret). Other admin routes are guarded by ~/.mergen/secret or MERGEN_ADMIN_SECRET.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_ADMIN_SECRET
type: secret · default: unset
Dedicated env-only secret for the admin-mutation guard and sensitive-GET guard. Recommended for production so agents with filesystem access cannot forge admin actions.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_AUDIT_SECRET
type: secret · default: unset
HMAC key for audit evidence-pack signing.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_POLICY_SIGNING_SECRET
type: secret · default: unset
HMAC key for local enterprise-policy.json tamper evidence. Falls back to ~/.mergen/secret when unset (weaker: on-disk).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_POLICY_HMAC_SECRET
type: secret · default: unset
HMAC key verifying REMOTE policy-sync responses (X-Mergen-Policy-Signature). Distinct from MERGEN_POLICY_SIGNING_SECRET (local file signing).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_POLICY_SYNC_TOKEN
type: secret · default: unset
Bearer token for the self-hosted policy sync plane (/policies/sync).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_OIDC_SIGNING_KEY
type: secret · default: unset
PEM/PKCS8 RSA private key for the OIDC issuer (GCP/Azure credential federation). Falls back to a key persisted on disk when unset (weaker).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_AGENT_TOKEN
type: secret · default: unset
Verified agent identity token presented by a registered agent process.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_TOKEN
type: secret · default: unset
CI/CD and ephemeral non-interactive environment machine token.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_PLAN_ID
type: string · default: unset
CI/CD license plan override (used with MERGEN_TOKEN).
MERGEN_AGENT_TOKEN_SECRET
type: secret · default: unset
HMAC key for signing/verifying agent identity tokens.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SSO_TOKEN
type: secret · default: unset
Bearer token required on mutating requests when MERGEN_SSO_REQUIRED=true.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_USER_ID
type: string · default: unset
FALLBACK human principal on ledger rows. A verified agent token's SSO-federated userId always wins over this unauthenticated value.
MERGEN_ENVIRONMENT
type: string · default: unset
Deployment environment label (production/staging/dev) matched by policy rule conditions.
MERGEN_REPO
type: string · default: unset
Repository label (org/name) matched by policy rule conditions.
MERGEN_GIT_BRANCH
type: string · default: unset
Current git branch matched by policy rule branch conditions.
MERGEN_AGENT_ID
type: string · default: unset
Registered agent id for this process, matched by policy agentIds conditions.
MERGEN_CLIENT
type: string · default: unset
Client surface label (claude-code/cursor/cli-hook/…) recorded on gate decisions.
MERGEN_TRACE_ID
type: string · default: unset
Trace id propagated onto ledger rows for cross-tool correlation.
MERGEN_SERVICES
type: csv · default: unset
Known service names for attribution.
MERGEN_TENANT_ID
type: string · default: unset
Tenant id for cloud-mode client calls.
MERGEN_DEFAULT_TENANT_ID
type: string · default: unset
Default tenant id assigned to unattributed events (cloud mode).
MERGEN_SYSTEM_TENANT_ID
type: string · default: unset
Reserved tenant id for system-generated events (cloud mode).
MERGEN_WATCH_INTERVAL_MS
type: int · default: unset · module: process-watch
Process watcher poll interval.
MERGEN_POLICY_URL
type: url · default: unset · module: policy-sync
Central policy server URL for team policy sync. HTTPS enforced at startup.
MERGEN_CLOUD_POLICY_SYNC
type: boolean · default: true · module: cloud-policy-sync
Automatically pull and activate Mergen Cloud org policy on an interval, for signed-in paid-plan installs. false = cloud policy sync only via the manual policy pull --cloud command.
MERGEN_CLOUD_POLICY_POLL_MS
type: int · default: 120000 · module: cloud-policy-sync
Interval between automatic Mergen Cloud policy sync attempts, in ms.
MERGEN_AUTH_STUB
type: boolean · default: false
DEV ONLY: serve a local device-authorization stub standing in for api.mergen.app so activation runs offline. Affects licensing/plan metadata only, never enforcement.
MERGEN_AUTH_STUB_PLAN
type: string · default: unset
DEV ONLY: plan the auth stub grants.
MERGEN_AUTH_STUB_EMAIL
type: string · default: unset
DEV ONLY: account email the auth stub reports.
MERGEN_AUTH_STUB_GITHUB_LOGIN
type: string · default: unset
DEV ONLY: fake GitHub login the offline Connect-GitHub broker stub reports.
MERGEN_AUTH_STUB_SLACK_TEAM
type: string · default: unset
DEV ONLY: fake Slack workspace name the offline Connect-Slack broker stub reports.
Integrations
Connections to external systems (Slack, PagerDuty, SIEM, email, …). Integrations deliver notifications and reports; the security decision itself never depends on one being configured.
MERGEN_OKTA_DOMAIN
type: string · default: unset · module: idp
Okta domain for IDP identity enrichment.
MERGEN_ENTRA_TENANT_ID
type: string · default: unset · module: idp
Microsoft Entra tenant for IDP identity enrichment / Azure federation.
MERGEN_OIDC_CLIENT_ID
type: string · default: unset · module: idp
OIDC client id for IDP identity enrichment.
MERGEN_OIDC_ISSUER_URL
type: url · default: unset · module: idp
External OIDC issuer URL for verifying operator identities.
MERGEN_OIDC_JWKS_URL
type: url · default: unset · module: idp
JWKS endpoint override for the external OIDC issuer.
MERGEN_SLACK_BOT_TOKEN
type: secret · default: unset · module: slack
Slack Web API token (threads, replies, HITL delivery fallback). Optional once the OAuth install flow has persisted a token.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SLACK_CHANNEL
type: string · default: unset · module: slack
Default incident channel.
MERGEN_SLACK_SIGNING_SECRET
type: secret · default: unset · module: slack
HMAC secret verifying inbound Slack interactions; without it every interactive button click is rejected with 401.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SLACK_WEBHOOK
type: secret · default: unset · module: slack
Simple-mode incoming webhook for alerts with link buttons.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SLACK_CLIENT_ID
type: string · default: unset · module: slack
Slack app OAuth client id: enables /slack/install.
MERGEN_SLACK_CLIENT_SECRET
type: secret · default: unset · module: slack
Slack app OAuth client secret for the install flow.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SLACK_DIGEST
type: boolean · default: unset · module: slack
Post the daily operational digest at 09:00 UTC.
MERGEN_SLACK_DIGEST_CHANNEL
type: string · default: unset · module: slack
Channel override for the daily digest.
MERGEN_TEAM_DIGEST
type: boolean · default: unset · module: slack
Post the weekly team digest Mondays 09:15 UTC (reports only, never HITL).
MERGEN_HITL_WEBHOOK_URL
type: secret · default: unset · module: hitl
Explicit HITL delivery webhook (first in preference order). The HOLD itself always runs on every plan; delivery is the convenience.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_HITL_SECONDARY_WEBHOOK
type: secret · default: unset · module: hitl
Delegation chain: fired at the 5-min mark if the primary channel produced no response.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_HOLD_NOTIFY
type: enum · values: off · on · default: off · module: hitl
Desktop notification (macOS osascript / Linux notify-send) the moment a HOLD is placed — for a terminal-first user with no Slack/webhook and no mergen monitor open. Opt-in; fire-and-forget, never blocks or affects the hold. The HOLD and its 15-min auto-deny are unchanged either way. Subsumed by MERGEN_NOTIFY below (still honored: on = MERGEN_NOTIFY=hold).
MERGEN_NOTIFY
type: string · default: `` · module: hitl
Comma list of gate events to fire a native desktop toast on: block, hold, hold-expiry (or all). The CLI-side parity for the VS Code extension's notifyOnBlock/notifyOnHold/notifyOnHoldExpiry (docs/SURFACE_PARITY.md). Default off; each fire is fire-and-forget and never affects the verdict, delivery, or the 15-min auto-deny. macOS osascript / Linux notify-send; other platforms skip silently.
MERGEN_PAGERDUTY_SECRET
type: secret · default: unset · module: pagerduty
INBOUND webhook HMAC signing secret. Required in cloud mode and under autopilot.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_PAGERDUTY_ROUTING_KEY
type: secret · default: unset · module: pagerduty
OUTBOUND Events API v2 key: pages when HITL approvals go unanswered for 10 min. Distinct from the inbound signing secret.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_PAGERDUTY_OAUTH_CLIENT_ID
type: string · default: unset · module: pagerduty
PagerDuty OAuth App client id (BYO app): enables /pagerduty/install. Falls back to the hosted Connect broker when unset. Distinct from MERGEN_PAGERDUTY_ROUTING_KEY, which this OAuth flow provisions automatically.
MERGEN_PAGERDUTY_OAUTH_CLIENT_SECRET
type: secret · default: unset · module: pagerduty
PagerDuty OAuth App client secret for the BYO install flow.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_PR_COMMENTS
type: boolean · default: unset · module: github
Post AI code review comments on PRs (enables habituation tracking).
MERGEN_GITHUB_CLIENT_ID
type: string · default: unset · module: github
GitHub App/OAuth App client id: enables /github/install.
MERGEN_GITHUB_CLIENT_SECRET
type: secret · default: unset · module: github
GitHub App/OAuth App client secret for the install flow.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_LINEAR_CLIENT_ID
type: string · default: unset · module: linear
Linear OAuth App client id (BYO app): enables /linear/install. Falls back to the hosted Connect broker when unset.
MERGEN_LINEAR_CLIENT_SECRET
type: secret · default: unset · module: linear
Linear OAuth App client secret for the BYO install flow.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SENTRY_SECRET
type: secret · default: unset · module: sentry
HMAC secret verifying inbound Sentry webhooks. When unset, Sentry events are accepted only in local diagnosis-only mode.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_JIRA_CLIENT_ID
type: string · default: unset · module: jira
Jira/Atlassian OAuth App client id (BYO app): enables /jira/install and lets this process refresh its own access token directly. Falls back to the hosted Connect broker (refresh proxied through it) when unset.
MERGEN_JIRA_CLIENT_SECRET
type: secret · default: unset · module: jira
Jira/Atlassian OAuth App client secret; required for both the BYO install flow and every subsequent token refresh (Atlassian requires client_secret on refresh_token grants, not just the initial code exchange).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SIEM_WEBHOOK_URL
type: url · default: unset · module: siem
Generic SIEM webhook: blunders + forwarded ledger rows POSTed as JSON.
MERGEN_SIEM_WEBHOOK_TOKEN
type: secret · default: unset · module: siem
Bearer token for the generic SIEM webhook.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SPLUNK_HEC_URL
type: url · default: unset · module: siem
Splunk HTTP Event Collector endpoint.
MERGEN_SPLUNK_HEC_TOKEN
type: secret · default: unset · module: siem
Splunk HEC token.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_ELASTIC_URL
type: url · default: unset · module: siem
Elasticsearch endpoint for audit forwarding.
MERGEN_ELASTIC_API_KEY
type: secret · default: unset · module: siem
Elasticsearch API key.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_EMAIL_DIGEST
type: boolean · default: unset · module: email
Enable the daily digest email.
MERGEN_SMTP_URL
type: secret · default: unset · module: email
Single-URL SMTP config (may embed credentials).
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SMTP_HOST
type: string · default: unset · module: email
SMTP host (discrete form).
MERGEN_SMTP_PORT
type: int · default: 587 · module: email
SMTP port.
MERGEN_SMTP_USER
type: string · default: unset · module: email
SMTP username.
MERGEN_SMTP_PASS
type: secret · default: unset · module: email
SMTP password.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_SMTP_SECURE
type: boolean · default: unset · module: email
Explicit TLS override (default true only on port 465).
MERGEN_EMAIL_FROM
type: string · default: unset · module: email
Digest sender address.
MERGEN_EMAIL_TO
type: csv · default: unset · module: email
Digest recipients.
MERGEN_NTFY_TOPIC
type: string · default: unset · module: notifications
ntfy.sh topic name.
MERGEN_NTFY_URL
type: url · default: https://ntfy.sh · module: notifications
ntfy server.
MERGEN_NTFY_TOKEN
type: secret · default: unset · module: notifications
ntfy access token.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_DISCORD_WEBHOOK_URL
type: secret · default: unset · module: notifications
Discord alert webhook.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_DISCORD_CLIENT_ID
type: string · default: unset · module: notifications
Discord OAuth App client id (BYO app): enables /discord/install. Falls back to the hosted Connect broker when unset.
MERGEN_DISCORD_CLIENT_SECRET
type: secret · default: unset · module: notifications
Discord OAuth App client secret for the BYO install flow.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
MERGEN_FLEET_SYNC_URL
type: url · default: unset · module: fleet-audit
Self-hosted sync plane URL member installs report audit rows to (single-team, own-infra).
MERGEN_LEDGER_SYNC_URL
type: url · default: unset · module: cloud-ledger-sync
ADR-013: base URL of a MERGEN_CLOUD_MODE=true Mergen deployment this install pushes its local action-ledger/blunder-log rollup to, for cross-install visibility under that deployment's own tenant. Distinct from MERGEN_API_URL (Mergen's own hosted licensing/Governance Console) and MERGEN_FLEET_SYNC_URL (the self-hosted sync plane): this targets a customer-operated cloud-mode Mergen server's own POST /v1/ledger-batch. Requires MERGEN_LEDGER_SYNC_API_KEY. Silent/no-op when either is unset; Gate A's own local write path never depends on this.
MERGEN_LEDGER_SYNC_API_KEY
type: secret · default: unset · module: cloud-ledger-sync
Tenant API key (x-api-key) for MERGEN_LEDGER_SYNC_URL's cloudAuthMiddleware, issued by that deployment via POST /api-keys, identifies which tenant this install's pushed rows are stamped under.
Secret: set via an env-only mechanism (secrets manager, systemd EnvironmentFile). The value is never rendered by any Mergen surface and is rejected from the signed config file.
Experimental flags
MERGEN_EXPERIMENTAL_* flags are undocumented, unstable, and bound by monotonic strictness: they may only add capability or escalate PASS→HOLD, never weaken a verdict.
Modules & tiers
The capability manifest (server/src/config/modules.ts): inspect live state on any install with mergen-server config modules or GET /config/modules.
Trusted Core: no off switch exists in code
- Execution Gateway: The Claude Code/Windsurf Bash+Edit PreToolUse hook, Cursor/VS Code self-heal, and
mergen-server exec. Every covered call passes the gate before its handler runs. - Policy Engine: Deterministic <1ms rule evaluation → PASS / HOLD / BLOCK. Immutable hard-safety rules cannot be edited or bypassed by any setting.
- Verdicts & Guided Alternatives: Every BLOCK/HOLD carries why it happened and what to do instead, so agents reformulate instead of stopping.
- Audit Recording: Action ledger (every PASS/HOLD/BLOCK), hash-chained Agent Blunder Log, usage meter. Recording is core; forwarding is an integration; retention is config.
- Human-in-the-Loop Holds: HOLD suspends the call for human decision and fails closed (15-min auto-deny). The hold is core on every plan; delivery channels are integrations.
- Admin Auth Guards: Mutation + sensitive-GET guards over every admin surface, including the signed org-policy settings file.
- PII Shield: Always-on redaction patterns (emails, keys, JWTs, cards) on stored/streamed content; extendable, never disableable.
Modules: toggleable; disabling can only make the gate same-or-stricter
- Incident Autopilot (Gate B): Autonomous diagnose→fix→validate loop on incidents. Off by default; shadow mode is its staging tier.
- Override Corpus: Human overrides encoded as enforcement policy; feeds Gate B always and Gate A via the four explicit opt-in paths.
- Policy Suggester: Stages repeatedly-overridden patterns as HOLD-only proposals for one-click human approval. Never auto-activates, never proposes a BLOCK.
- Change Authorization Gate (Gate C): POST /ci/gate diff-content review: deterministic detectors (secret introduction, test deletion, auth-bypass, CI-check removal, permission/config weakening) plus a heuristic task-to-diff scope match. Governs what code a PR is allowed to leave behind, distinct from Gate A (tool-call execution) and Gate B (autopilot fixes). MERGEN_CHANGE_GATE_MODE=shadow runs the same evaluation for measurement without affecting the verdict, CI build, or review label; the rollout ramp before MODE=enforce.
- Edit-Time Change Gate: Claude Code, GitHub Copilot CLI, and Windsurf pre-write hooks plus Cursor/VS Code self-heal integrations: reuses Gate C's deterministic diff-content detectors at edit time instead of only at PR-diff time (/ci/gate). MERGEN_EDIT_GATE_MODE=shadow (default) computes and logs every finding without blocking or reverting the write.
- Script Trust: Opaque-script escalation: untracked/fresh scripts hold for approval; approval vouches for exact content (HMAC-signed store). Window=0 disables only the freshness check; git-tracking and workspace checks stay on.
- Exec Sandbox: Runs
mergen-server execcommands in Docker or macOS Seatbelt isolation instead of directly on the host. - Cloud Credential Broker: Ephemeral task-scoped AWS/GCP/Azure credentials instead of long-lived secrets in agent config. Active when credential scopes are configured.
- Agent & Human Identity: Verified agent tokens with SSO-federated human principals bound in; RBAC roles for approvals.
- Incident Memory & Diagnosis: Causal analysis, incident similarity, postmortem retrieval: the context brief that cuts MTTR.
- Process Watchers: Local process/port auto-watch feeding runtime telemetry into the buffer.
- Degradation Watcher: Background watcher that flags sustained error-rate degradation.
- Confidence Calibration: Platt-scaled confidence from engineer verdict tags; governs Gate B autonomy thresholds only.
Integrations: delivery & ingest channels
- Slack: Incident threads, HITL approve/deny buttons, daily + weekly digests.
- HITL Delivery Webhooks: Explicit webhook chain for hold notifications (primary + 5-min secondary escalation).
- PagerDuty: Inbound incident webhooks (signed) + outbound paging on unanswered HITL approvals.
- GitHub: PR review comments (habituation), webhook-fed commit context, CI gate reporting.
- Linear: Ticket creation from incidents/holds via the Linear GraphQL API.
- Jira: Ticket creation from incidents/holds via the Jira REST API: OAuth (Connect broker or BYO app) or the legacy JIRA_BASE_URL/EMAIL/API_TOKEN Basic-Auth paste form.
- Sentry: Error events into the diagnosis buffer (signed webhooks).
- Datadog: Trace fetch + blame attribution during triage.
- SIEM Forwarding: Blunders + selected ledger verdicts streamed to webhook / Splunk HEC / Elastic.
- Email Digest: Daily/weekly digest sink. Deliberately NEVER a HITL channel (pinned by test).
- Push Notifications: ntfy.sh and Discord alert channels.
- IDP Enrichment (Okta / Entra): Operator identity enrichment from the org IDP.
- Policy Sync Plane: Pulls the team's shared policy from a central instance (HTTPS + HMAC verified).
- Cloud Policy Sync: Automatically pulls and activates Mergen Cloud org policy for signed-in paid-plan installs (distinct from the self-hosted Policy Sync Plane above).
- Fleet Audit Sync: Member installs report ledger rollups to a self-hosted sync plane (single-team, own infra).
- Cloud Ledger Sync: ADR-013: pushes this install's local action-ledger/blunder-log rollup to a customer-operated MERGEN_CLOUD_MODE=true Mergen deployment's authenticated ingestion endpoint (POST /v1/ledger-batch), tenant-stamped there from the API key; never by Gate A, which stays tenant-agnostic and never writes to Postgres directly.
- Redis Persistence: Ring-buffer persistence across restarts.