← All docs

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=true to 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 os import 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 exec commands 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.

Last updated September 9, 2026