Skip to content

Settings reference

Generated page

This page is built from settings-schema.js, the registry the plugin itself reads, every time the site is built, so it always matches the code on main. How to change a setting: Changing settings.

Settings live in ~/.anti-hall/settings.json. Change them with /anti-hall:settings ("set autoHandover.pct to 80") or the CLI:

node plugins/anti-hall/scripts/settings.js set autoHandover.pct 80

How to read the tables

Mark Meaning
config Also shown in Claude Code's native /config panel.
safety Changing it in the risky direction needs --confirmed (or a direct request from you).
advanced A tuning knob. settings.js show hides it unless you pass --all.

Env is an ANTIHALL_* environment variable that overrides the file value. Precedence, highest first: environment variable, settings.json, the /config panel, a legacy per-feature file, the default.

330 settings in 20 sections: Auto Handover, Guards, Safety Guards, Context Injections, Maintenance, Agent tracker, Version Alerts, Updates / Maintenance, Limit Conservation, Jev (semantic decision engine), Jev cascade, Jev integration, DevSwarm, Statusline, Codex Nudge, Process watch, Resource watch, Disk watch, Engine, Defects.

Auto Handover

Automatic session-handover writing as context fills up.

Setting Default Type Env What it does
autoHandover.enabled true boolean Write an automatic handover before context runs out.
autoHandover.pct 85 number, 1 to 99 ANTIHALL_AUTO_HANDOVER_PCT Context-usage percent that triggers an automatic handover.
autoHandover.maxTokens 0 number, at least 0 ANTIHALL_AUTO_HANDOVER_MAX_TOKENS Opt-in absolute context-token ceiling that also triggers the handover, whichever of pct/maxTokens fires first; 0 (the default) = no ceiling — the real per-session context window size (85% of it) is the only trigger unless a user explicitly sets this.
autoHandover.nag true boolean Nag (remind) the user when a handover is due but not yet written.
autoHandover.nagStepPct 5 number, 1 to 100 Percent increments between successive handover nags.
autoHandover.nagQuietMin 15 number, at least 1 Minutes to wait before repeating a handover nag.
autoHandover.gateNewWork true boolean Post-handover new-work gate: once context is past the threshold and this session's handover is written, the agent judges each new request's size before starting it and, if it needs more than gateBudgetPct of the context window, offers to park it in the task list + handover (start after /compact or /clear) or proceed if you insist. Quick questions, finishing the in-flight task, and spawning a DevSwarm workspace pass straight through.
autoHandover.gateBudgetPct 5 number, 1 to 50 Context-window points a new request may use after the handover before the gate applies; also the measured backstop — one capped reminder to refresh the handover and offer to park the rest once usage grows this many points past where the handover was saved.
autoHandover.decisivePrompt true boolean At a Stop (turn-ending) point once this session's handover exists and is fresh, tell the agent to end its reply with one prominent line naming the exact /compact (or /clear, or Codex /new) command — or, if the handover has gone stale since it was written, to refresh it first. Off reverts to the plain fire/pause-nag wording.
autoHandover.gateHousekeepingMarkers "" comma-separated list Extra comma-separated markers (case-insensitive substrings) that identify a scheduled/cron housekeeping prompt (e.g. a mailbox-wake or DevSwarm peer-check tick), on top of the built-in defaults ("inbox tick", "peer check", "BROADCAST bug sweep") — a matching prompt never gets the POST-HANDOVER NEW-WORK GATE nudge.

Guards

On/off switches and tuning for the always-on safety guard hooks.

Setting Default Type Env What it does
guards.mergeGate false boolean ANTIHALL_MERGE_GATE Enable merge-readiness gate checks before merging.
guards.shipitGate false boolean ANTIHALL_SHIPIT_GATE Enable the ship-it workflow gate.
guards.outputVerifyGuard true boolean ANTIHALL_OUTPUT_VERIFY_GUARD Output-verification guard (blocks unverified completion claims).
guards.outputVerifyOncePerTurn true boolean ANTIHALL_OUTPUT_VERIFY_ONCE_PER_TURN Show the output-verify advisory once per turn per distinct pass/fail signal set instead of after every identical test re-run. false = every mixed result.
guards.failureRootCauseNudge true boolean ANTIHALL_FAILURE_ROOT_CAUSE_NUDGE Nudge toward root-cause analysis after a failure.
guards.failureNudgeFilter true boolean ANTIHALL_FAILURE_NUDGE_FILTER Cut root-cause-nudge noise: stay silent on expected exit-1 predicates (grep no-match, test, diff, git diff --quiet), on harness refusals, and after the first nudge in a turn. false = nudge on every failure again.
guards.repoSelfDrift true boolean ANTIHALL_REPO_SELF_DRIFT anti-hall's own repo-drift self-check hook.
guards.stashGuard false boolean ANTIHALL_STASH_GUARD SAFETY (confirm to change — see settings.js set/reset). Arm the git-stash guard in command-guard: block mutating git stash (also armed per-repo via .anti-hall/protected-stashes).
If changed: git stash commands that can silently drop uncommitted work will no longer be blocked.
guards.handoverCommitGuard true boolean ANTIHALL_HANDOVER_COMMIT_GUARD git-guard: block a git commit whose paths include a session handover (.anti-hall/handovers/* at any depth, or HANDOVER.md, CONTINUE-HERE.md, *.continue-here.md at the repo root). Handovers are local session state and are never committed; git add is never blocked.
guards.gitAliasResolve true boolean ANTIHALL_GIT_ALIAS_RESOLVE SAFETY (confirm to change). git-guard: resolve git <alias> through the repo/global git config (chains and !shell aliases included) and scan what it really runs; block defining a git alias (git config alias.x, -c alias.x=, GIT_CONFIG_VALUE_<n>) or shell alias whose body is a blocked git command, and scan a call to a shell alias/function defined in the same command as the git command it forwards to. Builtin subcommands never spawn git.
If changed: a git alias (or a shell alias) that runs a force push or an AI-credited commit will no longer be seen through.
guards.gitReusedMessageCheck true boolean ANTIHALL_GIT_REUSED_MESSAGE_CHECK SAFETY (confirm to change). git-guard: for a git commit with no -m/-F, read the message it would reuse (-C/-c/--reuse-message/--reedit-message <rev>, HEAD for --amend, -t/commit.template) and block it when it carries an AI self-credit trailer. A reused-verbatim message (-C, --no-edit, a no-op editor) always blocks; an editor-path commit blocks only when the command sets no real editor of its own. What an editor or commit hook writes is caught afterwards by the PostToolUse audit.
If changed: a commit that reuses an AI-credited message (-C/-c <rev>, --amend, a commit template) will no longer be blocked before it runs.
guards.gitGuardHeredocData true boolean ANTIHALL_GIT_GUARD_HEREDOC_DATA git-guard: a heredoc whose consumer is not a shell is data, so its body is not scanned as commands. Applies only when every heredoc in the command ends in a prose/data file (.md, .txt, .rst, .log, ...) via cat/tee, a git commit/tag/notes/merge message (-F - or $(cat <<EOF)), or a gh pr/issue/release body; every other command in the line is on a short allowlist (cat, tee, git, gh, echo, printf, cd, mkdir, wc, ...); and no target is a script, dotfile, git hook or .git/.husky/.ssh/.config path. Bodies fed to bash/sh/eval/source/xargs/python/..., piped into a shell, or written to a file the same line runs stay scanned. A git beside it may use only commit/tag/notes/merge, status/log/diff/show/add or rev-parse with listed flags (no fetch/push/pull/clone/remote/submodule/config), and a gh only pr/issue/release create/edit/comment with listed flags and no --; any other flag keeps the bodies scanned. Commit/PR credit trailers are checked either way. false = scan every heredoc body as shell (the old behaviour).
guards.gitignoreHint true boolean ANTIHALL_GITIGNORE_HINT One-time (per project, every 7 days) SessionStart reminder to git-ignore .anti-hall/ when it exists in a git repo and is not ignored; doctor always reports it.
guards.allowAnthropicEnvKey false boolean SAFETY, home-settings only (no env / project override). Opt-in: let the speculation judge and Jev triage read ANTHROPIC_API_KEY from the environment (Codex has no plugin options). Default off.
If changed: anti-hall would read ANTHROPIC_API_KEY from the environment for the speculation judge and Jev triage fallback instead of only the anthropic_api_key plugin option.
guards.emitDedupe true boolean ANTIHALL_EMIT_DEDUPE Deduplicate repeated hook-emit output.
guards.injectionRepeatEvery 10 number, at least 0 ANTIHALL_INJECTION_REPEAT_EVERY Turns between full re-injections of a static UserPromptSubmit reminder block (VERIFY-FIRST, the task-tracker SHORT line, the DEVSWARM PRIMARY dispatch-tier/top-fan-out-tier suffixes, the DEVSWARM WORKSPACES table when unchanged) once its first-turn/post-compact copy has been consumed; set 0 to restore every-turn injection.
guards.codexQuotaDetect true boolean ANTIHALL_CODEX_QUOTA_DETECT Detect a Codex-CLI quota/rate-limit exhaustion message in a codex:codex-rescue Agent result and record it to ~/.anti-hall/codex-availability.json so other lanes/sessions stop rediscovering the outage independently.
guards.editGuardAllow "" comma-separated list ANTIHALL_EDIT_GUARD_ALLOW SAFETY (confirm to change — see settings.js set/reset). Extra allowed file globs for edit-guard (comma/colon separated).
If changed: those files can be edited without edit-guard's protection.
guards.allowSubagentMailbox false boolean ANTIHALL_ALLOW_SUBAGENT_MAILBOX SAFETY (confirm to change — see settings.js set/reset). One-off allow for the subagent-mailbox command pattern.
If changed: subagents can read/ack the Primary's mailbox, which is normally blocked.
guards.allowReadOnlyVerify true boolean ANTIHALL_ALLOW_READ_ONLY_VERIFY command-guard "narrow allow": lets the coordinator run ONLY these shapes inline: a non-heavy command with --check/--dry-run/--list, <cc> -fsyntax-only, python3 -m pytest -q <one file>, node --test <1-2 files>, ctest -R <name>, or git clone --depth 1 <https-url> <scratchpad/tmp dir>, only when piped to tail/head/grep -c/grep -m N/wc with no other segment left unaccounted for and no write redirect outside the scratchpad/tmp.
guards.allowReadOnlyVerifyScripts true boolean ANTIHALL_ALLOW_READ_ONLY_VERIFY_SCRIPTS command-guard read-only verify, script form: lets the coordinator run <python*\|node\|ruby\|perl\|php> <existing script file> --check\|--dry-run\|--list piped to a bounded sink inline. No inline-code flag (-c/-e/-m/--eval), no stdin/heredoc script, no wrapper verb, and the remaining arguments must be non-heavy. Requires guards.allowReadOnlyVerify.
guards.projectCommandAllow true boolean ANTIHALL_PROJECT_COMMAND_ALLOW command-guard per-project allowlist: a repo may declare its own sanctioned exact commands (e.g. a deploy script that must never be delegated) in <repo-toplevel>/.anti-hall/command-allow.json, run inline in the MAIN THREAD ONLY. Default empty config means no behavior change. Kill-switch: false disables the carve-out entirely.
guards.projectEditAllow true boolean ANTIHALL_PROJECT_EDIT_ALLOW edit-guard per-project doc-edit allowlist: a repo may list repo-relative globs in <repo-toplevel>/.anti-hall/edit-allow.json ({"paths":["docs/**"]}) that the MAIN THREAD may Edit/Write directly. Applies only after the user trusts that exact file content (settings.js trust-edit-allow <repo> --confirmed); an edit revokes trust. Never matches outside the repo, .git, .anti-hall, .claude, .codex, hooks config or ~/.claude. Kill-switch: false disables it.
guards.allowPlainPush true boolean ANTIHALL_ALLOW_PLAIN_PUSH command-guard "allow plain push": in the MAIN THREAD ONLY, lets git add/git commit/a plain git push [-q\|--quiet\|-u\|--set-upstream] [remote] [ref] (ref omitted, HEAD, or the current branch only; -u/--set-upstream needs an explicit remote AND ref and is never combined with another flag), and &&/; chains made up only of those three, run inline instead of being delegated. Also allows ONE optional leading cd <path> (only when it realpaths to the payload cwd's own repo toplevel or a directory inside it) and optional trailing read-only segments (git log --oneline [-N], git status [--short\|-s], git show --stat [-N\|HEAD]) ONLY after a push segment. --force/-f/--force-with-lease/--force-if-includes/--mirror/--delete/-d/--all/--tags/+refspec/src:dst-to-another-branch/any other flag combined with -q stay exactly as blocked as before; git-guard.js keeps its own independent force-push/AI-credit checks.
guards.allowGcloudReads true boolean ANTIHALL_ALLOW_GCLOUD_READS command-guard narrow read-only Google Cloud access: in the MAIN THREAD ONLY, lets the cloud CLI token-printing command, read-style verbs (describe, list, get-iam-policy, read) with JSON, YAML or value output into a bounded sink or jq, and a token-authorized silent HTTP GET with an optional Bearer header to an https URL on googleapis.com or a subdomain run inline. Mutating verbs, other HTTP methods, request bodies, uploads, output-to-file flags, redirects, proxies, IP literals, @file arguments and chained commands stay blocked.
guards.allowBackgroundScratchScripts true boolean ANTIHALL_ALLOW_BACKGROUND_SCRATCH_SCRIPTS command-guard background scratch scripts: in the MAIN THREAD ONLY, a Bash call with run_in_background: true may run ONE segment <interpreter> <script file> [args…] (python3, node, sh or bash) when the file is an existing regular file inside the session scratchpad or a tmp root (os.tmpdir(), /tmp, /private/tmp; realpath-checked). No interpreter option before the file (-c/-e/…), no env prefix or wrapper, no chaining/pipes, no substitution or expansion, no stdin redirect, no write redirect outside the scratchpad/tmp. Foreground runs keep the normal rules. Each such run counts toward the main-thread work window (guards.coordinatorWorkWindowMinutes).
guards.coordinatorWorkWindowMinutes 10 number, at least 0 ANTIHALL_COORDINATOR_WORK_WINDOW_MINUTES Main thread only: successful state-changing Bash calls (WORK: state-changing git, gh mutations, Bash writes into non-notes repo files, scratch/tmp/.anti-hall script runs, other text-script runs except tracked-and-clean project scripts, package-manager/system tools and old ~/.local/bin, ~/Library or ~/.claude/plugins tools, inline -c/-e code that writes files or runs state-changing git/gh) are counted over this many minutes. In a non-git project only coordinator-writable or fresh scripts count; an old script there is not WORK. Set nudgeAt and blockAt to 0 to record only. 0 = feature off.
guards.coordinatorWorkNudgeAt 4 number, at least 0 ANTIHALL_COORDINATOR_WORK_NUDGE_AT One advisory note each time the window's WORK count reaches this. 0 = no nudge.
guards.coordinatorWorkBlockAt 7 number, at least 0 ANTIHALL_COORDINATOR_WORK_BLOCK_AT The Nth WORK Bash call within the window is blocked. Recovery commands (git am/rebase/cherry-pick/revert --abort|--quit, merge --abort, stash pop/apply) and loosely matched inline code are counted but never blocked. Skip key coordinator-work-guard. 0 = no block.
guards.coordinatorWorkMaxEntries 50 number, at least 1 ANTIHALL_COORDINATOR_WORK_MAX_ENTRIES Safety cap on stored window timestamps per session.
guards.bashEditParity true boolean ANTIHALL_BASH_EDIT_PARITY command-guard applies edit-guard's verdict to Bash writes (sed -i, perl -i, tee, cp, mv, >/>> redirects, literal python -c / node -e open-for-write paths) into repo files in the main thread. git verbs and trusted (redirect-free) project command-allow matches are never blocked by it. Also off when safety.editGuard is off or edit-guard is skipped. Both hosts (tested with Claude and Codex payload shapes).
guards.shellWriteChecks true boolean ANTIHALL_SHELL_WRITE_CHECKS api-guard and ship-it-guard also run on Bash (both hosts): the files a shell write targets (>/>> redirects, heredoc into cat/tee, echo/printf, tee, sed -i, perl -i, cp/mv, python -c open(..., 'w')) go through ship-it-guard's existence gate, and the visible text of a heredoc/echo/printf write into a .py/.js/.ts file through api-guard. Writes into the session scratchpad or a tmp root outside a repo are not gated by ship-it-guard. Unparseable forms are allowed. Each guard's own switch (guards.apiGuard, guards.shipitGate) still applies; edit-guard's Bash parity is guards.bashEditParity.
guards.reaperMatch "" string ANTIHALL_REAPER_MATCH Extra process-name pattern for the MCP session-end reaper.
guards.reaperExclude "" string ANTIHALL_REAPER_EXCLUDE Excludes matching processes from the MCP reaper.
guards.reaperCodexBroker true boolean ANTIHALL_REAPER_CODEX_BROKER companion/mcp-reaper.js: REPORT (list in the reaper log, both dry-run and real runs) abandoned openai-codex plugin app-server-broker.mjs helper processes. REPORT-ONLY — this class is NEVER killed (a 2026-09-25 safety review found its detection could not be made reliable enough to act on automatically: unquoted --cwd paths with spaces, symlinked /tmp-vs-/private/tmp cwd mismatches, and the broker's own app-server child always looking like an "owner"). It is spawned detached+unref ON PURPOSE (PPID 1 is normal for a LIVE broker, not evidence of death), so a candidate is listed only when its --cwd directory no longer exists, or no live claude/codex process (excluding the broker's own descendants) has a realpath'd cwd equal to/an ancestor of/a descendant of the realpath'd --cwd, AND it is older than guards.reaperCodexBrokerMinAgeS. Matched by an exact script-name + codex-plugin-path signature, kept fully separate so this never loosens the MCP matcher (which alone can still trigger a real kill). Only takes effect when the opt-in companion reaper is installed and running.
guards.reaperCodexBrokerMinAgeS 1800 number, at least 0 ANTIHALL_REAPER_CODEX_BROKER_MIN_AGE_S Minimum age in seconds an app-server-broker.mjs whose owner cannot be found must have before the report-only class above will list it (30 minutes by default — deliberately conservative since PPID gives no death signal for this class); an unresolvable age is always skipped, never listed.
guards.tasklistWorkThreshold 3 number, at least 1 ANTIHALL_TASKLIST_WORK_THRESHOLD Minimum work items before tasklist-guard fires.
guards.pruneCompletedTasksAfter 10 number, at least 1 ANTIHALL_PRUNE_COMPLETED_TASKS_AFTER TOKEN SAVINGS (0.117.0): once completed/cancelled tasks in the list exceed this count, task-guard emits a one-line advisory (never a block) to prune them via TaskUpdate status=deleted after recording them in the history ledger — Claude Code's own TaskCreate reminder re-prints the whole list, completed tasks included, every few turns.
guards.progressFreshMs 1800000 number, at least 0 ANTIHALL_PROGRESS_FRESH_MS Freshness window (ms) for the progress file in tasklist-guard.
guards.apiGuardThirdparty false boolean ANTIHALL_API_GUARD_THIRDPARTY Also verify installed 3rd-party package APIs, not just stdlib/builtins.
guards.modelRouting strict one of strict, advisory, off ANTIHALL_MODEL_ROUTING model-routing-guard (PreToolUse Agent/Task): strict blocks a mis-tiered spawn, advisory only warns, off disables the hook.
guards.noBlockingQuestions off one of off, advise, block ANTIHALL_NO_BLOCKING_QUESTIONS ask-guard (PreToolUse AskUserQuestion, optional): advise adds a standing-rule reminder to the question call, block refuses it unless the first question starts with DESTRUCTIVE: or CREDENTIAL:. off (default) does nothing.
guards.questionAgentsNote true boolean ANTIHALL_QUESTION_AGENTS_NOTE ask-guard (PreToolUse AskUserQuestion): when a question is asked while background agents are in flight, add one advisory line naming them and saying they may act on an option before the answer arrives (pause them or tell them to wait). Silent when no agent is running or the count cannot be proven. Never blocks; independent of guards.noBlockingQuestions.
guards.sharedTreeAgentNote true boolean ANTIHALL_SHARED_TREE_AGENT_NOTE swarm-guard (PreToolUse Agent/Task): when a write-capable subagent is spawned without isolation:"worktree" while another write-capable agent is still running in the same working tree, add one advisory sentence (two such agents can commit each other's uncommitted changes: isolate, serialize, or use separate scratch clones; in a repo whose CLAUDE.md/AGENTS.md says no worktrees: serialize or use scratch clones). Read-only agent types, isolated spawns, and unknown agent state are silent. Never blocks.
guards.mergeSidePickAdvisory true boolean ANTIHALL_MERGE_SIDE_PICK_ADVISORY merge-side-pick (PostToolUse + PreToolUse Bash, Claude and Codex): records a conflict resolved by taking one side wholesale (git checkout/restore --ours|--theirs, git merge/pull/rebase -X ours|theirs, git merge -s ours) and test runs (npm/pnpm/yarn test, node --test, pytest, go/cargo/flutter/dart test, mvn/gradle test, make test, ...) per session; a push while a side-pick has no test run after it adds one advisory (run the tests, review the discarded side). Never blocks; silent when tests ran after the side-pick or state is unknown. On Codex it shows only on builds that support PreToolUse additionalContext (rust-v0.129.0+).
guards.updateInSession true boolean ANTIHALL_UPDATE_IN_SESSION model-routing-guard blocks a subagent spawn that runs anti-hall's own update (skills/update/scripts/update.js, or run /anti-hall:update): update.js runs migrations, so it runs in the main session, which judges the result. off allows delegating it.
guards.modelRoutingDeployFloor sonnet one of sonnet, opus, off ANTIHALL_MODEL_ROUTING_DEPLOY_FLOOR model-routing-guard floor for deploy/migration/rollback/production/secret/credential-shaped spawns: such a spawn at or above the floor is never blocked, one below it (or with no explicit model) gets an advisory to use at least the floor. off restores the plain routing table.
guards.apiGuard true boolean api-guard (PreToolUse Write/Edit): block fabricated stdlib/builtin APIs in written code.
guards.speculationGuard true boolean speculation-guard (Stop): block a turn that ends on unverified hedged claims.
guards.inferenceCheck false boolean ANTIHALL_INFERENCE_CHECK speculation-guard (Stop): also block, once per reply, a confident causal claim with no hedge word ("caused by", "the root cause is", "because", "is due to", "stems from", "this means", "the culprit is", "that's why") when no tool output, observation-tool input, pasted fenced block or task notification in the transcript window mentions the stated cause. Default off: 100% precision on the 84-case synthetic corpus (tools/eval/inference-bench.js) but it flagged 3.8% of 3,276 real final replies, mostly design rationale ("X because Y"), so field precision is far below 0.9.
guards.claimLedger true boolean claim-ledger (Stop, never blocks): record claims in the last reply that nothing in the session backs.
guards.taskGuard true boolean task-guard (Stop): block stopping while tracked tasks are still open.
guards.taskGuardOwnerBlockedMarker true boolean ANTIHALL_TASK_GUARD_OWNER_BLOCKED_MARKER task-guard IDLE NEGLECT: honor an explicit owner-blocked marker (metadata.blockedOn / blockedOn === 'owner'|'user'|'human'|'external', or an "OWNER:" / "OWNER DECISION" subject prefix) as non-dispatchable, instead of requiring a fake blockedBy dependency to silence the nag. Off reverts to pre-marker behavior (only a real blockedBy id suppresses idle-neglect).
guards.dispatchDemand true boolean ANTIHALL_DISPATCH_DEMAND Per-turn "DISPATCH NOW in parallel: #id subject, …" demand (task-tracker, UserPromptSubmit) and task-guard IDLE NEGLECT count in-flight agents PER TASK from this session's transcript (an agent whose description names #id covers it; unmapped agents cover one task each; running < min(16, cores-2)). Off removes the per-turn DISPATCH NOW line and restores task-guard's legacy blanket rule (any fresh ~/.anti-hall/agents heartbeat suppresses IDLE NEGLECT). Metrics: node scripts/dispatch-report.js.
guards.idleNeglectMinPriority p1 one of p0, p1, p2, p3 ANTIHALL_IDLE_NEGLECT_MIN_PRIORITY task-guard IDLE NEGLECT urgency floor: a pending/unowned/unblocked task nags only when its priority is at or above (numerically ≤) this rank; anything below it (e.g. P2/P3 when the floor is P1, or "low"/"deferred") is non-nagging backlog. Missing/unrecognized priority is always treated as P1 (fail-open). Consistent across every rank — was previously hard-coded to skip only the literal "P2".
guards.maxParallelDispatch 0 number, at least 0 ANTIHALL_MAX_PARALLEL_DISPATCH Hard cap on concurrently-running background agents the DISPATCH NOW line / task-guard IDLE NEGLECT will demand up to. 0 (default) = the existing dynamic cap (min(16, cores-2)). Some owners run exactly ONE implementation agent per workspace at a time — setting this to 1 makes the demand ask for the next task only once nothing is running, instead of piling on parallel dispatch pressure.
guards.idleNeglectProvenOnly true boolean ANTIHALL_IDLE_NEGLECT_PROVEN_ONLY task-guard IDLE NEGLECT blocks only when a dispatchable task is uncovered under every placement of the running agents that name no task (dispatchable > unmapped agents). The per-turn DISPATCH NOW line is unchanged. false = also block on the in_progress-first estimate.
guards.idleNeglectAgentMaxAgeMin 30 number, at least 0 ANTIHALL_IDLE_NEGLECT_AGENT_MAX_AGE_MIN task-guard IDLE NEGLECT, proven count only: a running agent that names no task stops counting as cover once its newest sign of life (launch, SendMessage resume, pending teammate message, output-file write) is older than this many minutes, or when it was launched before the earliest uncovered task was created / last set pending or in_progress (it cannot be working on a task that did not exist). Unknown age or unknown task time = the agent still counts. 0 = never age out.
guards.tasklistGuard true boolean tasklist-guard (Stop): require a task list / progress file for multi-step work.
guards.tasklistNoTaskTools reduced one of reduced, full, skip ANTIHALL_TASKLIST_NO_TASK_TOOLS tasklist-guard (Stop): the nag form for a session that is positively known to lack task tools (today: a Codex session with no task-tool evidence in its transcript). reduced (default) = no TaskCreate demand, list the tasks in the reply, blocks at most once per session; full = today's TaskCreate/TaskUpdate demand; skip = no nag. A Claude session with no evidence keeps the full demand (task tools exist before they leave a trace). When not set explicitly, context.protocolLevel=full makes the default full.
guards.stopNagBudgetPerPrompt 0 number, at least 0 ANTIHALL_STOP_NAG_BUDGET Per-prompt cap on Stop blocks from task-guard and tasklist-guard (each counted separately), inside their existing session caps (5 and 3). 0 (default) = off = today's behaviour; N = at most N blocks per user prompt, keyed by the Stop payload prompt_id or the last user entry uuid (no key = not applied). speculation-guard, claim-ledger and the PreToolUse guards are not affected.
guards.scanThrottle true boolean ANTIHALL_SCAN_THROTTLE scan-throttle (PreToolUse Bash): advise running heavy repo-wide scans at background priority (nice/taskpolicy); never rewrites the command.
guards.silentAgentNudge true boolean ANTIHALL_SILENT_AGENT_NUDGE silent-agent-nudge (Stop): nudge once, advisory-only, when a background Agent launch in the transcript has no terminal notification and a stale/missing output_file (plus the ~/.anti-hall/agents/<id>.json heartbeat as an extra signal), past silentAgentNudgeMin. Never kills anything.
guards.silentAgentNudgeMin 20 number, at least 1 ANTIHALL_SILENT_AGENT_NUDGE_MIN Minutes of silence (no terminal task-notification + stale/missing output_file, or a stale heartbeat) before silent-agent-nudge fires.
guards.staleAgentStopNote true boolean ANTIHALL_STALE_AGENT_STOP_NOTE stale-agent-stop-note (PreToolUse TaskStop, never blocks): one advisory line when TaskStop names an agent that was sent a message, or resumed, after its last report and has not reported since (it may be working). Settings file + env only; no plugin option.
guards.idleAgentSweep true boolean ANTIHALL_IDLE_AGENT_SWEEP idle-agent-sweep (UserPromptSubmit, Claude + Codex, never blocks): once per user prompt, lists agents that finished but were never stopped (Claude: named teammates whose last report is an idle_notification with idleReason available/failed and no later SendMessage or TaskStop; Codex: multi_agent_v1 agents whose wait_agent result is completed/errored and that were never closed) and gives the exact TaskStop / close_agent call. Fires when guards.idleAgentSweepCount are idle or one has been idle guards.idleAgentSweepMin minutes
guards.idleAgentSweepCount 3 number, at least 1 ANTIHALL_IDLE_AGENT_SWEEP_COUNT idle-agent-sweep fires when at least this many finished agents are idle and not stopped
guards.idleAgentSweepMin 15 number, at least 1 ANTIHALL_IDLE_AGENT_SWEEP_MIN idle-agent-sweep also fires when any one finished agent has been idle at least this many minutes
guards.compactAdviceGuard true boolean compact-advice-guard (Stop): block once when the reply recommends /compact ("SAFE TO COMPACT", "good point to /compact") while context is below the auto-handover threshold minus compactAdviceMarginPct, or within compactAdviceRecentTurns turns of a compact. The threshold-fired auto-handover path stays allowed.
guards.compactAdviceRecentTurns 10 number, 0 to 100 compact-advice-guard: a compact boundary within this many turns makes a new /compact recommendation a block; 0 turns the recent-compact rule off.
guards.compactAdviceMarginPct 10 number, 0 to 50 compact-advice-guard: context-% points below autoHandover.pct at which a /compact recommendation counts as low-context.
guards.compactDeclarationGuard true boolean compact-declaration-guard (PreToolUse — opt-in in 0.116.0 pending false-positive fixes on quoted/question/negated "safe to compact" phrasing; RE-ENABLED by default in 0.117.0 now that findAdvice ignores quoted/question/negated/conditional mentions, see hooks/lib/compact-advice.js): after declaring SAFE TO COMPACT in a turn, block new work (Agent/Task spawns, Write/Edit/NotebookEdit, state-changing Bash) until the next user message or an explicit "RETRACT SAFE TO COMPACT" line. Read-only tools stay allowed.
guards.stopHookVersionDowngrade true boolean ANTIHALL_STOP_HOOK_VERSION_DOWNGRADE When installed_plugins.json (harness-owned) has re-registered a newer anti-hall version than this running session, downgrade nudge-class Stop-hook blocks (silent-agent-nudge, tasklist-guard, devswarm-parent-gate NEGLECT) to advisory (skip the block) until restart — a stale already-fixed nudge should not keep blocking. Never applied to safety guards.
guards.stopAck true boolean ANTIHALL_STOP_ACK Nudge-class Stop hooks (silent-agent-nudge, tasklist-guard) honor a per-signature session ack the agent writes to ~/.anti-hall/stop-ack/<session>.json once the user has explicitly confirmed a condition is a false positive — the same signature then stays advisory (never blocks again) for the rest of the session. Off disables the mechanism entirely (hooks block exactly as before it existed). Never applies to safety guards.

Safety Guards

Switches for the safety-critical guards (force-push / AI self-credit / heavy-command and edit delegation / runaway spawns). Normal precedence applies (env > ~/.anti-hall/settings.json > /config > default): a value in settings.json counts like any other. settings.js set to the risky value, and a reset whose fallback value is risky, need --confirmed (a human direct command, or the user saying yes after a one-line factual warning); re-arming a guard never does. Off = the guard's core check no-ops; the per-guard skip.json escape hatch is unchanged.

Setting Default Type Env What it does
safety.gitGuard true boolean ANTIHALL_GIT_GUARD git-guard: block force-push and AI self-credit in commits and gh pr/issue/release bodies.
If changed: force-pushes and AI credit lines in commits will no longer be stopped.
safety.commandGuard true boolean ANTIHALL_COMMAND_GUARD command-guard core: make the coordinator delegate heavy commands (build/test/deploy/push). Its data-safety sub-guards (DevSwarm read/send/mailbox, armed stash guard) stay on.
If changed: heavy commands (builds, tests, deploys, pushes) will run directly in the main session instead of being handed to a helper.
safety.editGuard true boolean ANTIHALL_EDIT_GUARD edit-guard core: make the coordinator delegate file edits outside its own plan/state/handover files.
If changed: edits to protected files like plugin config and secrets will no longer be stopped.
safety.swarmGuard true boolean ANTIHALL_SWARM_GUARD swarm-guard: block agent spawns past the spawn-rate cap or under critical memory pressure.
If changed: nothing will stop runaway agent spawning that can overload the machine.

Context Injections

The verify-first protocol and the other text anti-hall injects at session start, per turn, and into subagents.

Setting Default Type Env What it does
context.verifyFirstSession true boolean verify-first-full (SessionStart): inject the full verify-first protocol (also re-injected after compaction).
context.verifyFirstOrchestration true boolean verify-first-orch (SessionStart): inject the orchestration discipline for the main thread.
context.protocolLevel compact one of compact, full ANTIHALL_PROTOCOL_LEVEL Size of the verify-first and orchestration text anti-hall injects. compact (default) sends a short core with every load-bearing clause inline and points at PROTOCOL.md for the rest; full sends today's complete text on every channel, byte for byte (the one-key rollback).
context.codexOrchFullOn session one of session, spawn ANTIHALL_CODEX_ORCH_FULL_ON EXPERIMENTAL, Codex only (>= 0.129, hooks trusted). session (default) = the full orchestration rules (A-N) arrive at SessionStart, as today. spawn = SessionStart sends the compact core + compact orchestration lines and the full rules arrive once per context epoch on the first spawn_agent call (a PreToolUse additionalContext, which Codex 0.160 surfaces to the model). Needs positive Codex evidence, otherwise session; ignored under protocolLevel=full, and a DevSwarm Primary always gets the full text at SessionStart.
context.orchFullOn auto one of auto, spawn, session, off ANTIHALL_ORCH_FULL_ON When the full orchestration rules (A-N) are sent under protocolLevel=compact. auto (default) = session = inline at SessionStart next to the compact core; spawn = EXPERIMENTAL: compact lines at SessionStart and the full text once on the first Agent/Task/Workflow spawn of each context epoch (Claude Code only, needs positive platform evidence, otherwise coerced to session; unproven live, so opt-in); off = the compact lines only (also on Codex). Ignored under protocolLevel=full; a DevSwarm Primary always gets the full text at SessionStart.
context.verifyFirstTurn true boolean verify-first (UserPromptSubmit): the short per-turn verify-first nudge.
context.verifyFirstSubagent true boolean verify-first-subagent (SubagentStart): inject the protocol into every subagent.
context.taskTracker true boolean task-tracker (UserPromptSubmit): the task-list discipline directive and per-turn reminder.
context.handoverResume true boolean handover-resume (SessionStart): point a fresh or compacted session at the newest handover.
context.defectNudge true boolean defect-nudge (SessionStart): the once-a-day note about the defect channel.
context.dedupeWindowMin 20 number, at least 0 ANTIHALL_DEDUPE_WINDOW_MIN Fallback per-session suppression window (minutes) for repeated UserPromptSubmit injection blocks (LIMIT CONSERVATION, TASK-LIST, DEVSWARM COMMS OVERRIDE, DEVSWARM WORKSPACES) when a burst of queued prompts is delivered together and the transcript cannot confirm the earlier copy was already read — used only as the last-resort guard; content that changed always re-emits. 0 disables emit-dedupe entirely (same as guards.emitDedupe=false).
context.roleGuard true boolean ANTIHALL_ROLE_GUARD engine-role-guard (PreToolUse Bash) and the ah-engine command line: refuse an engine verb the caller's role may not run (roles.matrix: owner-level verbs are main-session only, a workspace child acts on itself only).
context.roleNote true boolean ANTIHALL_ROLE_NOTE engine-role-note (SessionStart, SubagentStart): tell the session its role, the engine verbs it may use and where the guide is (the anti-hall:engine skill).
context.injectGate true boolean ANTIHALL_INJECT_GATE Token cuts, master switch (engine dispatcher): the hooks that re-send the same context every turn (limit-conserve-inject, task-tracker, the DevSwarm comms-override line, swarm-guard's shared-tree advisory) are passed on only when the model does not already hold it; off hands every hook's output through unchanged. The state is per session and per agent, bounded in the daemon, cleared by SessionStart (compaction), and fails open.
context.injectGateLimit true boolean ANTIHALL_INJECT_GATE_LIMIT Token cut 1: the limit-conservation directive is injected when the usage band or reset window changes, else as a short keepalive every context.injectGateLimitEvery turns (its reset time jitters by milliseconds, which defeated the Node dedupe).
context.injectGateLimitEvery 10 number, at least 1 ANTIHALL_INJECT_GATE_LIMIT_EVERY Turns between keepalives of an unchanged limit-conservation directive.
context.injectGateTask true boolean ANTIHALL_INJECT_GATE_TASK Token cut 2: task-tracker's long directive always passes; its short reminder passes every context.injectGateTaskEvery turns, its freshness note when it changed.
context.injectGateTaskEvery 10 number, at least 1 ANTIHALL_INJECT_GATE_TASK_EVERY Turns between short task-tracker reminders and unchanged freshness notes.
context.injectGateComms true boolean ANTIHALL_INJECT_GATE_COMMS Token cut 3: the DevSwarm comms-override line and the workspace-title instruction are injected once per session, when changed, and as a keepalive every context.injectGateCommsEvery turns.
context.injectGateCommsEvery 30 number, at least 1 ANTIHALL_INJECT_GATE_COMMS_EVERY Turns between keepalives of the unchanged comms-override line.
context.injectGateSwarm true boolean ANTIHALL_INJECT_GATE_SWARM Token cut 4: swarm-guard's shared-tree advisory is injected when new or changed, and again only after context.injectGateSwarmEvery turns.
context.injectGateSwarmEvery 20 number, at least 1 ANTIHALL_INJECT_GATE_SWARM_EVERY Turns between repeats of an unchanged shared-tree advisory.

Maintenance

Background housekeeping hooks: self-repair, pruning, snapshots, logs, and the session-end MCP sweep.

Setting Default Type Env What it does
maintenance.repairOnReload true boolean ANTIHALL_REPAIR_ON_RELOAD repair-on-reload (SessionStart/UserPromptSubmit): re-apply safe doctor repairs after a plugin update.
maintenance.progressPrune true boolean progress-prune (SessionStart): archive stale per-session progress files into the history ledger.
maintenance.precompactSnapshot true boolean precompact-snapshot (PreCompact): write a mechanical continuation snapshot before compaction.
maintenance.taskLifecycleLog true boolean task-lifecycle-log (TaskCreated/TaskCompleted): append task events to the per-session history ledger.
maintenance.sessionEndReaper true boolean ANTIHALL_SESSION_END_REAPER session-end-mcp-reaper (SessionEnd): kill orphaned MCP-server processes this session left behind.

Agent tracker

The engine-side agent tracker: follows every agent, raises hung / looping / token-waste / drift / stale-heartbeat / no-wake-path signals, and reminds. It never stops an agent.

Setting Default Type Env What it does
agents.tracker true boolean ANTIHALL_AGENT_TRACKER agent tracker (engine job agent_tick): track agents and raise signals; off, a tick does nothing.
agents.reminders true boolean ANTIHALL_AGENT_REMINDERS agent-reminders (UserPromptSubmit, PostToolUse): deliver the tracker's queued reminders to the agent that owns them; off, signals are recorded but nothing is queued.
agents.ownerNotify false boolean ANTIHALL_AGENT_OWNER_NOTIFY agent tracker owner notices: also append hung / looping / token-waste advisories to the owner notices file.

Version Alerts

Update-available nudges for anti-hall, Claude CLI, and DevSwarm.

Setting Default Type Env What it does
versionAlerts.antiHall true boolean ANTIHALL_VERSION_ALERT Alert when a newer anti-hall version is available.
versionAlerts.claudeCli true boolean ANTIHALL_CLAUDE_CLI_VERSION_ALERT Alert when a newer Claude CLI version is available.
versionAlerts.devswarm true boolean ANTIHALL_DEVSWARM_VERSION_ALERT Alert when a newer DevSwarm/hivecontrol version is available.

Updates / Maintenance

/anti-hall:update and its background sweep.

Setting Default Type Env What it does
updates.quiet false boolean ANTIHALL_UPDATE_QUIET Suppress update output (for scripted capture).
updates.reconcileBudgetMs 60000 number, at least 0 ANTIHALL_RECONCILE_BUDGET_MS Time budget (ms) for the reconcile step during update; 0 = unlimited.
updates.postpullBudgetMs 90000 number, at least 0 ANTIHALL_UPDATE_POSTPULL_BUDGET_MS Time budget (ms) for the post-pull update sweep; 0 = unlimited.
updates.sweepBudgetMs 20000 number, at least 0 ANTIHALL_UPDATE_SWEEP_BUDGET_MS Overall time budget (ms) for the update sweep.
updates.allowCachePrune true boolean ANTIHALL_ALLOW_CACHE_PRUNE Enables the opt-in doctor --prune-cache verb (never automatic: not run by update.js, the supervisor, a cron, SessionStart or any hook). Without --confirmed it only lists the old ~/.claude/plugins/cache/anti-hall/anti-hall/<semver>/ dirs it would remove and their total size; --confirmed removes them and logs each removal. Always keeps the newest 3, the installPath registered in installed_plugins.json, every version a live process runs from, the running version, and anything unparseable; symlinks and paths outside that root are refused. false disables the verb.

Limit Conservation

Auto-downshift behavior as usage approaches plan limits.

Setting Default Type Env What it does
limitConserve.mode auto one of auto, on, off ANTIHALL_LIMIT_CONSERVE Force conservation mode on/off, or auto-detect from the OMC usage cache.
limitConserve.threshold 85 number, 1 to 99 ANTIHALL_LIMIT_THRESHOLD Usage percent that triggers conservation mode.
limitConserve.accountCheck true boolean ANTIHALL_LIMIT_ACCOUNT_CHECK Guard against stale usage-cache readings after an account switch.

Jev (semantic decision engine)

Opt-in Jev "System One" classifier for triage/decisions.

Setting Default Type Env What it does
jev.enabled false boolean ANTIHALL_JEV Enable Jev (ANTIHALL_JEV=0 always force-disables regardless of this).
jev.transport vercel one of vercel, typesafe Vercel AI Gateway passthrough (default) or a direct TypeSafe API call.
jev.fallbackTransport none one of none, vercel, typesafe Automatic backup transport: when the primary vendor times out, errors (5xx) or is out of balance (402/429), retry ONCE on this one, inside the same time budget. none = off; equal to jev.transport = off. Needs its own vendor-bound key (jev_vercel_api_key / jev_typesafe_api_key, or the key file of that vendor with jev.allowLegacyKeyRead). Text then reaches the second vendor.
jev.judgeModel haiku string ANTIHALL_JUDGE_MODEL Model used for speculation-judge / jev-triage LLM calls.
jev.judgeBackend api one of api, cli, auto ANTIHALL_JUDGE_BACKEND How speculation-judge (jev.semanticJudge) reaches the model. api (default) = Anthropic API with the anthropic_api_key plugin option; cli = the local claude -p CLI on your own Claude login, no API key (isolated: no tools, no MCP, no settings files, all hooks disabled; about 5-6 s per turn end, measured); auto = api when a key is visible, else cli. Fail-open in every mode.
jev.speculationBackend haiku one of haiku, jev, cascade ANTIHALL_JEV_SPECULATION_BACKEND Which backend answers the semantic speculation question when jev.semanticJudge is on. haiku (default) = the judge asks the model (jev.judgeModel through jev.judgeBackend), except while Jev's own speculation integration is on; jev = the judge never asks the model and speculation-guard's Jev path is the only semantic check; cascade = as jev, and the Jev-first cascade (jevCascade.speculation) is switched on. Answered by the engine (engine/defaults/judge.toml); the Node fallback keeps the haiku behaviour.
jev.triageBackend jev one of jev, haiku, cascade ANTIHALL_JEV_TRIAGE_BACKEND Which backend labels mesh messages in ah-engine jev triage. jev (default) = Jev first, the Anthropic API fills a missing label when a key is visible (the hooks/lib/jev-triage-worker.js behaviour); haiku = the model alone, through jev.judgeBackend (the local claude -p CLI about 3-4 s per message, so raise the triage budget to use it).
jev.cascade true boolean ANTIHALL_JEV_CASCADE Global kill switch of the Jev-first cascade. false = no Jev answer is ever re-judged by the model, whatever the per-integration jevCascade switches say.
jev.cascadeShowJevAnswer true boolean ANTIHALL_JEV_CASCADE_SHOW_JEV_ANSWER Whether the model that re-judges an unsure Jev answer is shown Jev's answer and confidence (true) or only the evidence (false), so anchoring can be A/B tested.
jev.semanticJudge false boolean ANTIHALL_SEMANTIC_JUDGE Enable the semantic speculation-judge hook (off = hook no-ops).
jev.allowLegacyKeyRead false boolean SAFETY, home-settings only (no env / project override). Opt-in: let anti-hall read the Jev key from AI_GATEWAY_API_KEY / TYPESAFE_API_KEY env vars and the key file (jev.keyFile or the default path) — the only way background tools (CLI, finding-dedup, jev-report) and Codex (no plugin options) see a key. Default off: only the jev_api_key plugin option is used.
If changed: anti-hall would read the Jev gateway key (AI_GATEWAY_API_KEY / TYPESAFE_API_KEY env vars and the key file) from this machine instead of only the jev_api_key plugin option.
jev.genericKeyVendor vercel one of vercel, typesafe SAFETY, home-settings only (no env / plugin option / legacy file). The ONE vendor the legacy generic jev_api_key and jev.keyFile are bound to; they are never sent to any other vendor, whatever jev.transport or jev.fallbackTransport say. Vendor-named keys (jev_vercel_api_key / jev_typesafe_api_key) need no binding. Change it only with jev-setup.js bind-generic-key --vendor <v>.
If changed: the generic jev_api_key plugin option and jev.keyFile would be sent to the other vendor (they carry no vendor name, so anti-hall sends them only to this one).
jev.keyFile "" string Credential key-file path (default depends on transport).
jev.timeoutMs 1500 number, 1 to 3000 Per-call timeout (ms), capped at 3000.
jev.confidenceThreshold 0.85 number, 0 to 1 Minimum confidence for a Jev answer to be trusted by callers.
jev.triage true boolean Message-triage labeling once Jev is enabled.
jev.triageUrgentThreshold 0.9 number, 0 to 1 Confidence threshold for the urgent triage label.
jev.budget.mode unlimited one of unlimited, watch Jev spend: no limit, or warn when over budget (never auto-disables).
jev.budget.usdPerDay (none) number optional: daily USD spend threshold, used only when budget.mode=watch.
jev.budget.usdPerWeek (none) number optional: weekly USD spend threshold, used only when budget.mode=watch.
jev.weeklyNotice true boolean Once-a-week SessionStart scorecard notice naming one integration worth promoting or turning off (Jev enabled only).
jev.audit.snippets false boolean ANTIHALL_JEV_AUDIT_SNIPPETS Store a redacted ~200-char snippet for decisions Jev changed or would change in shadow mode (off by default: privacy).
jev.logRotatedFiles 10 number, 1 to 100 Rotated generations kept for jev-assist.ndjson (2MB each) and jev-triage.ndjson (1MB each): .1 .. .N. 10 keeps roughly 20 days of decision rows at ~1MB/day.
jev.rollupRetentionDays 0 number, 0 to 3650 Days of daily rollups (~/.anti-hall/logs/jev-daily/<day>.json) to keep. 0 (default) keeps every rollup; only an explicit N > 0 removes rollups older than N days.
jev.budget.minCreditUsd (none) number optional: warn (once a day, budget.mode=watch only) when the gateway credit balance drops below this USD amount.
jev.prices (none) object computed: per-model USD price table {model: {inPerMTok, outPerMTok}} (or a "default" entry), used only when the gateway reports tokens but no cost. File-only (no env, no CLI set) — edit ~/.anti-hall/settings.json directly.
jev.priceUsdPerMInput 0.042 number, at least 0 ANTIHALL_JEV_PRICE_USD_PER_M_INPUT USD per 1M input tokens for the Jev judge call, used to compute costUsd when the gateway reports tokens but no cost and prices has no matching entry. Default is Jev's own published rate (verified: typesafe.ai, vercel.com/ai-gateway/models/jev, openrouter.ai/typesafe).
jev.priceUsdPerMOutput 0 number, at least 0 ANTIHALL_JEV_PRICE_USD_PER_M_OUTPUT USD per 1M output tokens for the Jev judge call (default 0 — output is free on the verified rate).
jev.dispatchTierNoWorkspaceRepos "" comma-separated list ANTIHALL_JEV_DISPATCH_TIER_NO_WORKSPACE_REPOS Repos (directory basenames or absolute paths; "*" = all) where the Jev dispatchTier recommendation never says workspace (shown as subagent, logged as repo-override).
jev.dispatchTierDetectNoWorkspaces true boolean ANTIHALL_JEV_DISPATCH_TIER_DETECT_NO_WORKSPACES Also treat a repo as no-workspace when its CLAUDE.md / AGENTS.md says "no workspaces for real work".
jev.reviewAfterDays 7 number, 1 to 365 ANTIHALL_JEV_REVIEW_AFTER_DAYS Minimum days an integration must have sat in shadow mode before its shadow numbers are DUE for owner review (also the re-review cadence once reviewed).
jev.reviewMinDecisions 30 number, at least 0 ANTIHALL_JEV_REVIEW_MIN_DECISIONS Minimum decisions logged for a shadow integration before its review is due — avoids nagging about a barely-used integration with too little data to judge.
jev.reviewReminder true boolean ANTIHALL_JEV_REVIEW_REMINDER Durable "time to review the Jev shadow numbers" SessionStart/doctor nudge (on by default — owner opt-out only).
jev.recommendNotice true boolean ANTIHALL_JEV_RECOMMEND_NOTICE Bold "Recommended: enable Jev" notice at SessionStart (once on first install, then at most every 30 days) and in doctor, shown only while Jev is NOT enabled. Set false to silence it.
jev.recommendNoticeHeadless false boolean ANTIHALL_JEV_NOTICE_HEADLESS Allow the "Recommended: enable Jev" notice in non-interactive runs (claude -p / SDK, detected by CLAUDE_CODE_ENTRYPOINT=sdk-*). Default false: nobody reads it there, and a headless run no longer uses up the notice's once-per-30-days slot. JEV REVIEW DUE is not affected; Codex is unchanged. When not set explicitly, context.protocolLevel=full makes the default true.

Jev cascade

Per-integration switch of the Jev-first cascade: when Jev answers below the integration's escalation threshold (engine/defaults/judge.toml, default = its act threshold) the answer is re-judged by the model, shown Jev's answer unless jev.cascadeShowJevAnswer is off. A hook-blocking decision never waits: Jev's answer applies now and the re-judged one from the next turn. Off by default = today's behaviour.

Setting Default Type Env What it does
jevCascade.speculation off one of on, off ANTIHALL_JEV_CASCADE_SPECULATION Re-judge a speculation Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.triage off one of on, off ANTIHALL_JEV_CASCADE_TRIAGE Re-judge a triage Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.newRequest off one of on, off ANTIHALL_JEV_CASCADE_NEW_REQUEST Re-judge a newRequest Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.claimLedger off one of on, off ANTIHALL_JEV_CASCADE_CLAIM_LEDGER Re-judge a claimLedger Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.outputVerifyGuard off one of on, off ANTIHALL_JEV_CASCADE_OUTPUT_VERIFY_GUARD Re-judge a outputVerifyGuard Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.gitGuardSelfCredit off one of on, off ANTIHALL_JEV_CASCADE_GIT_GUARD_SELF_CREDIT Re-judge a gitGuardSelfCredit Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.modelRouting off one of on, off ANTIHALL_JEV_CASCADE_MODEL_ROUTING Re-judge a modelRouting Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.tasklistTrivial off one of on, off ANTIHALL_JEV_CASCADE_TASKLIST_TRIVIAL Re-judge a tasklistTrivial Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.codexNudgeSubstantial off one of on, off ANTIHALL_JEV_CASCADE_CODEX_NUDGE_SUBSTANTIAL Re-judge a codexNudgeSubstantial Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.mergeGateHedge off one of on, off ANTIHALL_JEV_CASCADE_MERGE_GATE_HEDGE Re-judge a mergeGateHedge Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.parentGateQuestion off one of on, off ANTIHALL_JEV_CASCADE_PARENT_GATE_QUESTION Re-judge a parentGateQuestion Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.supervisorBlockerLabel off one of on, off ANTIHALL_JEV_CASCADE_SUPERVISOR_BLOCKER_LABEL Re-judge a supervisorBlockerLabel Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.findingDedup off one of on, off ANTIHALL_JEV_CASCADE_FINDING_DEDUP Re-judge a findingDedup Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.postHandoverGate off one of on, off ANTIHALL_JEV_CASCADE_POST_HANDOVER_GATE Re-judge a postHandoverGate Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.speculationFramed off one of on, off ANTIHALL_JEV_CASCADE_SPECULATION_FRAMED Re-judge a speculationFramed Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.dispatchTier off one of on, off ANTIHALL_JEV_CASCADE_DISPATCH_TIER Re-judge a dispatchTier Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.devswarmOnBrief off one of on, off ANTIHALL_JEV_CASCADE_DEVSWARM_ON_BRIEF Re-judge a devswarmOnBrief Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.devswarmExtraSanctioned off one of on, off ANTIHALL_JEV_CASCADE_DEVSWARM_EXTRA_SANCTIONED Re-judge a devswarmExtraSanctioned Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.devswarmWaitKind off one of on, off ANTIHALL_JEV_CASCADE_DEVSWARM_WAIT_KIND Re-judge a devswarmWaitKind Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.devswarmLoop off one of on, off ANTIHALL_JEV_CASCADE_DEVSWARM_LOOP Re-judge a devswarmLoop Jev answer the model when Jev is unsure (see the section note). on | off.
jevCascade.devswarmStepMap off one of on, off ANTIHALL_JEV_CASCADE_DEVSWARM_STEP_MAP Re-judge a devswarmStepMap Jev answer the model when Jev is unsure (see the section note). on | off.

Jev integration

Per-integration trust mode for every Jev-assisted decision point (v0.108.4 — each of the 13 integrations gets its own row/setting; postHandoverGate added in 0.109.0; the five devswarm* supervision integrations in 0.117.0; legacy home: jev.json "integrations.<id>" and, pre-0.108.4, settings.json jev["integrations.<id>"]). on = Jev may change the outcome (bounded by its own trust rule below), shadow = consulted + logged only, off = not consulted.

Setting Default Type Env What it does
jevIntegrations.speculation on one of on, shadow, off Is this claim unsupported speculation (add-block trust: Jev may only turn a non-block baseline into a block).
jevIntegrations.triage on one of on, shadow, off Mesh message urgency/kind labeling (advisory: its own triage client, not the add-block/relax-block trust model).
jevIntegrations.newRequest shadow one of on, shadow, off Classify a prompt as new-request/follow-up/correction/question (advisory trust).
jevIntegrations.claimLedger shadow one of on, shadow, off Is a flagged claim genuinely unsupported by evidence (relax-block trust: Jev may only turn a blocking baseline into a non-block).
jevIntegrations.outputVerifyGuard shadow one of on, shadow, off Does this test-runner output actually indicate a pass (advisory trust).
jevIntegrations.gitGuardSelfCredit shadow one of on, shadow, off Does this commit/PR message contain paraphrased AI self-credit (add-block trust; never relaxes git-guard).
jevIntegrations.modelRouting shadow one of on, shadow, off Is this agent-spawn task actually mechanical (relax-block trust).
jevIntegrations.tasklistTrivial shadow one of on, shadow, off tasklist-guard: is this session a genuinely non-trivial, multi-part effort (relax-block trust; asked synchronously, 1.5 s cap, fail-open).
jevIntegrations.codexNudgeSubstantial shadow one of on, shadow, off codex-nudge: are these file edits genuinely substantial, not just formatting (relax-block trust; asked synchronously, 1.5 s cap, fail-open).
jevIntegrations.mergeGateHedge shadow one of on, shadow, off Does this text hedge on merge-readiness (relax-block trust; askDetached fire-and-forget in shadow).
jevIntegrations.parentGateQuestion shadow one of on, shadow, off Is this unread child message really a question awaiting a reply (add-block trust; cache-only, zero network).
jevIntegrations.supervisorBlockerLabel shadow one of on, shadow, off Is a stale child waiting-on-parent or genuinely wedged (advisory trust; cache-only, zero network).
jevIntegrations.findingDedup on one of on, shadow, off Do two deadly-loop TRIO findings describe the same underlying issue, for advisory duplicate-grouping (advisory trust); default on — 65/65 correct at confidence >=0.85 on a 30-day, 3-project offline benchmark (see CHANGELOG 0.108.4).
jevIntegrations.postHandoverGate off one of on, shadow, off Does this new request fit in the remaining post-handover context budget (advisory trust; askDetached fire-and-forget, zero latency). Default off: an offline benchmark (n=299) found park-recall 17.6% vs 28.8% for the agent's own size judgment plus the measured budget backstop, no gain over the baseline.
jevIntegrations.speculationFramed shadow one of on, shadow, off When a deterministic speculation-guard hedge hit sits under a FRAMED heading/line prefix (Expected/Plan/"Should be <verb>:"/"Should still"/Unverified/"(unverified)"/"not yet measured"), is it a stated expectation/plan or an unverified claim presented as fact (relax-block trust: Jev may only turn the framed hit's block into a non-block; an unframed hedge never consults Jev and always blocks).
jevIntegrations.dispatchTier on one of on, shadow, off Recommend how each dispatchable task should be dispatched — workspace / workflow / subagent — on the DISPATCH NOW line (advisory trust; never blocks or forces; the Primary makes the final call). on = annotate "#7 … → subagent (0.91)"; shadow = log only; asked via askDetached only when a task's text changes (PostToolUse TaskCreate/TaskUpdate). Outcomes logged: actual dispatch followed/overridden, subagent one-lane vs escalated, workflow fan-out.
jevIntegrations.devswarmOnBrief on one of on, shadow, off DevSwarm supervision: is a child's off-scope work actually off its brief (relax-block over the off-scope straying warning; asked detached from the supervisor sweep only when off-scope fires, answer read from the cache next sweep; input: current step, scope, last 3 summaries, last 5 commit subjects, off-scope files, <=1.5k chars scrubbed).
jevIntegrations.devswarmExtraSanctioned on one of on, shadow, off DevSwarm supervision, recommendation (as devswarmOnBrief): did the user ask for this off-scope work (annotates the off-scope warning, threshold >=0.9; an explicit scope add always wins; input: the child's last user prompts, secrets scrubbed, plus the off-scope files, <=1k chars).
jevIntegrations.devswarmWaitKind on one of on, shadow, off DevSwarm supervision, recommendation (as devswarmOnBrief): is an idle/stalled child stuck or legitimately waiting on CI, the owner or a peer (annotates the idle/stall warning; input: step, last summary, signal reasons, <=800 chars).
jevIntegrations.devswarmLoop on one of on, shadow, off DevSwarm supervision, recommendation (as devswarmOnBrief): is a busy child looping on its step (annotates a burn/stall warning, or adds its own advisory loop warning when none fired; threshold >=0.9; asked when the step is older than 2x devswarm.stepStallMin or a burn warning fired; input: step, time on step, tokens since the step moved, summaries, commit churn, <=1.2k chars).
jevIntegrations.devswarmStepMap on one of on, shadow, off DevSwarm supervision, recommendation: which plan step a heartbeat summary without --step describes (threshold 0.8; when on it fills an inferred ~N step that shows only while the child never reported a step itself).

DevSwarm

Multi-workspace mesh orchestration, liveness, and supervisor tuning. Every consumer takes an explicit env parameter (for testability); settings.js routes these through getWithEnv() so a home derived from that SAME env is used, never os.homedir().

Setting Default Type Env What it does
devswarm.hivecontrol "" string ANTIHALL_DEVSWARM_HIVECONTROL Explicit path to the hivecontrol CLI binary (default: PATH lookup — no single default value; empty means "look it up").
devswarm.supervisorMode auto one of auto, on, off ANTIHALL_DEVSWARM_SUPERVISOR Force the DevSwarm supervisor context on/off, or auto-detect.
devswarm.requiredGates done,merged,tests_passed comma-separated list ANTIHALL_DEVSWARM_REQUIRED_GATES Merge gates required for DevSwarm tasks.
devswarm.inboxCmd "" string ANTIHALL_DEVSWARM_INBOX_CMD Consumer-configured command to read pending mesh messages (no built-in default).
devswarm.heldPartitions "" comma-separated list ANTIHALL_DEVSWARM_HELD_PARTITIONS Owner-held mesh partition ids (comma-separated). A held partition is exempt from the per-turn "ORPHANED MESH" warning and from reap-orphans; it still appears in diagnose/doctor as held by owner.
devswarm.childGateStrict true boolean ANTIHALL_DEVSWARM_CHILD_GATE_STRICT Strict child-gate enforcement.
devswarm.parentGateCap 3 number, 2 to 5 ANTIHALL_DEVSWARM_PARENT_GATE_CAP Caps the parent-gate wait/child count, clamped to [2,5].
devswarm.parentGateNeglectMinUnread 0 number, at least 0 ANTIHALL_DEVSWARM_PARENT_GATE_NEGLECT_MIN_UNREAD Minimum real-unread count a genuinely NOT-busy child needs before the parent Stop gate hard-blocks on it; 0 = any real unread blocks (pre-existing sensitivity, unchanged default). A BUSY child (fresh real-work transcript, see parentGateBusyFreshMin) gets an advisory line instead, until its oldest unread passes parentGateBusyMaxAgeMin. A child waiting on its own question/plan approval always blocks.
devswarm.parentGateBusyFreshMin 5 number, at least 1 ANTIHALL_DEVSWARM_PARENT_GATE_BUSY_FRESH_MIN Minutes a child's transcript may be quiet and still count as busy for the parent Stop gate. Busy needs positive evidence: a transcript written within this window whose latest turn is real work (not a mailbox ping, not waiting). A live pid or a fresh heartbeat alone never counts. An unresolved tool call on a transcript quiet longer than this is treated as waiting (permission prompt or hung tool).
devswarm.parentGateBusyMaxAgeMin 60 number, at least 1 ANTIHALL_DEVSWARM_PARENT_GATE_BUSY_MAX_AGE_MIN Age cap (minutes) on the busy advisory: once a busy child's oldest unread message is older than this, the parent Stop gate blocks anyway ("busy but hasn't read mail in Xm"). An unknown message age never qualifies for the advisory.
devswarm.parentGateNeglectGraceMin 1 number, at least 1 ANTIHALL_DEVSWARM_PARENT_GATE_NEGLECT_GRACE_MIN Grace window (minutes) for a plain unread backlog on the parent Stop gate: an unread message younger than this never counts as neglect by itself, independent of whether the child is separately provably busy — a Primary that just sent a child a message should not be hard-blocked seconds later, before the child has had a turn to read it. Never applies to a store-only (mesh-direct send, or dead/foreign-descriptor) row, and never suppresses an unanswered child question, an escalation, or unread older than this window. Default kept at 1 (not higher) so it never overlaps the 2-minute-old backlog this file's own busy/idle regressions use as their baseline "still neglect" fixture.
devswarm.activeFloorPct 50 number, 0 to 100 ANTIHALL_DEVSWARM_ACTIVE_FLOOR_PCT Min percent of active workspaces kept in the archived cache (0 disables the floor).
devswarm.archivedCacheMaxAgeMs (none) number, at least 0 ANTIHALL_DEVSWARM_ARCHIVED_CACHE_MAX_AGE_MS computed: no fixed default — 2x the reconcile sweep’s own resolved cooldown (itself env/default-derived), not a literal constant.
devswarm.archivedGraceMs 600000 number, at least 0 ANTIHALL_DEVSWARM_ARCHIVED_GRACE_MS Grace period (ms) before a workspace is considered archived.
devswarm.cooldownSec 600 number, at least 0 ANTIHALL_DEVSWARM_COOLDOWN_SEC Supervisor cooldown (sec) between recovery actions.
devswarm.idleSec 900 number, at least 60 ANTIHALL_DEVSWARM_IDLE_SEC Supervisor idle threshold (sec).
devswarm.dormantMs 1800000 number ANTIHALL_DEVSWARM_DORMANT_MS Dormant-workspace threshold (ms).
devswarm.drainTtlMs 600000 number, at least 0 ANTIHALL_DEVSWARM_DRAIN_TTL_MS TTL (ms) for the drain marker.
devswarm.graceSec 5 number, 1 to 60 ANTIHALL_DEVSWARM_GRACE_SEC Grace window (sec) before recovery in devswarm-recover.
devswarm.maxRecoveries 3 number, 1 to 20 ANTIHALL_DEVSWARM_MAX_RECOVERIES Max auto-recovery attempts.
devswarm.intervalSec 90 number, 60 to 120 ANTIHALL_DEVSWARM_INTERVAL Sweep interval (sec) used at supervisor install time, clamped [60,120].
devswarm.migrateMarkRead false boolean ANTIHALL_DEVSWARM_MIGRATE_MARK_READ Mark migrated messages as read during state migration.
devswarm.monitorTimeoutSec 30 number, at least 0 ANTIHALL_DEVSWARM_MONITOR_TIMEOUT_SEC Bounded cadence (sec) for monitor timeout in devswarm-ingest.
devswarm.monitorNoOkFailMin 10 number ANTIHALL_DEVSWARM_MONITOR_NO_OK_FAIL_MIN Minutes without a successful monitor poll (since daemon start, or since the last success) before ingest health reads FAILING; inside the window a fresh daemon reads "starting up".
devswarm.nudgeCooldownSec 120 number, at least 0 ANTIHALL_DEVSWARM_NUDGE_COOLDOWN_SEC Cooldown (sec) between supervisor nudges.
devswarm.nudgeMaxAttempts 2 number, 1 to 20 ANTIHALL_DEVSWARM_NUDGE_MAX_ATTEMPTS Max nudge attempts before escalation.
devswarm.nudgeWindowSec 180 number, at least 1 ANTIHALL_DEVSWARM_NUDGE_WINDOW_SEC Window (sec) for counting nudge attempts.
devswarm.postSpawnGraceSec 120 number, 0 to 1800 ANTIHALL_DEVSWARM_POST_SPAWN_GRACE_SEC Grace period (sec) right after spawning a child workspace, clamped [0,1800].
devswarm.reapedRetentionDays 30 number ANTIHALL_DEVSWARM_REAPED_RETENTION_DAYS Retention window (days) for reaped-workspace logs.
devswarm.receiptWindowMs 300000 number, at least 0 ANTIHALL_DEVSWARM_RECEIPT_WINDOW_MS Window (ms) for parent-reply receipt tracking.
devswarm.archiveRequestRenagHours 24 number, at least 1 ANTIHALL_DEVSWARM_ARCHIVE_REQUEST_RENAG_HOURS Hours a pending archive-request suppresses the ARCHIVE-READY re-nudge and the CHILD NOT DRAINING nag for that child before re-nagging anyway.
devswarm.reconcileSweep auto one of auto, off ANTIHALL_DEVSWARM_RECONCILE_SWEEP Enable/disable the periodic reconcile sweep in the supervisor.
devswarm.reconcileSweepSec 900 number, at least 300 ANTIHALL_DEVSWARM_RECONCILE_SWEEP_SEC Interval (sec) for the reconcile sweep, floor 300s.
devswarm.sweepTailMode node one of node, engine ANTIHALL_DEVSWARM_SWEEP_TAIL_MODE Who decides the DevSwarm sweep tail (archived registry rows, twin descriptors): node = the scheduled Node functions (default); engine = the engine decides each step only after Node's own function, run on a scratch mirror, agrees with it.
devswarm.rowStaleMs 86400000 number, at least 0 ANTIHALL_DEVSWARM_ROW_STALE_MS Staleness threshold (ms) for workspace row selection.
devswarm.sendReceiptRetentionDays 7 number ANTIHALL_DEVSWARM_SEND_RECEIPT_RETENTION_DAYS Retention window (days) for send-receipt records.
devswarm.summaryRetentionDays 30 number, at least 0 ANTIHALL_DEVSWARM_SUMMARY_RETENTION_DAYS Retention window (days) for summary records.
devswarm.wakeCron 7,37 * * * * string ANTIHALL_DEVSWARM_WAKE_CRON Wake-poll cron schedule override (treated as untrusted input).
devswarm.rearmOnTickOnly true boolean ANTIHALL_DEVSWARM_REARM_ON_TICK_ONLY TOKEN SAVINGS (0.117.0): re-arm a lapsed Monitor wake-watch ONLY from the cron tick's own watcherArmed:false check, never inline on the Monitor tool's own final/expired event (reply in <=1 line there instead) — collapses two overlapping ~30-minute re-arm triggers into one. false restores the pre-0.117.0 wording (re-arm inline on expiry too). Metric: ~/.anti-hall/devswarm/rearm-cues.jsonl records each cue by trigger (tick vs expiry).
devswarm.cronMissingWarnMin 60 number ANTIHALL_DEVSWARM_CRON_MISSING_WARN_MIN Minutes without a fresh inbox-tick marker (cron not running — e.g. after a DevSwarm crash/session restore/Claude restart) before the Stop gate warns once, capped, to CronList/CronCreate the wake cron again.
devswarm.wakeWatchPollMs 2000 number, 250 to 60000 ANTIHALL_DEVSWARM_WAKE_WATCH_POLL_MS Poll interval (ms) for the wake-watch loop, clamped [250,60000].
devswarm.wakeWatchIdleSkip true boolean ANTIHALL_DEVSWARM_WAKE_WATCH_IDLE_SKIP TOKEN SAVINGS (#39): a Primary with 0 LIVE (non-archived) child workspaces gains nothing from an armed wake-watch Monitor — nothing will ever message it. When on and the caller is a Primary with 0 live children, inbox tick reports watcherArmed idle-skip (not false) so the cron prompt's "re-arm if watcherArmed false" rule does not fire, and devswarm-wake-watch.js, if started anyway, prints one line and exits 0 without arming. A live child (even one Monitor lapse away from false) is unchanged; archived-only, held (devswarm.heldPartitions) and archive-ignored children also count as 0 live. The cron fallback is never affected. Metric: ~/.anti-hall/devswarm/rearm-cues.jsonl records each idle-skip (trigger 'idle-skip'), surfaced by doctor.
devswarm.dispatchTierText true boolean ANTIHALL_DEVSWARM_DISPATCH_TIER_TEXT The DevSwarm PRIMARY dispatch-tier text ("the workspace is your top fan-out tier ...") that task-tracker, verify-first and verify-first-orch inject. Off removes it everywhere; it is also never injected in a repo whose CLAUDE.md/AGENTS.md forbids workspaces for real work (jev.dispatchTierNoWorkspaceRepos / dispatchTierDetectNoWorkspaces). Governs only this injected text; the separate devswarm.inlineWorkNudge has its own switch and is not affected.
devswarm.inlineWorkNudge true boolean ANTIHALL_DEVSWARM_INLINE_WORK_NUDGE Advisory, DevSwarm PRIMARY only: once per session, when pending actionable tasks exist, the Primary has PROVEN zero live child workspaces, and its main thread has made more than devswarm.inlineWorkNudgeThreshold Edit/Write/NotebookEdit calls, one note says workspace-scale work belongs in a child workspace. Silent when liveness cannot be determined, in a child workspace, and in a repo that forbids workspaces. Rides the edit-guard PreToolUse hook (so it is inactive while safety.editGuard is off or edit-guard is skipped). Never blocks. Independent of devswarm.dispatchTierText (turning that text off does not silence this nudge).
devswarm.inlineWorkNudgeThreshold 5 number, at least 1 ANTIHALL_DEVSWARM_INLINE_WORK_NUDGE_THRESHOLD Main-thread Edit/Write/NotebookEdit calls a Primary may make before devswarm.inlineWorkNudge fires (the nudge fires on the call after this many).
devswarm.tickRosterEvery 0 number, at least 0 ANTIHALL_DEVSWARM_TICK_ROSTER_EVERY Every Nth inbox tick --quiet on a Primary appends the compact roster table after the unchanged first line, but only when roster data proves at least one live child and unread is 0 and known. 0 (default) = never. The JSON form of tick (no --quiet, or --json) is never changed.
devswarm.childGateRetentionDays 14 number ANTIHALL_DEVSWARM_CHILD_GATE_RETENTION_DAYS Days a per-session child-gate state file is kept before the housekeeping/doctor sweep removes it.
devswarm.housekeepingSweep auto one of auto, off ANTIHALL_DEVSWARM_HOUSEKEEPING_SWEEP Supervisor disk-hygiene sweep (reaped logs, child-gate state); only "off" disables it.
devswarm.housekeepingSweepSec 3600 number, at least 300 ANTIHALL_DEVSWARM_HOUSEKEEPING_SWEEP_SEC Seconds between housekeeping sweeps, floor 300.
devswarm.supervisorLogRotateBytes 10485760 number ANTIHALL_DEVSWARM_SUPERVISOR_LOG_ROTATE_BYTES Size at which the supervisor rotates its own log.
devswarm.inboxGraceSec 120 number, at least 0 ANTIHALL_DEVSWARM_INBOX_GRACE_SEC Grace window (sec) before a child's fresh unread is flagged, unless it heartbeats first; 0 = no grace.
devswarm.stableLauncher true boolean ANTIHALL_DEVSWARM_STABLE_LAUNCHER Point injected DevSwarm directive text (mailbox wake cron, Monitor re-arm, comms override, drain nudge) at a version-independent launcher under ~/.anti-hall/bin/ instead of the current hook's own version-pinned plugin-cache path, so crons/Monitors/handovers survive an anti-hall update without a manual recreate. false reverts to the raw versioned path.
devswarm.supervisorSweepBudgetMs 20000 number, at least 0 ANTIHALL_SUPERVISOR_SWEEP_BUDGET_MS Time budget (ms) for one supervisor sweep pass.
devswarm.supervisorBlockerLabelReaskSec 21600 number, at least 60 ANTIHALL_DEVSWARM_SUPERVISOR_BLOCKER_LABEL_REASK_SEC Seconds a supervisorBlockerLabel ask/log is suppressed while its input (childId+kind+ts) is unchanged, before a periodic re-ask fires anyway. Also the per-input re-ask window of the five devswarm* supervision Jev integrations (0.117.0).
devswarm.autoArchive.mode on one of on, dry-run, off ANTIHALL_DEVSWARM_AUTO_ARCHIVE_MODE Auto-archive finished workspaces (needs DevSwarm ≥ 2.5.3).
devswarm.autoArchive.idleMin 30 number, at least 5 ANTIHALL_DEVSWARM_AUTO_ARCHIVE_IDLE_MIN Minutes idle before a finished workspace is eligible for auto-archive.
devswarm.autoArchive.maxPerSweep 3 number, 1 to 20 ANTIHALL_DEVSWARM_AUTO_ARCHIVE_MAX_PER_SWEEP Max workspaces auto-archived in one sweep.
devswarm.autoArchive.ignorePings true boolean ANTIHALL_DEVSWARM_AUTO_ARCHIVE_IGNORE_PINGS Idle timer ignores a finished workspace's own mailbox-wake/heartbeat/status turns; real work (an AI turn, a tool call, a new message, a commit) still resets it. Off = any activity resets it.
devswarm.retention.days 30 number, at least 0 ANTIHALL_DEVSWARM_RETENTION_DAYS Days of message bodies kept before archive+prune; 0 = retention off.
devswarm.retention.maxStoreMB 100 number, at least 0 ANTIHALL_DEVSWARM_RETENTION_MAX_STORE_MB Store size limit (MB): above it, oldest bodies are pruned regardless of age; 0 = no limit.
devswarm.retention.keepPerPartition 200 number, at least 0 ANTIHALL_DEVSWARM_RETENTION_KEEP_PER_PARTITION Newest messages per partition that are never pruned (age or size).
devswarm.retention.archive true boolean ANTIHALL_DEVSWARM_RETENTION_ARCHIVE Write pruned bodies to the gzip archive first (restorable via devswarm.js retention restore).
devswarm.retention.archiveMaxMB 0 number, at least 0 ANTIHALL_DEVSWARM_RETENTION_ARCHIVE_MAX_MB Archive size cap (MB); 0 (default) = never evict; above a set cap the oldest archive months are dropped. doctor warns past 500 MB.
devswarm.parentGate true boolean devswarm-parent-gate (Stop): make a Primary attend to a child with unread mail or a stale verdict before stopping.
devswarm.childGate true boolean devswarm-child-gate (Stop): make a child workspace heartbeat/report to its parent before going idle.
devswarm.parentInbox true boolean devswarm-parent-inbox (UserPromptSubmit): inject the workspace roster and unread child mail into a Primary.
devswarm.childTurn true boolean devswarm-child-turn (UserPromptSubmit): inject a child workspace's pending mail each turn.
devswarm.childRole true boolean devswarm-child-role (SessionStart): inject the mesh-only messaging directive into Primary and child sessions.
devswarm.childDrain true boolean devswarm-child-drain (PostToolUse Bash): re-surface a child's unread mail mid-task (throttled).
devswarm.parentReplyTracker true boolean devswarm-parent-reply-tracker (PostToolUse Bash): record the Primary's direct replies so the parent gate can tell read from answered.
devswarm.commsGuard true boolean devswarm-comms-guard (PreToolUse SendMessage): block SendMessage to a DevSwarm workspace (mesh messaging only).
devswarm.inboxReadGuard true boolean inbox-read-guard (PreToolUse Read): block raw Read-tool reads of the DevSwarm inbox/store (use the wrapper).
devswarm.wakeWatch true boolean devswarm-wake-watch monitor: wake an idle session the moment new mesh mail lands (the cron fallback stays).
devswarm.appSync true boolean ANTIHALL_DEVSWARM_APP_SYNC Supervisor app-DB sync: apply the DevSwarm app database (archive state, names, drift) every tick.
devswarm.screenshotSync true boolean devswarm.js sync-ui: reconcile a transcribed sidebar screenshot against the app DB.
devswarm.spawnFromOrigin true boolean devswarm.js spawn: fetch origin first and fast-forward the local default branch so a child never starts from stale tooling; refuses when it is behind and cannot be updated (unless --from-local).
devswarm.spawnStrictFlagValues true boolean ANTIHALL_DEVSWARM_SPAWN_STRICT_FLAG_VALUES devswarm.js spawn: refuse when a value-taking create option (-s/--source, -a/--agent, -t/--title, -p/--prompt) has no value or is handed what looks like the next option (e.g. -t -p "brief" would make "-p" the title), naming the flag.
devswarm.sendMultiRecipient true boolean ANTIHALL_DEVSWARM_SEND_MULTI_RECIPIENT devswarm.js send: --to <id1>,<id2> or a repeated --to sends the same body to each (deduped) recipient, attempts every one even after a failure, and exits non-zero if any failed. false restores the old parsing (last --to wins).
devswarm.spawnFetchTtlSec 300 number, at least 0 ANTIHALL_DEVSWARM_SPAWN_FETCH_TTL_SEC devswarm.js spawn: skip the origin fetch when the remote-tracking ref was already updated within this many seconds (0 = always fetch).
devswarm.spawnCreateTimeoutMs 180000 number, at least 1000 ANTIHALL_DEVSWARM_SPAWN_CREATE_TIMEOUT_MS Timeout (ms) for the hivecontrol workspace create call spawn makes; on timeout only our own child process is killed.
devswarm.planTracking true boolean ANTIHALL_DEVSWARM_PLAN_TRACKING Step-plan tracking: spawn turns a numbered list in -p into the child's plan file, the roster and workspace table show "3/7 done · doing #4 · 42m · progress 18m ago", and the child is reminded to report heartbeat --step N. Off: no plan is written or shown (the explicit plan / heartbeat --step verbs still work).
devswarm.planRequired false boolean ANTIHALL_DEVSWARM_PLAN_REQUIRED Ask every child without a step plan to write one (devswarm.js plan set) on each turn. Never refuses a spawn — numbered step lists stay encouraged, not enforced.
devswarm.stepStallMin 30 number, at least 5 ANTIHALL_DEVSWARM_STEP_STALL_MIN Minutes a busy child with a step plan may go without step progress (or since its last correction) before the supervisor raises a stall straying warning; also the window in which step progress after a correction counts as "correction worked".
devswarm.strayWarnMax 2 number, 0 to 10 ANTIHALL_DEVSWARM_STRAY_WARN_MAX Most straying warnings per signal (stall / off-scope / idle / jev-*) per plan step; each is shown once as an advisory DEVSWARM STRAYING line. 0 turns straying warnings off.
devswarm.burnTokensWarn 2000000 number, at least 0 ANTIHALL_DEVSWARM_BURN_TOKENS_WARN Token-burn straying warning: a child with a step plan that spends more than this many weighted tokens (input + output + cache writes + burnCacheReadPct% x cache reads, read incrementally from its own session transcript) since its last step progress gets one burn warning ("used 2.1M tokens since step 3 last moved"). Default 2M: with the 10% cache-read weight, one model call at a 150k-token cached context costs ~17k weighted tokens, so 2M is roughly 100+ calls with no step moving. 0 turns the burn signal off.
devswarm.burnCacheReadPct 10 number, 0 to 100 ANTIHALL_DEVSWARM_BURN_CACHE_READ_PCT Weight of cache-read tokens in the token-burn figure, in percent (0-100). Default 10 mirrors prompt-cache pricing, where a cache read bills at a tenth of the base input rate; 100 counts every cached token in full.
devswarm.respawnGraceMin 20 number, at least 0 ANTIHALL_DEVSWARM_RESPAWN_GRACE_MIN Minutes after a correct warning (the plan's warned_at) before the Primary may run devswarm.js respawn <id>. Respawn is never automatic and refuses without a warning.
devswarm.respawnWipWaitSec 120 number, at least 0 ANTIHALL_DEVSWARM_RESPAWN_WIP_WAIT_SEC Seconds respawn waits for the child to commit and push its WIP after being asked; whatever is still dirty or unpushed is then parked on a new pushed park/<branch>-<ts> branch.
devswarm.archivedChildStop true boolean ANTIHALL_DEVSWARM_ARCHIVED_CHILD_STOP An archived child workspace can never re-register its descriptor and is told once to save a handover and stop, instead of being nagged to heartbeat forever. false reverts to pre-fix behaviour (descriptor rewritten every turn, normal heartbeat-report forcing).
devswarm.maintainerNotice.post false boolean ANTIHALL_DEVSWARM_MAINTAINER_NOTICE_POST SAFETY (confirm to change — see settings.js set/reset). Allow devswarm.js notice --post from THIS checkout; also requires the checkout's own plugins/anti-hall/.claude-plugin/plugin.json to have name "anti-hall" (a mistake guard, not authentication — see companion/lib/devswarm-maintainer-notice.js). Off refuses every post regardless of the checkout.
If changed: this checkout would be allowed to post a maintainer notice that every project's Primary sees — the checkout-name check is a mistake guard, not authentication, so only turn this on in the anti-hall dev checkout.
devswarm.maintainerNotice.show true boolean Show unseen maintainer notices to a Primary (devswarm-parent-inbox.js). Off suppresses the surface only — posting/listing via the CLI is unaffected.
devswarm.startupSampling true boolean ANTIHALL_DEVSWARM_STARTUP_SAMPLING Supervisor reconcile sweep: opportunistically probe hivecontrol workspace info <id> (read-only, bounded, 3s timeout) for stale/not-draining rows and log a non-null startup field or a terminalId change to ~/.anti-hall/logs/devswarm-startup-samples.ndjson — pure data capture toward designing paused-workspace detection.
devswarm.pausedProbeMax 8 number, 1 to 20 ANTIHALL_DEVSWARM_PAUSED_PROBE_MAX Max hivecontrol workspace info probes per supervisor sweep tick for the startup-state sampler above.

Statusline

The rich statusline (version chip, phase bar, account segment).

Setting Default Type Env What it does
statusline.base "" string ANTIHALL_STATUSLINE_BASE Shell command run as the line-1 base in consolidated statusline mode.
statusline.noEmail false boolean ANTIHALL_STATUSLINE_NO_EMAIL Suppress the email segment in the statusline.

Codex Nudge

Hand-off nudge suggesting Codex for review/diagnosis.

Setting Default Type Env What it does
codexNudge.enabled true boolean ANTIHALL_CODEX_NUDGE Enable the Codex hand-off nudge hook.
codexNudge.min 3 number, at least 1 ANTIHALL_CODEX_NUDGE_MIN Minimum substantial code-file edits before the nudge fires.

Process watch

Leftover processes of ended Claude sessions (report by default; kill is a per-class opt-in), and agents silent past a threshold. Warns only, never stops an agent. Needs the ah-engine.

Setting Default Type Env What it does
procwatch.enabled true boolean ANTIHALL_PROCWATCH procwatch (scheduled sweep + SessionStart/UserPromptSubmit/PreToolUse advisory): look for processes a Claude session left behind (marked by the environment Claude Code sets, owner session gone, class pattern, minimum age) and for agents with no output. Never touches a live session, an unmarked process or a system process.
procwatch.devServerMode report one of off, report, kill ANTIHALL_PROCWATCH_DEV_SERVER dev_server class of the process watch: dev servers and watchers an agent started. off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.testRunnerMode report one of off, report, kill ANTIHALL_PROCWATCH_TEST_RUNNER test_runner class of the process watch: test runners and their children. off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.buildDaemonMode report one of off, report, kill ANTIHALL_PROCWATCH_BUILD_DAEMON build_daemon class of the process watch: build tool daemons. off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.mcpServerMode report one of off, report, kill ANTIHALL_PROCWATCH_MCP_SERVER mcp_server class of the process watch: MCP servers of ended sessions (the SessionEnd reaper, maintenance.sessionEndReaper, is separate). off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.shellTaskMode report one of off, report, kill ANTIHALL_PROCWATCH_SHELL_TASK shell_task class of the process watch: background shell commands of ended sessions. off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.otherMode report one of off, report, kill ANTIHALL_PROCWATCH_OTHER other (catch-all) class of the process watch: any other process a Claude session started and left behind, oldest first. off | report (list only, the default) | kill (stop them one pid at a time after a grace period).
procwatch.stuckMinutes 20 number, at least 1 ANTIHALL_PROCWATCH_STUCK_MINUTES Minutes without output after which a background agent of this session is named in a stuck-agent advisory (UserPromptSubmit; warn only, once per cooldown). Reuses the silent-agent-nudge detection.

Resource watch

Soft warning when processes of a live Claude session use too much CPU or memory, or the system swaps. Never kills or throttles by default.

Setting Default Type Env What it does
resourceWatch.enabled true boolean ANTIHALL_RESOURCE_WATCH resource-watch: sample the processes under live Claude sessions each sweep and warn the session (advisory only).
resourceWatch.cpuPercent 90 number, at least 1 ANTIHALL_RESOURCE_WATCH_CPU Per-core CPU percent (100 = one core busy; a multi-threaded process can exceed it) every sample of the window must reach.
resourceWatch.cpuWindowSeconds 120 number, at least 10 ANTIHALL_RESOURCE_WATCH_CPU_WINDOW Seconds the CPU reading must hold.
resourceWatch.memoryMb 4096 number, at least 16 ANTIHALL_RESOURCE_WATCH_MEM Memory in MB (resident set on Linux, physical footprint on macOS) at which a process of a live session is named.
resourceWatch.swapMb 8192 number, at least 0 ANTIHALL_RESOURCE_WATCH_SWAP System swap in use, MB, that triggers a warning; 0 = off.
resourceWatch.pressurePercent 25 number, at least 0 ANTIHALL_RESOURCE_WATCH_PSI Linux memory pressure (PSI some avg10, percent) that triggers a warning; 0 = off.
resourceWatch.macPressureLevel 2 number, at least 0 ANTIHALL_RESOURCE_WATCH_MAC_PRESSURE macOS memory pressure level (2 warn, 4 critical) that triggers a warning; 0 = off.
resourceWatch.cooldownSeconds 900 number, at least 0 ANTIHALL_RESOURCE_WATCH_COOLDOWN Least seconds before the same process (or system warning) is named again.
resourceWatch.renice false boolean ANTIHALL_RESOURCE_WATCH_RENICE Opt-in: lower the priority (nice 10) of a process the watch warned about, once. Off by default; the watch never kills.

Disk watch

Soft warning when the volumes Claude sessions write to run low on free space. Never deletes anything.

Setting Default Type Env What it does
diskWatch.enabled true boolean ANTIHALL_DISK_WATCH disk-watch: warn (SessionStart/UserPromptSubmit) when the project, HOME or temp volume is below the warn floor, and before heavy commands (PreToolUse) at the critical floor; names the biggest build/cache directories as a suggestion.
diskWatch.warnGb 20 number, at least 0 ANTIHALL_DISK_WATCH_WARN_GB Warn below this many GB free (0 = not used).
diskWatch.warnPercent 10 number, at least 0 ANTIHALL_DISK_WATCH_WARN_PCT Warn below this percent free (0 = not used).
diskWatch.criticalGb 5 number, at least 0 ANTIHALL_DISK_WATCH_CRITICAL_GB Critical below this many GB free (0 = not used).
diskWatch.criticalPercent 3 number, at least 0 ANTIHALL_DISK_WATCH_CRITICAL_PCT Critical below this percent free (0 = not used).
diskWatch.cooldownSeconds 1800 number, at least 0 ANTIHALL_DISK_WATCH_COOLDOWN Least seconds before the same level is warned about again (a worse level always is).
diskWatch.blockAtCritical false boolean ANTIHALL_DISK_WATCH_BLOCK Opt-in: at the critical level, block heavy commands (builds, clones, worktree add) instead of only warning. Off by default.

Engine

The optional ah-engine binary (native hook answers).

Setting Default Type Env What it does
engine.bootstrap true boolean AH_ENGINE_BOOTSTRAP Download and install the sha256-pinned ah-engine binary from the GitHub Release on SessionStart (once per pinned release). Off: nothing is downloaded and the Node hooks answer everything. AH_ENGINE_BOOTSTRAP=0/1 overrides this key.
engine.autoUpdate off one of off, stable, dev AH_ENGINE_AUTO_UPDATE Update the engine binary on its own, at most once a day: off (default), stable (latest ah-engine-v* release) or dev (latest dev pre-release, which also syncs the plugin files of a live kit). Runs hooks/ah-update.sh --auto from the engine scheduler; verifies SHA256SUMS and the GitHub attestation; the previous binary is kept (ah-update.sh --rollback). One-shot: sh hooks/ah-update.sh --from FILE | --channel stable|dev | --rollback. URLs and timeouts: engine/ah-update.toml.

Defects

The two-way defect-reporting channel.

Setting Default Type Env What it does
defects.defaultProj "" string ANTIHALL_DEFECT_PROJ Default project tag used when filing an anti-hall defect (max 64 chars).

Engine defaults

The Rust engine reads its values from plugins/anti-hall/engine/defaults/, 7512 entries in 67 files (limits, intervals, message texts, patterns). The table lists the ones you can override with an environment variable.

Value Default Env File What it does
schedule.agent_tick_ms 60000 ms AH_ENGINE_AGENT_TICK_MS agent_tracker.toml Interval of the agent_tick job; 0 turns the tracker's ticks off.
config.watch_ms 500 ms AH_ENGINE_CONFIG_WATCH_MS config.toml How often the daemon checks the config files for a change.
config.debounce_ms 300 ms AH_ENGINE_CONFIG_DEBOUNCE_MS config.toml A change must stay unchanged this long before it is loaded, so a half-written or rapidly edited file is read once.
dispatch.in_process 0 AH_ENGINE_DISPATCH_IN_PROCESS dispatch.toml Run the built-in checks inside the hook client (1) instead of asking the daemon (0, the default).
dispatch.max_timeout_s 86400 s AH_ENGINE_DISPATCH_MAX_TIMEOUT_S dispatch.toml An upper bound on any Node hook's timeout, whatever its hooks.json entry says (the default is above every real timeout, so it changes nothing; tests lower it to exercise a hook that never exits).
daemon.workers 4 AH_ENGINE_WORKERS engine.toml Worker threads evaluating requests.
daemon.queue 16 AH_ENGINE_QUEUE engine.toml Connections that may wait for a worker; beyond this the daemon answers BUSY and the client falls back.
daemon.max_request 1048576 bytes AH_ENGINE_MAX_REQUEST engine.toml Largest request the daemon reads; the client sends nothing larger (it falls back instead).
daemon.read_ms 1000 ms AH_ENGINE_READ_MS engine.toml Total time a client has to deliver its request.
daemon.write_ms 1000 ms AH_ENGINE_WRITE_MS engine.toml Time allowed to write a reply.
daemon.eval_budget_us 200000 us AH_ENGINE_EVAL_BUDGET_US engine.toml Per-request thread CPU budget for rule evaluation; 0 turns the budget off.
daemon.mem_mb 512 MB AH_ENGINE_MEM_MB engine.toml Data-segment limit applied with setrlimit; 0 = none. It is a ceiling against runaway allocation, not a budget (the RSS cap is the budget), and Linux enforces it on thread stacks, so it must exceed daemon.workers times git.stack_mb plus headroom or a check thread cannot start. macOS accepts the call but does not enforce it.
daemon.rss_cap_kb 131072 KB AH_ENGINE_RSS_CAP_KB engine.toml Resident-set cap; above it the daemon drains and exits cleanly and the next call starts a fresh one; 0 = none. Set from measurement, not guessed (DECISIONS.md 1.111, 2026-10-09): on the real-payload replay (2,113 recorded hook calls, unpaced, isolated home) the engine with 16 scripted checks sits at 69 MB after one pass and 78 MB after three (jemalloc, aarch64-apple-darwin), and at 102 MB after one pass with the system allocator (the x86_64-apple-darwin and musl builds, measured as a system-allocator build on this Mac); the live heap is 45-52 MB. The engine before the scripted checks (live4) measured 62 and 68 MB on the same replay, so the previous 64 MB cap (set from a synthetic soak with a 16-18 MB live heap) sat inside the steady state of both: the daemon restarted 4 times in 600 s and the crash-loop breaker sent every hook to Node. The cap sits above the larger figure with room for the slow growth both builds show on repeated passes (about 1.5 MB per 1,000 calls), so only real growth trips it.
daemon.rss_check_ms 10000 ms AH_ENGINE_RSS_CHECK_MS engine.toml How often the watchdog samples resident memory.
daemon.stuck_ms 8000 ms AH_ENGINE_STUCK_MS engine.toml A worker busy on one request for longer than this trips a drain and exit.
daemon.stall_ms 5000 ms AH_ENGINE_STALL_MS engine.toml An accept loop silent for longer than this trips a drain and exit.
daemon.watchdog_tick_ms 250 ms AH_ENGINE_WATCHDOG_TICK_MS engine.toml How often the watchdog thread wakes to look at heartbeats.
daemon.nice 5 AH_ENGINE_NICE engine.toml nice increment applied to the daemon process.
daemon.session_rps 50 AH_ENGINE_SESSION_RPS engine.toml Sustained requests per second allowed per session; 0 = unlimited.
daemon.session_burst 200 AH_ENGINE_SESSION_BURST engine.toml Token-bucket burst per session.
daemon.project_rps 100 AH_ENGINE_PROJECT_RPS engine.toml Sustained requests per second allowed per project; 0 = unlimited.
daemon.project_burst 400 AH_ENGINE_PROJECT_BURST engine.toml Token-bucket burst per project.
daemon.idle_exit_s 0 s AH_ENGINE_IDLE_EXIT_S engine.toml Seconds without any request after which the daemon exits (the next hook call starts a fresh one, and the scheduler catches up its missed jobs); 0 keeps it resident. 0 by default: the daemon is always resident so the scheduler and mailbox keep running after every session closes (D7). A daemon whose state dir, lock file or executable is gone still exits on its own (daemon.orphan_check_ms).
client.deadline_ms 2000 ms AH_ENGINE_DEADLINE_MS engine.toml Overall deadline for one engine exchange (connect, write, read); a hard watchdog thread enforces it.
client.breaker_n 5 AH_ENGINE_BREAKER_N engine.toml Engine failures within the window that open the breaker (the client then skips the engine).
client.breaker_window_s 60 s AH_ENGINE_BREAKER_WINDOW_S engine.toml Window in which breaker failures are counted.
client.breaker_cooldown_s 60 s AH_ENGINE_BREAKER_COOLDOWN_S engine.toml How long the breaker stays open once tripped.
client.crash_n 4 AH_ENGINE_CRASH_N engine.toml Daemon deaths within the window that stop respawning.
client.crash_window_s 600 s AH_ENGINE_CRASH_WINDOW_S engine.toml Window in which daemon deaths are counted.
client.crash_cooldown_s 1800 s AH_ENGINE_CRASH_COOLDOWN_S engine.toml How long respawning stays stopped after a crash loop.
client.fallback_ms 8000 ms AH_ENGINE_FALLBACK_MS engine.toml The Node fallback hook must finish, and its stdout and stderr must reach EOF, within this long. A hook still running at the deadline is killed (then plain allow, since it is unavailable); one that finished with output still unread is an error outcome, never an empty stdout.
schedule.gh_poll_ms 20000 ms AH_ENGINE_GH_POLL_MS github_rt.toml Interval of the gh_poll job, the tick that decides which repos are due (the cadences below decide how often a repo is really polled); 0 turns GitHub realtime off.
schedule.jev_sweep_ms 900000 ms AH_ENGINE_JEV_SWEEP_MS jev_sweep.toml Interval of the jev_sweep job; 0 turns it off.
ops.shadow_rate_statusline 50 AH_ENGINE_SHADOW_RATE_STATUSLINE operator.toml How many runs in a thousand of the statusline command are also run by the Node version in the background and compared (0 turns the shadow off). The engine result is always the real one.
ops.shadow_rate_settings 1000 AH_ENGINE_SHADOW_RATE_SETTINGS operator.toml How many runs in a thousand of the settings command are also run by the Node version in the background and compared (0 turns the shadow off). The engine result is always the real one.
ops.shadow_rate_defect 1000 AH_ENGINE_SHADOW_RATE_DEFECT operator.toml How many runs in a thousand of the defect command are also run by the Node version in the background and compared (0 turns the shadow off). The engine result is always the real one.
realtime.poll_ms 750 ms AH_ENGINE_RT_POLL_MS realtime.toml How often a polled directory is listed and its watched files stat'ed, in milliseconds. Only directories that cannot use OS events are polled (9p, drvfs, NFS, SMB, FUSE, a directory that does not exist yet, backend = poll), so this is the detection latency of those: at most this plus debounce_ms. Polling costs CPU in proportion to the files watched divided by this interval.
realtime.debounce_ms 100 ms AH_ENGINE_RT_DEBOUNCE_MS realtime.toml A changed file is reported once it has been quiet this long, so a burst of writes becomes one report.
realtime.max_delay_ms 1000 ms AH_ENGINE_RT_MAX_DELAY_MS realtime.toml A file that keeps changing is still reported at least this often (the ceiling on debounce_ms), so a busy source is never starved.
schedule.tick_ms 1000 ms AH_ENGINE_TICK_MS schedules.toml Longest the ticker sleeps between checks; it wakes earlier when a job is due sooner or schedule run asks.
schedule.maintain_ms 86400000 ms AH_ENGINE_MAINTAIN_MS schedules.toml Interval of the maintain job (D26); 0 turns it off.
schedule.handovers_ms 600000 ms AH_ENGINE_HANDOVERS_MS schedules.toml Interval of the handovers job; 0 turns it off.
schedule.backup_ms 0 ms AH_ENGINE_BACKUP_MS schedules.toml Interval of the backup job (D27); 0 (the default) turns it off.
schedule.telemetry_rollup_ms 86400000 ms AH_ENGINE_TELEMETRY_ROLLUP_MS schedules.toml Interval of the telemetry rollup job (D78); 0 turns it off.
schedule.procwatch_ms 30000 ms AH_ENGINE_PROCWATCH_MS schedules.toml Interval of the process watch job (resource sampling; orphan scans run every procwatch.scan_every_s); 0 turns it off.
script.enabled 1 AH_ENGINE_SCRIPT script.toml 1: a check whose script exists runs the script instead of its compiled port; 0: the compiled port always runs (the parity baseline).
script.time_limit_ms 50 ms AH_ENGINE_SCRIPT_TIME_MS script.toml CPU-time limit of one script call (the interpreter thread's own CPU time, see script.wall_limit_factor for the wall-clock backstop); past it the interpreter is interrupted and the call defers to Node (never a silent allow).
script.exec_timeout_scale 1 AH_ENGINE_SCRIPT_EXEC_SCALE script.toml Multiplier on the time every ah.exec run and every process listing a script asks for may take (the limit a script asks for, and the longest one, are both multiplied). 1 in production; a test build on a loaded machine raises it so a slow child process is not read as a failure.
session.gitignore_probe_ms 1000 ms AH_ENGINE_GITIGNORE_PROBE_MS session.toml The longest the engine waits for the gitignore probe before it hands the hook to Node. Node waits 3000 ms, but the client gives up on the engine after client.deadline_ms, so a longer wait here could answer after the client has already left; a test keeps the shipped value below that deadline.
ops.shadow_rate_phase 1000 AH_ENGINE_SHADOW_RATE_PHASE slcfg.toml How many runs in a thousand of the phase command are also run by the Node version in the background and compared (0 turns the shadow off). The engine result is always the real one.
ops.shadow_rate_install 1000 AH_ENGINE_SHADOW_RATE_INSTALL slcfg.toml How many runs in a thousand of install-statusline are also run by the Node installer in the background, on a scratch copy of the settings (never a second real write), and compared (0 turns the shadow off).
ops.shadow_rate_uninstall 1000 AH_ENGINE_SHADOW_RATE_UNINSTALL slcfg.toml How many runs in a thousand of uninstall-statusline are also run by the Node uninstaller in the background, on a scratch copy of the settings, and compared (0 turns the shadow off).
storage.fullfsync 0 AH_ENGINE_FULLFSYNC storage.toml 1 makes SQLite use F_FULLFSYNC on macOS, which also survives power loss at a large cost in commit rate (D73: 479 against 43k commits per second measured); 0 keeps the plain fsync. Off until metrics decide.
storage.write_queue 1024 AH_ENGINE_WRITE_QUEUE storage.toml Writes that may wait for the writer thread; beyond this a write is refused as busy (the client retries, then spools).
storage.group_commit_ms 0 ms AH_ENGINE_GROUP_COMMIT_MS storage.toml Group-commit window: after taking a write, the writer waits up to this long for more before committing them together (D23); 0 commits at once with whatever is already queued, which still groups writes that arrive during a commit.
storage.ack_timeout_ms 1000 ms AH_ENGINE_ACK_TIMEOUT_MS storage.toml How long a request waits for its write to commit before it is answered with an error (the client then retries or spools; the write id makes a late commit harmless); kept below client.ctl_timeout_ms so the client hears the error.
tier.budget_kb 2048 KB AH_ENGINE_TIER_BUDGET_KB storage.toml Memory budget of the active key-value items; past it the least recently used item is dropped from memory (SQLite keeps it).
spool.retries 4 AH_ENGINE_SPOOL_RETRIES storage.toml Retries of a project write before it is spooled (the first attempt is not counted).
spool.backoff_ms 20 ms AH_ENGINE_SPOOL_BACKOFF_MS storage.toml First retry delay; each retry doubles it, up to backoff_max_ms, with random jitter of up to half the delay.
spool.max_bytes 16777216 bytes AH_ENGINE_SPOOL_MAX_BYTES storage.toml Largest spool; a write that would grow it past this is refused instead of spooled, so the client learns it was not kept.
spool.drain_ms 1000 ms AH_ENGINE_SPOOL_DRAIN_MS storage.toml Interval of the scheduled spool drain job (it also drains on start and before each project write).
telemetry.max_events 5000 AH_ENGINE_MAX_EVENTS telemetry.toml Most impact events kept in memory (oldest dropped first); counts per kind are kept exactly in separate counters.
telemetry.snapshot_ms 60000 ms AH_ENGINE_SNAPSHOT_MS telemetry.toml Interval of the scheduled metrics snapshot job, which keeps the counters in hot.db and their rollups in archive.db (D51); the daemon also keeps one when it exits.
telemetry.flush_ms 10000 ms AH_ENGINE_TELEMETRY_FLUSH_MS telemetry.toml How often the recorder's counters and events are stored in hot.db, and at shutdown. A kill -9 loses at most this much (the data recorded since the last flush).
telemetry.health_snapshot_ms 60000 ms AH_ENGINE_HEALTH_SNAPSHOT_MS telemetry.toml How often the daemon records a daemon health snapshot event (resident set, its cap, restarts, degraded flag, queue and worker load, saturation). Events are kept for retention_days and capped by max_event_rows.