Neo environment variables
This file is generated-from / must-match src/runtime/env-settings.ts's ENV_SETTINGS table. Every NEO_* var Neo reads has one row below, transcribed from that registry (name, default, parse convention, description, where it applies). A drift-guard test (tests/runtime/env-settings.test.ts) asserts every ENV_SETTINGS entry name appears in this file, so the two cannot silently diverge — if you add or rename a var in the registry, update this table in the same change.
Non-NEO_* env vars (provider API keys, TELEGRAM_BOT_TOKEN, SystemRoot, PATH, …) are out of scope for this table — see docs/channels.md for channel gateways and provider docs for keys.
Parse conventions (kind column)
Chip 15 centralizes reads but deliberately does not unify parse semantics — each var keeps its exact historical behavior. The kind column names the convention; see src/runtime/env-settings.ts's parse-helper docstrings (offSentinel, strictOne, truthy, positiveIntMs, strictPositiveInt, nonNegativeIntMs, cron, multiSentinelFalsy, bypassKillswitchTruthy) for the exact rules of each:
| kind | meaning |
|---|---|
flag-off-sentinel | enabled unless the value is the literal string 'off' |
flag-on-sentinel | enabled iff the value is the literal string 'on' |
flag-one | enabled iff the value is the literal string '1' |
flag-one-or-true | enabled iff '1' or 'true' (exact strings, no trim/case-fold) |
flag-truthy | trim + lowercase, 1/true/yes[/on] enable — variant differs per site, see description |
multi-sentinel-falsy | unset ⇒ enabled; else trim + lowercase, disabled iff off/false/0/'' |
int-positive | positive integer with a fallback (parseInt or Number() — see description) |
int-nonneg | non-negative integer; invalid/unset falls through to the next precedence level |
string | raw (possibly trimmed) string passthrough |
path | filesystem path override |
cron | 5-field cron expression, validated; invalid falls back to the default |
custom | bespoke semantics — see the description |
Daemon-scoped variables
Daemon lifecycle, budget, gates, job timeouts, and Tier-0 cron overrides are listed in daemon.md as well as the table below — daemon.md adds operational narrative (what each gate protects, failure modes); this table is the flat, authoritative inventory.
Full inventory
| Variable | Kind | Default | Description | Original site |
|---|---|---|---|---|
NEO_MEMORY_DREAMING | flag-off-sentinel | on | Soul capability: weekly dream/consolidation pass | runtime/capability-flags.ts:64 |
NEO_REFLECTION | flag-off-sentinel | on | Soul capability: cross-session reflection pass | runtime/capability-flags.ts:64 |
NEO_ATTUNEMENT | flag-off-sentinel | on | Soul capability: emotional-attunement heuristics | runtime/capability-flags.ts:64 |
NEO_HEARTBEAT | flag-off-sentinel | on | Soul capability: proactive heartbeat job | runtime/capability-flags.ts:64 |
NEO_SIGNALS | flag-off-sentinel | on | Soul capability: Gmail/Calendar signal poller | runtime/capability-flags.ts:64 |
NEO_HOME | path | ~/.neo | Root ~/.neo directory override (test isolation) | runtime/paths.ts:20 (canonical) |
NEO_DAEMON | flag-on-sentinel | off (unset) | Always-on daemon explicit opt-in | runtime/daemon/spawn.ts:84 |
NEO_DAEMON_SINGLE_HOST | flag-one | off (unset) | Skip the synced-filesystem daemon refusal | runtime/daemon/daemon.ts:139 + spawn.ts:87 |
NEO_DAEMON_DAILY_TOKEN_BUDGET | custom | 2000000 | Daily Tier-0 token cap; off/0 = unlimited | runtime/daemon/budget.ts:183-191 |
NEO_DAEMON_ACTIVITY_GATE | flag-off-sentinel | on | Skip dream/reflect passes on a quiet house | runtime/daemon/activity-gate.ts:71-73 |
NEO_HEARTBEAT_CONTENT_GATE | flag-off-sentinel | on | Skip heartbeat LLM call when content is unchanged | runtime/daemon/heartbeat-content-gate.ts:79-82 |
NEO_JOB_TIMEOUT_MS | int-nonneg | 1200000 (20m) | Global daemon-job wall-clock ceiling (0 disables) | runtime/daemon/job-timeout.ts:72-80 |
NEO_JOB_TIMEOUT_MS_<JOBNAME> | int-nonneg | falls through to NEO_JOB_TIMEOUT_MS | Per-job ceiling override (e.g. NEO_JOB_TIMEOUT_MS_DREAM) | runtime/daemon/job-timeout.ts:72-80 |
NEO_DREAM_MIN_INTERVAL_MS | int-nonneg | 3600000 (1h) | Dream job re-entry throttle floor | runtime/daemon/jobs/dream-job.ts:61-69 |
NEO_HEARTBEAT_MIN_INTERVAL_MS | int-nonneg | 1800000 (30m) | Heartbeat job re-entry throttle floor | runtime/daemon/jobs/heartbeat-job.ts:135-143 |
NEO_REFLECTION_MIN_INTERVAL_MS | int-nonneg | 3600000 (1h) | Reflection job re-entry throttle floor | runtime/daemon/jobs/reflection-job.ts:85-93 |
NEO_SIGNALS_MIN_INTERVAL_MS | int-nonneg | 600000 (10m) | Signal-poller job re-entry throttle floor | runtime/daemon/jobs/signal-poller-job.ts:88-96 |
NEO_EFFICIENCY_ATTEST_MIN_INTERVAL_MS | int-nonneg | 60000 (1m) | Monitoring-attestation job re-entry throttle floor | runtime/daemon/jobs/attestation-job.ts |
NEO_HEARTBEAT_ACTIVE_HOURS | string | always active | Heartbeat active-hours window "START-END" (local 24h) | runtime/daemon/jobs/heartbeat-job.ts:324 |
NEO_MEMORY_DREAMING_CRON | cron | 0 2 * * 0 | Dream pass cron override | runtime/dream-scheduler.ts:53-57 |
NEO_HEARTBEAT_CRON | cron | */30 * * * * | Heartbeat cron override | runtime/heartbeat-scheduler.ts:37-41 |
NEO_REFLECTION_CRON | cron | 0 3 * * * | Reflection pass cron override | runtime/reflect-scheduler.ts:35-39 |
NEO_SIGNALS_CRON | cron | */15 * * * * | Signal-poll cron override | runtime/signal-scheduler.ts:39-43 |
NEO_EFFICIENCY_ATTEST | flag-off-sentinel | on | Context-efficiency monitoring-attestation refresh job (default-on) | runtime/reflect-scheduler.ts (efficiencyAttestationEnabled) |
NEO_EFFICIENCY_ATTEST_CRON | cron | */10 * * * * (every 10m) | Monitoring-attestation refresh cron override | runtime/reflect-scheduler.ts (efficiencyAttestCron) |
NEO_SESSION_IDLE_MS | int-positive | 1800000 (30m) | Agent-server idle-session eviction window | runtime/agent-cli.ts:174 |
NEO_SESSION_SWEEP_MS | int-positive | 60000 (1m) | Agent-server idle-sweep cadence | runtime/agent-cli.ts:176 |
NEO_REQUEST_TIMEOUT_MS | int-positive | 0 (disabled) | Agent-server per-request hard cap (0 = disabled) | runtime/agent-cli.ts:184 |
NEO_DEBUG_TOOL_SCHEMA | flag-one | off (unset) | Tool-schema cache determinism guard | runtime/tool-schema-cache.ts:42-44 |
NEO_PRINT_MODE_LOGS | flag-one | off (unset) | Keep structured logs (stderr) in print mode | runtime/cli.ts:149 |
NEO_DEBUG_CODEX_BODY | flag-one | off (unset) | Dump Codex request bodies to stderr | providers/openai-oauth-http-provider.ts:845 |
NEO_EGRESS_GATE_DEBUG | flag-one | off (unset) | Egress-gate diagnostic logging (never weakens the gate) | security/egress-gate/gate.ts (new in Wave R1a) |
NEO_MODEL | string | unset (providers.json defaultModel) | One-shot default-model override (/model command) | runtime/config-loader.ts:333 |
NEO_PROVIDER | string | unset (providers.json defaultProvider) | One-shot default-provider override | runtime/config-loader.ts:334 |
NEO_PROVIDER_TIMEOUT_MS | int-positive | 600000 (10m, Number() convention) | Provider SDK client timeout | providers/provider-timeout.ts:34-40 |
NEO_UNATTENDED_RETRY | flag-one-or-true | off (unset) | Persistent retry for unattended (daemon) runs | providers/retry.ts:113-116 |
NEO_VERSION | string | 0.1.0 | Version stamped into the Codex-facing user agent | providers/openai-oauth-http-provider.ts:139 + openai-image-client.ts:121 |
NEO_MEMORY_RAG_MIN_SIMILARITY | custom | 0.15 | RAG cosine-similarity floor; off disables | memory/embeddings/retrieval.ts:42-58 |
NEO_MEMORY_RAG_DECAY_RANKING | flag-off-sentinel | on | RAG decay-aware (retrievability) ranking | memory/embeddings/retrieval.ts:66-68 |
NEO_REFLECTION_FEEDBACK | flag-off-sentinel | on | Inject reflection insights into the agent loop | core/agent-loop/core.ts:49-51 |
NEO_ATTUNEMENT_LIVE | custom | off (heuristic floor only) | Opt-in per-turn LLM live-state read (=== 'llm') | runtime/agent-sections.ts:309-311 |
NEO_MEMORY_RAG | custom | auto (on iff embedder configured) | RAG prefetch mode (on/ensemble/off; unset = auto) | memory/prefetch.ts:100 |
NEO_MEMORY_EMBEDDING_CONFLICTS | multi-sentinel-falsy | on | Embedding-similarity conflict detection in dream | memory/embeddings/conflict-detector.ts:60-65 |
NEO_MEMORY_CONFLICT_ADJUDICATION | multi-sentinel-falsy | on | LLM conflict adjudication in dream | memory/distillation/dream.ts:98-103 |
NEO_MEMORY_ARCHIVE_BACKSTOP | flag-off-sentinel | on | Dream archive backstop for stale memories | memory/distillation/dream.ts:881-883 |
NEO_MEMORY_ARCHIVE_BACKSTOP_CYCLES | int-positive | module default (3) | Archive-backstop cycle threshold (int >= 1, parseInt) | memory/distillation/dream.ts:886-892 |
NEO_AUTO_MEMORY_DIR | path | getNeoDir() | Auto-memory base directory override | memory/auto-memory/paths.ts:35-37 |
NEO_TOOL_RESULTS_DIR | path | ~/.neo/tool-results | Truncated-tool-result persistence directory | core/executor/helpers.ts:453-455 |
NEO_MEDIA_DIR | path | ~/.neo/media | Inbound channel-media persistence directory | channels/_media-store.ts:52 |
NEO_TELEMETRY_FILE | path | ~/.neo/telemetry/events.jsonl | Telemetry events.jsonl path (token-report) | bin/token-report.ts:22 |
NEO_PROFILE | string | mobile_minimal | Channel gateway tool-policy profile name | bin/neo-tg.ts:61 + bin/neo-wa.ts:78 |
NEO_BIN | path | unset (required by channels) | Path to compiled neo.js for NdjsonChild spawns | channels/_ndjson-child.ts:17 |
NEO_ENGINE | custom | embedded | Channel endpoint engine ('isolated' opts out of embedded) | channels/_endpoint.ts:51 |
NEO_DISABLE_BYPASS | flag-truthy | off (1/true/yes/on, trim+ci) | Kill-switch for bypass permissions mode | permissions/bypass-killswitch.ts:21-25 |
NEO_LIVE_DRIVER_ENABLE | flag-one | off (unset) | Consent gate for the live eval driver (real LLM calls) | eval/live-driver/scheduler.ts:81 |
NEO_BEHAVIOR_EVAL_DIR | path | ./.neo/behavior-eval | Behavior-eval output directory | runtime/live-queue.ts:294 |
NEO_BUNDLED_SKILLS_ROOT | path | resolved from package layout | Bundled-skills root override (non-empty string) | skills/bundled-extractor.ts:64-68 |
NEO_POWERSHELL_PATH | path | auto-detected | PowerShell executable path override (non-empty string) | util/powershell-path.ts:81-85 |
NEO_WINDOWS_JOB_CONTAINMENT | flag-off-sentinel | on | Windows managed-Job containment; literal off selects observable direct-root-only rollback | runtime/windows-job-containment.ts |
NEO_UPDATE_CHECK | flag-off-sentinel | on | Passive npm-registry version check that powers the TUI update banner; off disables | runtime/update-check.ts |
NEO_EFFICIENCY_CHECKPOINT_LEVEL | lever-ceiling | off | Compaction-checkpoint lever (W1) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency W0) |
NEO_EFFICIENCY_COMPRESSION_LEVEL | lever-ceiling | off | Command-output-compression lever (W2) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency W0) |
NEO_EFFICIENCY_READ_CACHE_LEVEL | lever-ceiling | off | Read-cache lever (W3) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency W0) |
NEO_EFFICIENCY_ROUTING_LEVEL | lever-ceiling | off | Model-routing-downshift lever (W4) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency W0) |
NEO_EFFICIENCY_BEHAVIORAL_LEVEL | lever-ceiling | off | Behavioral-steering lever (W5) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency W5) |
NEO_EFFICIENCY_CONSERVE_LEVEL | lever-ceiling | off | Quota-conserve lever (R2b) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency R2b) |
NEO_EFFICIENCY_DUPLICATE_GUARD_LEVEL | lever-ceiling | off | Duplicate-guard lever (R3b) operator ceiling — can only narrow behavior below the provisioned policy, never enable beyond it | runtime/env-settings.ts (new — Context-Efficiency R3b) |
NEO_CODE_HARNESS_SELF_HEAL | flag-off-sentinel | on | Cross-backend self-heal (R3a): re-dispatch a transport-killed delegated run once on a sibling backend serving the same model class. Set to off to restore hard-fail | runtime/env-settings.ts (new — Context-Efficiency R3a) |
NEO_SUPPRESS_WARNINGS | flag-truthy | off (1/true/yes, trim+ci; module-cached with refresh hook) | Suppress warn-level structured-log output. Left owned by logger.ts: it is module-cached at logger-module load with its own live-refresh hook, and importing it into env-settings.ts would risk a circular import back into the logger every other module (including this one, transitively via errors) depends on. | observability/logger.ts:55 |
NEO_FLAG_<NAME> | flag-truthy | falls through to flags.json then call-site default | Feature-flag env override family (truthy/falsy pair). Left owned by feature-flags.ts: it is a dynamic family (one var PER flag name, resolved at runtime from flags.json keys), not a fixed set of named vars a static registry entry can enumerate. | runtime/feature-flags.ts:42-48 (dynamic family — stays owned there) |
Default-on capabilities (Wave 1 — "Waking the Soul")
NEO_MEMORY_DREAMING, NEO_REFLECTION, NEO_ATTUNEMENT, NEO_HEARTBEAT, and (since vision-waves W2.3) NEO_SIGNALS are default-ON. A 2026-07 audit found these capabilities existed, were tested, and worked — but were default-off, so on the live install user-profile.md was never generated after months of real use: built-but-off is, behaviorally, off. The fix is a polarity flip.
'off' is the only disable sentinel — capabilityEnabled() (src/runtime/capability-flags.ts) returns true for every other value: unset, 'on', garbage, or an empty string. There is no truthy/falsy parsing (contrast with the unrelated NEO_FLAG_<NAME> system above). To opt a capability back out, set it explicitly:
NEO_MEMORY_DREAMING=off
NEO_REFLECTION=off
NEO_ATTUNEMENT=off
NEO_HEARTBEAT=off
NEO_SIGNALS=offDuring neo login onboarding (src/cli/onboarding/always-on.ts), accepting always-on now asks "keep X enabled?" for each capability — declining writes NEO_X=off to ~/.neo/.env; accepting (or an unattended default) writes nothing, since the absence of the var already means enabled. Autostart (src/runtime/daemon/autostart.ts) forwards a live =off value into the baked launcher env so the opt-out survives service restarts — the failure mode is inverted from the old default-off world: forgetting to forward the flag now silently RE-enables a capability the user turned off, not the other way around.
Config-backed behavior toggles (CLI-expansion follow-up)
The five soul-capability flags above, plus NEO_REFLECTION_FEEDBACK and NEO_MEMORY_RAG_DECAY_RANKING, are now ALSO settable through settings.json's behavior.* block — reachable via the generic neo config get/set/unset commands (see docs/cli.md's "Behavior toggles" subsection under Config). No new command was added; behavior is just a new dotted-path section under settings.
Precedence: env > config > default. When the env var is explicitly set it always wins (back-compat: anyone relying on the env var today keeps working unchanged); when unset, settings.behavior.<key> applies; when both are unset, the toggle defaults to enabled. This mirrors the existing applyProviderEnvOverrides convention for NEO_MODEL/NEO_PROVIDER (runtime/config-loader.ts) — an explicit env var is a live, restart-scoped override. The resolver lives in src/runtime/behavior-settings.ts (resolveCapabilityEnabled / resolveReflectionFeedbackEnabled / resolveRagDecayRankingEnabled); capability-flags.ts/env-settings.ts themselves stay env-only and pure (avoiding an import cycle with config-loader.ts — see that module's doc comment).
neo config set behavior.reflection false # same effect as NEO_REFLECTION=off
neo config get behavior.reflection
neo config unset behavior.reflection # back to default (enabled)Every other env var in this document (paths, secrets, ports, one-shot model overrides, debug toggles) is deliberately NOT bridged into config — this bridge is scoped to the vision-waves behavior/feature toggles only, per the CLI-expansion follow-up brief.