Environment Variables — Reference¶
All environment variables read or written by amplihack during a launch (amplihack claude, amplihack copilot, amplihack codex, amplihack amplifier).
Contents¶
- Variables set by amplihack
- AMPLIHACK_AGENT_BINARY
- AMPLIHACK_ASSET_RESOLVER
- AMPLIHACK_HOME
- AMPLIHACK_GRAPH_DB_PATH
- AMPLIHACK_KUZU_DB_PATH
- AMPLIHACK_NONINTERACTIVE
- AMPLIHACK_SESSION_ID
- AMPLIHACK_DEPTH
- AMPLIHACK_RUST_RUNTIME
- AMPLIHACK_VERSION
- AMPLIHACK_RELEASE_VERSION
- NODE_OPTIONS
- Variables injected by recipe executor
- AMPLIHACK_STEP_TIMEOUT
- AMPLIHACK_NONINTERACTIVE (recipe runner subprocess)
- AMPLIHACK_RECIPE_RUN_ID
- AMPLIHACK_RUNTIME_ROOT
- AMPLIHACK_RESULT_SINK
- CLAUDECODE (recipe runner subprocess)
- AMPLIHACK_RECIPE_HEARTBEAT_INTERVAL_SECONDS
- AMPLIHACK_RECIPE_SNIPPET_LINES
- AMPLIHACK_RECIPE_SNIPPET_BYTES
- AMPLIHACK_RECIPE_LOG_JSONL
- AMPLIHACK_RECIPE_TRANSIENT_MAX_ATTEMPTS
- AMPLIHACK_RECIPE_TRANSIENT_BUDGET_SECS
- NONINTERACTIVE
- DEBIAN_FRONTEND
- CI (recipe context)
- Context-derived recipe variables
- AMPLIHACK_CONTEXT_ENV_BUDGET_BYTES
- Variables read by amplihack
- AMPLIHACK_MEMORY_BACKEND
- HOME
- AMPLIHACK_DEFAULT_MODEL
- AMPLIHACK_ENABLE_BLARIFY
- AMPLIHACK_BLARIFY_MODE
- AMPLIHACK_NO_UPDATE_CHECK
- AMPLIHACK_PARITY_TEST
- AMPLIHACK_SKIP_AUTO_INSTALL
- AMPLIHACK_SKIP_MMDC
- AMPLIHACK_TEST_FAKE_LATEST_VERSION
- External LiteLLM gateway variables
- AMPLIHACK_TOPIC_NAME
- AMPLIHACK_PROJECT_ID
- CI
- UV_TOOL_BIN_DIR
- IS_SANDBOX
- Signal channel variables
- AMPLIHACK_SIGNAL_REUSE_ROLLING_GROUP
- AMPLIHACK_SIGNAL_ROLLING_GROUP_ID
Variables set by amplihack¶
These variables are injected into every child process launched by amplihack. They are not inherited from the parent shell; they are built fresh on each invocation.
AMPLIHACK_AGENT_BINARY¶
Type: string
Allowed values: claude | copilot | codex | amplifier (case-insensitive, exact match after trim)
Default: copilot
Set by: EnvBuilder::with_agent_binary() (as a back-compat read-through cache)
Read by: amplihack_utils::agent_binary::resolve() (precedence step 1)
Identifies which CLI binary the current session should use when spawning new AI sessions. As of the workflow runtime-isolation contract, this variable is an explicit override and read-through cache, not the only routing source. The shared resolver consults:
AMPLIHACK_AGENT_BINARYenv var (explicit override; CI/testing/back-compat)$AMPLIHACK_RUNTIME_ROOT/launcher_context.jsonlauncherfield (canonical workflow runtime state)<repo>/.claude/runtime/launcher_context.jsonlauncherfield (legacy fallback only)- Built-in default:
copilot
The launcher continues to write this variable to subprocess environments so that external consumers (notably rysweet/amplihack-recipe-runner) that have not yet migrated to the file-based resolver continue to work. New code inside amplihack-rs should call amplihack_utils::agent_binary::resolve(&cwd) instead of reading the env var directly.
Validation¶
Values are normalized (trim, lowercase) and matched against the allowlist {claude, copilot, codex, amplifier}. Values that contain /, \, .., null bytes, whitespace, control characters, or exceed 32 bytes are rejected. On rejection the resolver emits a structured tracing::warn! and falls through to the next precedence source.
# Start a Copilot session (the new default)
amplihack copilot
# Inside hooks, recipe steps, sub-agents:
echo $AMPLIHACK_AGENT_BINARY
# copilot
# Explicit override (CI, testing, manual selection)
AMPLIHACK_AGENT_BINARY=claude amplihack recipe run smart-orchestrator -c task_description="..."
# Invalid values are rejected and the resolver falls through
AMPLIHACK_AGENT_BINARY="../bin/evil" amplihack copilot
# warn: rejected AMPLIHACK_AGENT_BINARY (failed allowlist); falling back to runtime launcher context
Why the precedence order¶
- Env var first preserves the established escape hatch for CI/testing and lets external recipe-runner builds keep working unchanged.
- Runtime-root launcher context second keeps durable workflow state outside the task worktree while preserving routing for descendants that inherit
AMPLIHACK_RUNTIME_ROOT. - Legacy
.claude/runtimefallback third preserves older repositories long enough to migrate without treating task-worktree runtime state as canonical. copilotdefault last matches the project's current preferred runtime and removes the prior implicitclaudeassumption.
Why it exists: Recipe runner, hooks, and sub-agents are agent-agnostic and must call back into whatever tool the user actually launched. See Active Agent Binary for the full algorithm and Agent Binary Routing for the architectural rationale.
Python parity: Python skill scripts (amplifier-bundle/skills/pm-architect/scripts/agent_query.py, delegate_response.py) implement the same precedence and same allowlist; agent_query.py::detect_runtime() is the canonical Python entry point and is reused by delegate_response.py. The shell helper at amplifier-bundle/skills/migrate/scripts/migrate.sh re-implements the same algorithm with a case statement allowlist. The active binary is therefore consistent across Rust, Python, and shell code paths.
Existing claude users: repos that already have .claude/runtime/launcher_context.json with "launcher": "claude" continue to resolve to claude during migration — the legacy fallback wins over the new copilot default when runtime-root state and the env override are absent. New workflow code must write launcher context under AMPLIHACK_RUNTIME_ROOT, not under the task worktree.
Effect on startup self-update prompt: A non-empty AMPLIHACK_AGENT_BINARY is also recognised by the startup self-update prompt as a subprocess-safe signal — when the variable is set, the prompt is skipped and the skip-line amplihack: skipping update check (subprocess-safe / no TTY) is emitted to stderr. This means delegated agent invocations never block on the prompt, even at an interactive TTY. See Startup Self-Update Prompt — Subprocess-Safe Skip.
AMPLIHACK_ASSET_RESOLVER¶
Type: path
Example: /home/alice/.local/bin/amplihack-asset-resolver
Set by: EnvBuilder::with_asset_resolver()
Absolute path to the native bundle-asset resolver. Child processes can execute this binary with a single supported named asset or relative asset path argument, for example:
"$AMPLIHACK_ASSET_RESOLVER" amplifier-bundle/recipes/smart-orchestrator.yaml
"$AMPLIHACK_ASSET_RESOLVER" hooks-dir
That returns the resolved absolute path on stdout and exits non-zero on invalid input or missing assets.
The standalone binary resolves assets through the same CLI resolver as
amplihack resolve-bundle-asset.
The CLI library's Rust named-asset table is the shared source for the standalone binary's usage/listing output and the runtime helper mappings, so those consumers stay in sync with the command.
Resolution order (first match wins):
| Priority | Source |
|---|---|
| 1 | AMPLIHACK_ASSET_RESOLVER already set in environment |
| 2 | Sibling amplihack-asset-resolver next to the running amplihack executable |
| 3 | PATH lookup |
| 4 | ~/.local/bin/amplihack-asset-resolver |
| 5 | ~/.cargo/bin/amplihack-asset-resolver |
If no binary is found, the variable is omitted. Callers that require native resolution should treat absence as a hard setup problem rather than silently degrading.
Why it exists: Python's resolve_bundle_asset.py was a hidden runtime dependency for recipes and helper scripts. Exposing a dedicated Rust binary makes asset lookup explicit, testable, and reusable by child tools without embedding Python-specific paths.
AMPLIHACK_HOME¶
Type: path
Example: /home/alice/.amplihack
Set by: EnvBuilder::with_amplihack_home()
The root directory where amplihack stores framework assets, hooks, runtime state, and helper scripts. Recipe runner uses this to locate .claude/tools/amplihack/ and related subdirectories without requiring hardcoded paths.
Resolution order (first match wins):
| Priority | Source | Example result |
|---|---|---|
| 1 | AMPLIHACK_HOME already set in environment |
value is passed through unchanged |
| 2 | $HOME/.amplihack |
/home/alice/.amplihack |
| 3 | Directory containing the amplihack binary |
/usr/local/bin/../amplihack |
| — | All above fail | variable is not set (silent degradation) |
# Override for a non-standard install location
export AMPLIHACK_HOME=/opt/amplihack
amplihack claude
# Verify the value a subprocess receives
AMPLIHACK_HOME=/opt/amplihack amplihack claude --print-env 2>&1 | grep AMPLIHACK_HOME
# AMPLIHACK_HOME=/opt/amplihack
Security note: The resolved path is validated to be absolute and must not contain .. path components. Paths that fail validation are silently dropped; a warning is emitted to the trace log.
Python parity: Corresponds to AMPLIHACK_HOME propagation in the Python launcher.
AMPLIHACK_GRAPH_DB_PATH¶
Type: path
Example: /work/repo/.amplihack/graph_db
Set by: EnvBuilder::with_project_graph_db()
Read by: commands::memory::resolve_memory_graph_db_path()
Overrides the code-graph database path used by Rust memory operations in launched child
processes. amplihack launch and the Rust recipe runner set it to the
project-local .amplihack/graph_db so launched sessions, hooks, and native
code-graph features operate on the same live store.
If this variable is absent, amplihack sets it to the project-local
.amplihack/graph_db directory. The legacy AMPLIHACK_KUZU_DB_PATH
override is accepted as an alias and translated to AMPLIHACK_GRAPH_DB_PATH
in the child process environment.
# Effective child-process environment for a project rooted at /work/repo
AMPLIHACK_GRAPH_DB_PATH=/work/repo/.amplihack/graph_db amplihack claude
Why it exists: Launched sessions, hooks, and native code-graph features must all operate on the same project-local DB. Setting this variable ensures every subprocess resolves to the correct location without relying on filesystem detection heuristics.
AMPLIHACK_KUZU_DB_PATH (backward-compatible alias)¶
Legacy compatibility alias for AMPLIHACK_GRAPH_DB_PATH.
If AMPLIHACK_GRAPH_DB_PATH is unset, Rust still reads AMPLIHACK_KUZU_DB_PATH
and also exports it for older child-process consumers. When both are present,
AMPLIHACK_GRAPH_DB_PATH wins.
# Backward-compatible older configuration still works
AMPLIHACK_KUZU_DB_PATH=/work/repo/.amplihack/graph_db amplihack claude
The alias remains because the storage engine was originally named Kuzu (now
rebranded to LadybugDB), but new automation should prefer
AMPLIHACK_GRAPH_DB_PATH so the public surface stays backend-neutral.
AMPLIHACK_NONINTERACTIVE¶
Type: flag
Values: 1 (non-interactive) — absence or any other value means interactive
Read by: util::is_noninteractive()
Set by: EnvBuilder::set_if(is_noninteractive(), "AMPLIHACK_NONINTERACTIVE", "1")
Signals that the process is running in a non-interactive environment. When set to 1, amplihack skips all interactive prompts and framework bootstrap guidance, preventing hangs in CI pipelines, pipes, and sandboxed environments.
# Run without interactive prompts (e.g. in CI)
AMPLIHACK_NONINTERACTIVE=1 amplihack claude --print 'Fix the lint errors'
# Pipe use also triggers non-interactive mode automatically (no TTY on stdin)
echo 'Summarize this file' | amplihack claude --print -
Detection logic:
Non-interactive mode is active when either condition is true:
AMPLIHACK_NONINTERACTIVE=1is set in the environmentstdinis not a TTY (detected viastd::io::IsTerminal)
Condition 2 covers pipe usage without requiring the caller to set the variable manually.
Effect on bootstrap: When non-interactive mode is detected, prepare_launcher() returns immediately without running check_required_tools() or ensure_framework_installed(). The assumption is that CI environments are pre-provisioned and that interactive guidance output would be noise.
Effect on update check: Non-interactive mode also suppresses the pre-launch npm update check. No npm subprocesses are spawned. This is equivalent to passing --skip-update-check on every invocation. See Manage Tool Update Notifications for details.
Effect on startup self-update prompt: A non-empty AMPLIHACK_NONINTERACTIVE (any value, not only "1") also skips the amplihack startup self-update prompt — the Update now? [y/N] (5s timeout): line is never printed and stdin is never read. A single skip-line amplihack: skipping update check (subprocess-safe / no TTY) is emitted to stderr. See Startup Self-Update Prompt — Subprocess-Safe Skip.
Propagation: Once detected, AMPLIHACK_NONINTERACTIVE=1 is written into the child process environment so that nested invocations (e.g. sub-agents spawned by hooks) also behave non-interactively.
Cross-language contract: Only the value "1" triggers non-interactive mode. The strings "true", "yes", "on", and "TRUE" are not recognised — this matches the Python launcher's behaviour.
Python parity: Corresponds to AMPLIHACK_NONINTERACTIVE check in amplihack/cli/launch.py (Python PRs #3103, #3066).
AMPLIHACK_SESSION_ID¶
Type: string
Example: rs-1741872000-12345
Set by: EnvBuilder::with_amplihack_session_id()
A correlation ID for the current session. Used in log output and by the nesting detector to identify recursive amplihack invocations. Reused unchanged if already set in the environment (i.e. a nested invocation inherits the session ID of its parent).
Format: rs-<unix_seconds>-<pid>
AMPLIHACK_DEPTH¶
Type: integer string
Default: 1
Set by: EnvBuilder::with_amplihack_session_id()
Nesting depth of the current invocation. The root invocation receives 1. Nested sessions (amplihack launched from within a Claude Code hook) inherit the value from the environment unchanged; the Python launcher increments it, but the Rust launcher propagates it as-is to match Python's observed behaviour for initial launches.
AMPLIHACK_RUST_RUNTIME¶
Type: flag
Value: always 1
Set by: EnvBuilder::with_amplihack_vars()
Indicates the session was started by the Rust CLI rather than the Python launcher. Hooks and recipe scripts can use this to branch on runtime differences.
AMPLIHACK_VERSION¶
Type: semver string
Example: 0.3.1
Set by: EnvBuilder::with_amplihack_vars()
The version of the amplihack-cli binary that launched the session. Release
builds use AMPLIHACK_RELEASE_VERSION when it was set at compile time; local
developer builds fall back to CARGO_PKG_VERSION.
AMPLIHACK_RELEASE_VERSION¶
Type: semver string
Example: 0.9.78
Set by: release build environment
Read by: Rust compile-time option_env!("AMPLIHACK_RELEASE_VERSION")
Build-time override for the version embedded in released binaries. The release
workflow sets this value while compiling so amplihack --version, doctor
output, plugin manifests, hook context loading, and the runtime
AMPLIHACK_VERSION child-process variable all report the release tag version.
Local builds normally leave this unset and use CARGO_PKG_VERSION.
AMPLIHACK_RELEASE_VERSION=0.9.78 cargo build --release --locked --bin amplihack
./target/release/amplihack --version
NODE_OPTIONS¶
Type: space-separated Node.js CLI flags
Set by: launcher startup via memory_config.rs, then propagated by EnvBuilder::with_amplihack_vars()
amplihack now computes a smart --max-old-space-size=<mb> value at top-level launcher startup based on detected system RAM, persists the consent choice in ~/.amplihack/config, and displays the active choice on launch. The resolved value is then propagated through EnvBuilder.
When startup does not supply an explicit value, EnvBuilder still falls back to --max-old-space-size=32768, and if ambient NODE_OPTIONS already contains --max-old-space-size= it is preserved rather than duplicated.
Variables injected by recipe executor¶
These variables are read, set, or removed by the recipe execution path
(amplihack recipe run) while launching recipe-runner-rs and running recipe
steps. Heartbeat, snippet, and JSONL log variables are optional user
configuration. See Recipe Executor Environment
and Recipe Runner Logging for full details.
AMPLIHACK_STEP_TIMEOUT¶
Type: string (unsigned integer as text)
Values: "0" (disable timeouts) | "600" (override to 600 seconds) | any non-negative integer
Set by: amplihack recipe run --step-timeout <SECONDS>
Overrides the timeout_seconds value defined in individual recipe steps. When set, every step in the recipe uses this value instead of its YAML-defined timeout. A value of "0" disables step timeouts entirely, allowing steps to run indefinitely.
This variable is only present in the child environment when the user passes --step-timeout to amplihack recipe run. When the flag is omitted, YAML-defined timeout_seconds values apply as-is (though the default-workflow agent steps no longer define timeout_seconds).
# Override all step timeouts to 10 minutes
amplihack recipe run recipe.yaml --step-timeout 600
# Child process sees: AMPLIHACK_STEP_TIMEOUT=600
# Disable all step timeouts
amplihack recipe run recipe.yaml --step-timeout 0
# Child process sees: AMPLIHACK_STEP_TIMEOUT=0
# No override — YAML timeouts apply (agent steps have none by default)
amplihack recipe run recipe.yaml
# AMPLIHACK_STEP_TIMEOUT is NOT set in child environment
Why it exists: The default-workflow recipes no longer define timeout_seconds on agent steps, so agent steps run to completion without artificial time limits. This variable provides an opt-in escape hatch for CI environments that need wall-clock budgets. The env var approach is forward-compatible — recipe-runner-rs can adopt it independently without CLI changes.
Security note: The value is always a u64 rendered as a string. No shell metacharacters are possible. The CLI rejects non-numeric input at parse time via clap's type enforcement.
AMPLIHACK_NONINTERACTIVE (recipe runner subprocess)¶
Type: flag
Value: 1
Set by: amplihack recipe run centralized subprocess environment
The recipe runner launch writes AMPLIHACK_NONINTERACTIVE=1 into the
recipe-runner-rs child environment. This is stronger than top-level launcher
propagation: the value is forced for recipe execution even when the parent
process is interactive and the parent environment does not contain
AMPLIHACK_NONINTERACTIVE.
This prevents nested recipe, hook, and agent subprocesses from asking for input or showing interactive update prompts while an automated workflow is already in progress.
# The recipe-runner child receives AMPLIHACK_NONINTERACTIVE=1.
env -u AMPLIHACK_NONINTERACTIVE \
amplihack recipe run default-workflow \
-c task_description="Update generated docs" \
-c repo_path=.
AMPLIHACK_RECIPE_RUN_ID¶
Type: UUID string
Set by: amplihack recipe run centralized subprocess environment
Read by: recipe-runner-rs, recipe steps, child tools, and log consumers
Stable correlation identity for one amplihack recipe run invocation. The CLI
generates this UUID before spawning recipe-runner-rs, injects it into the child
environment, writes it to early and final amplihack.recipe.log_pointer stderr
events, and includes it in final JSON/YAML results as run_id when a result can
be produced.
amplihack recipe run default-workflow \
-c task_description="Fix flaky retry tests" \
-c repo_path=. \
--format json > result.json 2> progress.log
jq -r '.run_id' result.json
grep '^amplihack\.recipe\.log_pointer ' progress.log
Treat this variable as read-only. Do not set it manually for normal use; the wrapper creates a fresh UUID for each invocation so concurrent runs do not share an identity.
See Recipe Run Correlation Reference for the pointer event schema and final result fields.
AMPLIHACK_RUNTIME_ROOT¶
Type: absolute path
Set by: amplihack recipe run runtime-root resolver when absent; preserved
when explicitly supplied by the caller
Read by: launchers, recipe steps, workflow provenance logging, publish
helpers, finalization helpers, and nested agents
Directory where workflow-generated runtime files are written. The runtime root keeps generated launcher state, provenance, logs, metrics, reflection output, locks, and child-agent runtime files outside the commit worktree. The top-level workflow establishes this value once and child workflows inherit it unchanged.
Resolution order:
| Priority | Source |
|---|---|
| 1 | Existing AMPLIHACK_RUNTIME_ROOT value |
| 2 | $XDG_RUNTIME_DIR/amplihack/runtime/<AMPLIHACK_RECIPE_RUN_ID> |
| 3 | /tmp/amplihack-runtime/<user>/<AMPLIHACK_RECIPE_RUN_ID> |
The resolver creates these subdirectories with restrictive owner-only permissions where the platform supports them:
# Override the runtime root for one recipe run.
AMPLIHACK_RUNTIME_ROOT=/var/tmp/amplihack-runtime/login-fix \
amplihack recipe run default-workflow \
-c task_description="Fix login flake" \
-c repo_path=.
Use a private path outside the repository worktree. Do not point this variable
at .claude/runtime, worktrees/, target/, or another generated directory
inside the active task worktree.
See Workflow Runtime Artifacts Reference for the full runtime-root, cleanup, and lifecycle preflight contract.
AMPLIHACK_RESULT_SINK¶
Type: absolute path
Set by: the orchestration runner (run_delivered_command) when a caller opts
in via RunOptions.result_sink
Read by: the spawned agent / recipe step
Names the clean result channel file for a step. When present and non-empty,
the child should write its final semantic answer (free text — JSON not required)
to this path in addition to whatever it prints on stdout. After the child
exits, the runner reads this file verbatim into ProcessResult.result,
giving consumers the answer without scraping ANSI / tracing / banner noise out of
stdout.
Key behaviours:
- Opt-in only. Exported only when
RunOptions.result_sinkisSome. Absent ⇒ legacy stdout-only capture (result == None). - No stale inheritance. When the caller does not opt in, the runner
env_removes any inheritedAMPLIHACK_RESULT_SINKso an ancestor value can never silently redirect capture. - Runner-owned path. The path is allocated by the runner under the run's runtime directory with owner-only permissions; it is never taken from untrusted recipe context.
- Verbatim. The runner performs no ANSI-strip, trim, newline-normalize, or
JSON parse. Oversize or non-UTF-8 contents yield
result == None(fallback to stdout).
# Child-side idiom: honour the channel when the runner provides it.
if [ -n "${AMPLIHACK_RESULT_SINK:-}" ]; then
printf '%s' "$FINAL_ANSWER" > "$AMPLIHACK_RESULT_SINK"
fi
See the Clean Result Channel Reference for the full contract, API, verbatim guarantee, and migration example.
CLAUDECODE (recipe runner subprocess)¶
Type: removed environment variable
Removed by: amplihack recipe run centralized subprocess environment
The recipe runner launch explicitly removes CLAUDECODE from the
recipe-runner-rs child environment. The variable is Claude-Code-specific
session state, not a portable amplihack routing signal. Leaving it set in a
nested recipe can make downstream agents believe they are running inside the
original Claude Code host even when the active launcher is Copilot, Codex, or
Amplifier.
Use AMPLIHACK_AGENT_BINARY for runtime routing. It is validated, propagated,
and documented as the active agent selector.
# The parent value is ignored for the recipe-runner child.
CLAUDECODE=1 amplihack recipe run smart-orchestrator \
-c task_description="Review the open PR" \
-c repo_path=.
AMPLIHACK_RECIPE_HEARTBEAT_INTERVAL_SECONDS¶
Type: string (unsigned integer as text)
Values: "0" (disable heartbeats) | "60" (default) | any non-negative integer
Read by: recipe-runner-rs
Controls how often long-running recipe, agent, subprocess, and nested-recipe steps emit heartbeat lines to stderr. The interval is rate-limited per active step. Short steps that complete before one interval do not emit heartbeats.
# Emit a heartbeat every 15 seconds while debugging a long-running agent step
AMPLIHACK_RECIPE_HEARTBEAT_INTERVAL_SECONDS=15 \
amplihack recipe run default-workflow \
-c task_description="Debug hanging test generation"
# Disable heartbeat lines while preserving start/completion/failure progress
AMPLIHACK_RECIPE_HEARTBEAT_INTERVAL_SECONDS=0 \
amplihack recipe run default-workflow \
-c task_description="Run with minimal progress"
Equivalent config key: recipe.heartbeat_interval_seconds in
~/.amplihack/config.
AMPLIHACK_RECIPE_SNIPPET_LINES¶
Type: string (unsigned integer as text)
Default: 20
Read by: recipe-runner-rs
Maximum number of recent lines retained per active child source and stream. Older lines are dropped from the rolling buffer. This bound applies to snippets printed in failure diagnostics, included in JSON results, and written to JSONL logs.
AMPLIHACK_RECIPE_SNIPPET_LINES=60 \
amplihack recipe run default-workflow \
-c task_description="Diagnose compiler failure" \
--format json > result.json
Equivalent config key: recipe.snippet_lines in ~/.amplihack/config.
AMPLIHACK_RECIPE_SNIPPET_BYTES¶
Type: string (unsigned integer as text)
Default: 8192
Read by: recipe-runner-rs
Maximum bytes retained per active child source and stream. This byte bound is
enforced together with AMPLIHACK_RECIPE_SNIPPET_LINES; whichever limit is hit
first controls truncation.
AMPLIHACK_RECIPE_SNIPPET_BYTES=32768 \
amplihack recipe run default-workflow \
-c task_description="Diagnose noisy subprocess output" \
--format json > result.json
Equivalent config key: recipe.snippet_bytes in ~/.amplihack/config.
AMPLIHACK_RECIPE_TRANSIENT_MAX_ATTEMPTS¶
Type: string (unsigned integer as text)
Default: 3
Read by: amplihack recipe run
Total attempts — the first try plus retries — made when a recipe run fails with an unambiguously transient transport fault (HTTP 529/503/502/500/429, a reset connection, a socket timeout). Nothing else is retried: a failing test, a missing binary, or a policy refusal is terminal on the first attempt.
Values above 10 are clamped to 10; 1 disables the retry entirely. Unset,
empty, 0, and unparsable values fall back to the default.
AMPLIHACK_RECIPE_TRANSIENT_MAX_ATTEMPTS=5 \
amplihack recipe run default-workflow \
-c task_description="Long run over a flaky endpoint"
See Transient Failure Retry (issue #1267) for the classification rules and the greppable markers each decision writes.
AMPLIHACK_RECIPE_TRANSIENT_BUDGET_SECS¶
Type: string (unsigned integer as text, seconds)
Default: 300
Read by: amplihack recipe run
Budget for the total time spent waiting on backoff across all
transient-transport retries in one recipe run. Backoff delays start at 10s and
double with equal jitter, clamped so a wait never overshoots the remaining
budget. Whichever bound is reached first — this one or
AMPLIHACK_RECIPE_TRANSIENT_MAX_ATTEMPTS — ends the retry with a terminal
error naming the class.
This is deliberately not wall-clock time since the run started. A 529 typically arrives hours into a long workstream; a budget measured from the start would already be exhausted at the first failure, and no retry would ever be attempted. Only the idle waiting is charged against this budget, so the duration of the work itself is irrelevant to it.
AMPLIHACK_RECIPE_TRANSIENT_BUDGET_SECS=900 \
amplihack recipe run default-workflow \
-c task_description="Tolerate a longer provider outage"
AMPLIHACK_RECIPE_LOG_JSONL¶
Type: path
Read by: recipe-runner-rs
When set, writes structured JSONL recipe events to the specified file. Events
include the recipe run_id, step lifecycle transitions, heartbeats, output
snippets, and failure context. Human-readable progress still goes to stderr.
AMPLIHACK_RECIPE_LOG_JSONL=/tmp/default-workflow.jsonl \
amplihack recipe run default-workflow \
-c task_description="Add retry budget metrics"
jq 'select(.type == "heartbeat")' /tmp/default-workflow.jsonl
Equivalent config key: recipe.log_jsonl in ~/.amplihack/config.
NONINTERACTIVE¶
Type: string
Value: 1
Set by: Recipe executor, execute_shell_step()
Signals to general-purpose tools that they should not attempt interactive prompts. Not specific to any one tool — serves as a generic non-interactive flag.
DEBIAN_FRONTEND¶
Type: string
Value: noninteractive
Set by: Recipe executor, execute_shell_step()
Suppresses interactive prompts from dpkg and apt. Standard Debian/Ubuntu convention for headless package management.
CI (recipe context)¶
Type: string
Value: true
Set by: Recipe executor, execute_shell_step()
Signals CI-like behavior to npm, yarn, pip, and other tools that check this variable before prompting. Note: this is set by the recipe executor for all recipe steps, independent of whether the top-level process is actually running in a CI system.
Context-derived recipe variables¶
Type: string (one variable per recipe context key)
Examples: TASK_DESCRIPTION, REPO_PATH, ISSUE_NUMBER, BRANCH_NAME
Set by: amplihack recipe run, context environment export (lowest precedence)
Every recipe context variable is exported to the recipe-runner-rs subprocess —
and therefore to every shell and nested sub-recipe step — as an environment
variable whose name is the ASCII-uppercased context key. For example,
task_description becomes TASK_DESCRIPTION and repo_path becomes
REPO_PATH. Bash steps can read these directly, including under set -u.
amplihack recipe run env-aware-recipe \
-c task_description="Add validation" \
-c repo_path=.
# A bash step sees: TASK_DESCRIPTION=Add validation, REPO_PATH=.
The exact set of names depends entirely on the recipe context. Rules:
- Names must be valid shell identifiers (
^[A-Z_][A-Z0-9_]*$); keys that do not qualify after uppercasing are skipped with a name-onlyWARN. - Reserved and dangerous names are never exported — including
PATH,HOME,SHELL,IFS, theLD_*/DYLD_*loader variables,BASH_ENV,ENV,PS4,PROMPT_COMMAND,SHELLOPTS,BASHOPTS,PYTHONPATH,NODE_OPTIONS,PERL5OPT,RUBYOPT, and any name beginning withAMPLIHACK_. - Context export is applied at the lowest precedence, so it can never override
the
AMPLIHACK_*variables orAMPLIHACK_RECIPE_RUN_IDdocumented above.
See Recipe Context Environment Export for the full contract, denylist, and security model.
AMPLIHACK_CONTEXT_ENV_BUDGET_BYTES¶
Type: string (unsigned integer as text)
Values: any non-negative integer (0 = essentials only) | unset (adaptive default)
Read by: amplihack recipe run, context environment export
Overrides the aggregate byte budget for mirroring recipe context into the
recipe-runner-rs environment. The context mirror is inherited by every bash
step, so an unbounded mirror could push the cumulative environment past the
kernel's ARG_MAX and make a late step fail with
Argument list too long (os error 7) (issue #1023). By default the budget is
derived adaptively at spawn time from sysconf(_SC_ARG_MAX) minus the
inherited environment and a reservation; this variable pins it explicitly.
- When unset, the budget is derived adaptively (recommended).
- When set to a valid
usize, that exact byte budget is used and takes precedence over the derived value. 0is valid and means "mirror only the essential keys" (task_description,repo_path,existing_branch,should_*).- An invalid value (non-numeric, negative, overflowing) is ignored with a
name-only
WARN reason=invalid_env_budget_override, and the derived budget is used — the run is never aborted for a bad override.
Essential keys are always exported regardless of the budget. Non-essential keys
are filled smallest-first until the budget is exhausted; any key dropped from the
mirror is still delivered to the runner via the --context-file path for
{{placeholder}} substitution.
# Pin the mirror budget to 256 KB
AMPLIHACK_CONTEXT_ENV_BUDGET_BYTES=262144 \
amplihack recipe run default-workflow \
-c task_description="Large multi-file campaign"
# Mirror only essential keys (drop all non-essential mirroring)
AMPLIHACK_CONTEXT_ENV_BUDGET_BYTES=0 \
amplihack recipe run default-workflow \
-c task_description="Minimal env footprint"
See Recipe Context Environment Export → Aggregate environment budget for the derivation, essential-key set, and smallest-first fill.
Variables read by amplihack¶
These variables influence amplihack's behaviour but are not set by it.
External LiteLLM gateway variables¶
These three variables form the complete opt-in external LiteLLM configuration. If any one is present, all three must be valid. Invalid, empty, or partial configuration fails before an agent process is spawned.
| Variable | Type and default | Purpose |
|---|---|---|
AMPLIHACK_LITELLM_ENDPOINT |
URL; unset | Gateway base URL. HTTPS is required except for literal loopback development URLs. |
AMPLIHACK_LITELLM_API_KEY |
secret string; unset | Restricted LiteLLM virtual key. It is never serialized or placed in child command arguments. Do not use an administrative master key. |
AMPLIHACK_LITELLM_MODEL |
model name; unset | Required for every supported launcher; selects the gateway model alias. |
LiteLLM and PostgreSQL own usage, spend, budgets, and rate limits. Amplihack does not implement process-local gateway accounting or controls.
When the selected launcher is Claude Code, amplihack sets
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1; users do not need to set that variable.
External Claude Code routing requires the exact claude executable to report
semantic version 2.1.247. Amplihack probes it before checkout, auto-mode
staging, launch setup, session tracking, or Docker operations and rejects
missing executables, failed probes, malformed or unknown output, prereleases,
and all other versions. The probe will receive neither
AMPLIHACK_LITELLM_API_KEY nor direct provider credentials.
The Docker launcher rejects loopback gateway endpoints so normal container network isolation remains intact. Use an HTTPS gateway reachable from the container, or run the agent outside Docker for a host-loopback development gateway.
See the external LiteLLM boundary for the routing and ownership contract.
AMPLIHACK_MEMORY_BACKEND¶
Type: string
Values: sqlite | graph-db | kuzu
Read by: resolve_memory_backend_preference(), resolve_transfer_backend_choice(), resolve_backend_with_autodetect()
Selects the memory storage backend for all memory commands: memory tree,
memory clean, memory export, and memory import. When unset, the backend
is chosen by probing the filesystem in priority order:
AMPLIHACK_GRAPH_DB_PATHpath exists on disk →graph-db~/.amplihack/memory_graph.dbexists →graph-db- Neither exists →
sqlite(default for new installs)
# Permanently opt into SQLite (add to shell profile)
export AMPLIHACK_MEMORY_BACKEND=sqlite
# Single-invocation override
AMPLIHACK_MEMORY_BACKEND=graph-db amplihack memory tree
# Legacy kuzu alias still works (backward-compatible)
AMPLIHACK_MEMORY_BACKEND=kuzu amplihack memory tree
Values outside the allowlist ['sqlite', 'kuzu', 'graph-db'] produce a
visible warning to stderr and fall back to the graph-db backend. There is no
silent acceptance of unrecognised values.
Why it exists: New installs default to SQLite (no native library
required). Existing installs with a populated memory_graph.db continue to
use graph-db automatically. This variable lets users and CI pipelines opt in
or out of either backend without modifying on-disk state.
See Memory Backend Reference for the complete backend configuration reference.
HOME¶
Required: yes (for most operations)
Standard Unix home directory. Used to resolve ~/.amplihack, ~/.npm-global, and shell profile paths.
AMPLIHACK_DEFAULT_MODEL¶
Type: string
Default: claude-opus-5[1m] (a concrete model id, not an alias; issue #1421). An empty or whitespace-only value passes no --model.
Used by: configured_default_model() in commands/launch/command.rs
Sets the --model amplihack passes to Claude-compatible tools: claude,
rusty, rustyclawd and amplifier. amplihack copilot and amplihack codex
ignore it.
AMPLIHACK_DEFAULT_MODEL |
What amplihack adds |
|---|---|
| unset, or not valid UTF-8 | --model claude-opus-5[1m] |
| a model id | --model with that id, trimmed of surrounding whitespace; a dotted Claude id is rewritten to hyphens |
| empty or whitespace-only | nothing; the tool picks its own default |
Because amplihack passes --model unless this variable is empty, the "model"
in ~/.claude/settings.json only takes effect when you set
AMPLIHACK_DEFAULT_MODEL= (empty).
When any External LiteLLM gateway variable
is set, this variable is not read: the model is the required
AMPLIHACK_LITELLM_MODEL, passed unchanged. It is never normalised, because the
gateway routes on the exact name.
Why the default is a concrete id: an alias such as opus[1m] is resolved by
the tool, and amplihack does not control the tool's version. On one install that
alias resolved to the retired claude-opus-4-1-20250805, and every agent step
failed with a 404 naming a model the user had never chosen. A concrete id either
works or fails naming the exact string amplihack sent.
# Pin a model for every Claude launch
AMPLIHACK_DEFAULT_MODEL=claude-sonnet-4-5 amplihack claude
# amplihack adds: --model claude-sonnet-4-5
# Let Claude Code (and ~/.claude/settings.json) choose
AMPLIHACK_DEFAULT_MODEL= amplihack claude
# amplihack adds no --model
Whenever amplihack adds --model, it prints one line to stderr naming the model
and where it came from, so a later "model not found" error can be traced back to
it:
amplihack: passing `--model claude-sonnet-4-5` to `claude` (from AMPLIHACK_DEFAULT_MODEL). Set AMPLIHACK_DEFAULT_MODEL to override it, or to an empty value to let claude choose its own default model.
With the variable unset or not valid UTF-8, the source reads
amplihack's built-in default.
On the LiteLLM gateway path the line names AMPLIHACK_LITELLM_MODEL, both as
the source and as the variable to change, because this variable is not read
there:
amplihack: passing `--model gateway-model` to `claude` (from AMPLIHACK_LITELLM_MODEL). Set AMPLIHACK_LITELLM_MODEL to change it. AMPLIHACK_DEFAULT_MODEL is not read while a LiteLLM gateway variable is set.
Dotted Claude model ids¶
GitHub Copilot CLI writes Claude model ids with a dot (claude-opus-5.5).
Claude model ids use hyphens (claude-opus-5-5; see Anthropic's
models overview),
and the variable is only read for Claude-compatible launches. So amplihack
rewrites a dotted Claude id before passing it. Issue #1527 records what Claude
Code did with the dotted form when it was reported; this page does not repeat
it, because it depends on the Claude Code version.
AMPLIHACK_DEFAULT_MODEL='claude-opus-5.5[1m]' amplihack claude
# amplihack adds: --model claude-opus-5-5[1m]
The stderr line names both spellings:
amplihack: passing `--model claude-opus-5-5[1m]` to `claude` (from AMPLIHACK_DEFAULT_MODEL, normalised from `claude-opus-5.5[1m]`: Claude model ids use hyphens, not dots). Set AMPLIHACK_DEFAULT_MODEL to override it, or to an empty value to let claude choose its own default model.
The rewrite applies only to a value (after trimming) of exactly the form
claude-<family>-<major>.<minor><suffix>, where:
<family>is one or more lowercase ASCII letters<major>and<minor>are one or more ASCII digits<suffix>is empty or starts with[or-
Only the dot between <major> and <minor> changes, to a hyphen. The suffix is
copied as typed. Matching is case-sensitive and exact, with no aliases and no
fuzzy matching, so the result always names the same model you set.
| Rewritten | What amplihack adds |
|---|---|
claude-opus-5.5 |
--model claude-opus-5-5 |
claude-sonnet-4.5 |
--model claude-sonnet-4-5 |
claude-opus-5.5[1m] |
--model claude-opus-5-5[1m] |
claude-opus-4.1-20250805 |
--model claude-opus-4-1-20250805 |
Any other value is passed as-is:
| Passed as-is | Why |
|---|---|
claude-opus-5-5, claude-opus-5-5[1m] |
already hyphenated |
claude-opus-5[1m] |
no minor version (this is the built-in default) |
opus[1m], sonnet |
aliases, not full ids |
gpt-5.1, gemini-2.5-pro |
not Claude ids |
claude-3.5-sonnet |
the version comes before the family |
claude-opus-5.5.1 |
the suffix starts with ., not [ or - |
Claude-Opus-5.5 |
not lowercase |
Only the --model argument is rewritten. The launched tool inherits
AMPLIHACK_DEFAULT_MODEL exactly as you set it. A nested amplihack launch reads
it again and produces the same rewrite, unless that launch has an explicit
--model or uses the LiteLLM gateway.
Explicit --model¶
A --model <id> or --model=<id> on the amplihack command line overrides
this variable. It is forwarded exactly as typed and is never rewritten, even
when dotted.
When an explicit value is a dotted Claude id of the form described above, amplihack forwards it unchanged and prints one warning to stderr naming the hyphenated spelling. The launched tool may not report the problem itself (issue #1527), so without this line the launch could give no sign of it:
amplihack: warning: passing `--model claude-opus-5.5` to `claude` as typed, but Claude model ids use hyphens, not dots. Use `--model claude-opus-5-5`.
The warning gives only the spelling, which amplihack can vouch for. It does not describe what the launched tool does with the dotted id, because that depends on the tool and its version.
There is no warning for any other explicit value, and none in these cases:
amplihack copilotandamplihack codex. The dotted spelling is GitHub Copilot CLI's own, soamplihack copilot --model claude-opus-4.5is correct as typed.- The LiteLLM gateway path, because the gateway routes on the exact name and a dot in it may be correct.
Neither the rewrite nor the warning looks at ANTHROPIC_BASE_URL, so both
apply whatever endpoint the launched tool talks to. If yours is a proxy that
serves the dotted spelling, pass it as an explicit --model. amplihack
forwards that as typed, and you can ignore the warning.
# The explicit --model wins over the variable and reaches claude unchanged
AMPLIHACK_DEFAULT_MODEL='claude-opus-5.5[1m]' amplihack claude --model claude-sonnet-4-5
# claude receives: --model claude-sonnet-4-5
# Forwarded unchanged, with the warning above
amplihack claude --model claude-opus-5.5
# Works
amplihack claude --model 'claude-opus-5-5[1m]'
For the other flags amplihack adds to the launch command, such as
--dangerously-skip-permissions, and the order of the assembled command line,
see Launch Flag Injection.
AMPLIHACK_COPILOT_NO_REMOTE¶
Type: flag
Values: 1 suppresses --remote injection; absence or any other value keeps the default
Used by: should_inject_copilot_remote() in commands/launch/command.rs
When amplihack copilot launches the Copilot CLI, it injects --remote by
default to offload compute to GitHub's cloud. Set this variable to 1 to
suppress the injection and run Copilot locally.
# Disable remote mode
AMPLIHACK_COPILOT_NO_REMOTE=1 amplihack copilot
# Copilot starts without --remote
Users can also pass --no-remote directly as an extra arg; the launcher
detects this and skips injection automatically.
AMPLIHACK_ENABLE_BLARIFY¶
Type: flag
Values: 1 enables launcher-side code-indexing checks; absence or any other value disables them
Read by: commands::launch::should_prompt_blarify_indexing()
Opt-in gate for launcher-side code indexing. When set to 1 for amplihack claude, the Rust launcher checks whether code-graph artifacts are missing or stale, and whether the project-local .amplihack/graph_db store already exists, then either prompts or follows AMPLIHACK_BLARIFY_MODE if that mode is set.
Without AMPLIHACK_BLARIFY_MODE, interactive launches offer to either:
- import an existing fresh
.amplihack/blarify.jsonviaamplihack index-codewhen the code-graph DB is missing, or - generate fresh native SCIP artifacts via
amplihack index-scipwhen the existing artifact is stale or no fresh import input exists.
If the variable is unset, the launcher skips all code-indexing checks and proceeds directly to the target AI tool.
# Enable launcher-side code indexing prompts for Claude launches
AMPLIHACK_ENABLE_BLARIFY=1 amplihack claude
# Generate native SCIP artifacts manually instead of waiting for the prompt
amplihack index-scip --project-path .
Artifact locations:
.amplihack/blarify.json— LadybugDB import input foramplihack index-code.amplihack/indexes/<language>.scip— per-language native SCIP artifacts fromamplihack index-scip.amplihack/graph_db— native code-graph store populated byindex-codeorindex-scip
Why it exists: Code-graph indexing is computationally expensive and should not run on every launch. This flag keeps the behavior opt-in so only projects that benefit from code-graph enrichment pay the cost.
AMPLIHACK_BLARIFY_MODE¶
Type: string
Values: skip | sync | background
Read by: commands::launch::blarify_mode()
Controls how launcher-side code indexing behaves once AMPLIHACK_ENABLE_BLARIFY=1 has opted the project in.
skip— suppress indexing work for this launchsync— run indexing in the foreground before launching Claudebackground— start indexing in the background and continue launching Claude immediately
If the variable is unset or has any other value, interactive launches fall back to the prompt flow and non-interactive launches do nothing.
# Always skip indexing for this launch
AMPLIHACK_ENABLE_BLARIFY=1 AMPLIHACK_BLARIFY_MODE=skip amplihack claude
# Force synchronous indexing before Claude starts
AMPLIHACK_ENABLE_BLARIFY=1 AMPLIHACK_BLARIFY_MODE=sync amplihack claude
# Allow non-interactive launches to queue background indexing
AMPLIHACK_ENABLE_BLARIFY=1 AMPLIHACK_BLARIFY_MODE=background amplihack claude --print 'summarize src'
Why it exists: Python session-start integration already used a skip / sync / background contract. Reintroducing the same lifecycle knob in Rust lets automated and non-interactive launches opt into indexing policy without waiting on a TTY prompt.
AMPLIHACK_NO_UPDATE_CHECK¶
Type: flag
Values: 1 (skip update check) — absence or any other value means check is enabled
Used by: update::should_skip_update_check(),
update::classify_skip_reason(),
freshness::skip_freshness_checks(). Also set to 1 on self-update subprocesses
by update::build_install_command / update::install as a recursion guard.
Permanently disables the update-check paths for every amplihack invocation:
- The pre-launch npm tool update check (notice for
claude,copilot,codexpackage versions). - The startup self-update prompt (
Update now? [y/N] (5s timeout):for theamplihackbinary itself). - The bundle freshness check (
skip_freshness_checks), so the same opt-out silences freshness warnings alongside the update checks.
Unlike AMPLIHACK_NONINTERACTIVE, this variable suppresses only the update
checks and has no effect on bootstrap prompts or interactive behaviour. Unlike
the subprocess-safe skip signals (CI, AMPLIHACK_AGENT_BINARY,
AMPLIHACK_NONINTERACTIVE, --subprocess-safe, non-TTY stdin), this variable
does not emit the amplihack: skipping update check (subprocess-safe / no
TTY) skip-line on stderr — the suppression is silent. Use this when you want
the pre-#625 silent-skip experience.
Equivalent to passing --skip-update-check on every invocation, but without
requiring the flag to be typed or aliased.
When to prefer this over AMPLIHACK_NONINTERACTIVE: Use
AMPLIHACK_NO_UPDATE_CHECK=1 when you want to silence the update banner on a
developer workstation while keeping interactive bootstrap prompts active. Use
AMPLIHACK_NONINTERACTIVE=1 in CI environments where all interactive output
should be suppressed.
AMPLIHACK_PARITY_TEST¶
Type: flag
Values: 1 (parity-test mode active) — absence or any other value has no effect
Used by: update::should_skip_update_check(),
update::classify_skip_reason()
Suppresses both update-check paths (pre-launch npm tool notice and startup
self-update prompt) without enabling full non-interactive mode. This is useful
for automation that compares command output against a known baseline, where
update-banner stderr output would create spurious differences. Suppression is
silent — the amplihack: skipping update check (subprocess-safe / no
TTY) skip-line introduced by issue #625
is not emitted, preserving byte-identical stderr against pre-#625 baselines.
Custom automation scripts that compare amplihack output against a known
baseline should also set this variable:
#!/usr/bin/env bash
# my-output-capture.sh
export AMPLIHACK_PARITY_TEST=1
actual=$(amplihack mode detect 2>&1)
expected="local"
[[ "$actual" == "$expected" ]] || { echo "FAIL: got $actual"; exit 1; }
Isolation contract: AMPLIHACK_PARITY_TEST=1 suppresses exactly one
behaviour: the update check. It does not propagate into the child tool process,
does not affect bootstrap logic, and does not change exit codes or stdout output.
AMPLIHACK_SKIP_AUTO_INSTALL¶
Type: flag
Values: any non-empty value (suppresses self-heal) — absence or empty string means the check runs
Used by: self_heal::ensure_assets_match_binary_version (via env_bypass_set)
Suppresses the startup-time self-heal check that runs before every
amplihack command dispatch. With the bypass active, amplihack does not
compare crate::VERSION to ~/.amplihack/.installed-version and does not
auto-run install when the stamp is missing or stale. Explicit amplihack install
invocations are unaffected.
When to set it:
- CI pipelines that pre-stage assets in a setup phase and then run many
amplihackcommands without wanting the binary to mutate~/.amplihackmid-run. - Unit/integration tests that stub out the framework asset tree and need to guarantee the binary will not overwrite it on first launch.
- Sandboxed parity test harnesses that already manage the
~/.amplihacklayout deterministically.
# CI: stage once, then run many commands without per-launch self-heal
amplihack install
export AMPLIHACK_SKIP_AUTO_INSTALL=1
amplihack claude --print 'run tests'
amplihack copilot --print 'run tests'
Truthiness: any non-empty value triggers the bypass (1, true,
yes, please-skip, etc.). An empty string (AMPLIHACK_SKIP_AUTO_INSTALL="")
is treated as unset and the check still runs.
Diagnostic on skip-with-mismatch: when the bypass is active and the
stamp does not match crate::VERSION, amplihack emits one line on stderr
before dispatch:
This makes the "stale assets, intentionally" state visible in CI logs. Matching versions produce no output.
What it does not do:
- Does not affect the existing
update::post_installhook fired byamplihack update. - Does not propagate into child tool processes (
claude,copilot, etc.) — inherited only because it is a normal env var, not becauseamplihackre-exports it. - Does not change exit codes, stdout output, or any other behaviour besides the self-heal decision.
See: Self-Heal: Auto-Restage Framework Assets.
AMPLIHACK_SKIP_MMDC¶
Type: flag
Values: any non-empty value (skips the attempt) — absence or empty string means the step runs
Used by: install::mermaid_cli::ensure_mermaid_cli (during amplihack install)
Disables the best-effort Mermaid CLI provisioning step in
amplihack install. When set to any non-empty value, the installer does not
probe for mmdc, does not probe for npm, and does not run
npm install -g @mermaid-js/mermaid-cli. The step resolves to SkippedByEnv
and prints one informational line. amplihack install otherwise proceeds
normally — this step is optional and never gates a successful install.
When to set it:
- Offline / air-gapped installs that must not reach npm or download the puppeteer/Chromium payload (hundreds of MB).
- Minimal containers or CI where local mermaid rendering is unnecessary and
the
pr-guidemermaid.inkfallback (or native Azure DevOps rendering) is acceptable. - Deterministic test harnesses that manage tool availability explicitly.
Truthiness: any non-empty value triggers the skip (1, true, yes,
etc.). An empty string (AMPLIHACK_SKIP_MMDC="") is treated as unset and
the step runs. This matches the presence-flag convention used by
AMPLIHACK_SKIP_AUTO_INSTALL.
See: Best-Effort Mermaid CLI Provisioning.
AMPLIHACK_TEST_FAKE_LATEST_VERSION¶
Type: version tag string (test-only)
Values: any version tag accepted by update::network::normalize_tag
(e.g. 99.99.99, v0.9.3); empty string is treated as unset.
Used by: update::network::fetch_latest_release()
Test-only short-circuit for the GitHub release lookup performed by the
startup self-update prompt. When set non-empty, fetch_latest_release
returns a synthetic UpdateRelease with the supplied tag and no network
call is made.
The synthetic release uses an asset_url on the allowlisted github.com
host and checksum_url=None, so any download path remains gated by the
existing URL allowlist and SHA-256 verification — the variable cannot be
used to redirect real downloads or bypass artifact verification. It exists
exclusively to drive the prompt code path deterministically from the
integration test suite at
bins/amplihack/tests/issue_625_update_prompt_subprocess_safe.rs.
# Force a "newer release available" outcome without a network call
AMPLIHACK_TEST_FAKE_LATEST_VERSION=99.99.99 amplihack copilot --help
Production deployments should not set this variable. It is documented for completeness only.
See: Startup Self-Update Prompt — Subprocess-Safe Skip.
CI¶
Type: flag (presence-based)
Values: any non-empty value (1, true, yes, anything) — empty string
or absence has no effect.
Used by: update::classify_skip_reason()
Conventional CI-runner marker recognised by amplihack as a subprocess-safe
signal. When set non-empty, the startup self-update prompt is skipped — the
Update now? [y/N] (5s timeout): line is never printed and stdin is never
read. A single skip-line amplihack: skipping update check (subprocess-safe /
no TTY) is emitted to stderr.
GitHub Actions, GitLab CI, CircleCI, Jenkins, Buildkite, and most other CI
runners set CI=true automatically, so this signal usually fires without any
explicit configuration.
# .github/workflows/agent.yml — CI=true is set automatically by the runner.
- run: amplihack copilot -p "Run the test suite"
Empty-string semantics: CI="" does not trigger skip. Only non-empty
values are recognised — matching the convention used by
commands::launch::command::resolve_subprocess_safe.
No effect on the npm pre-launch tool notice. That notice is non-blocking
and is suppressed by AMPLIHACK_NONINTERACTIVE /
AMPLIHACK_NO_UPDATE_CHECK instead. See Manage Tool Update
Notifications.
No effect on --subprocess-safe argv injection on the copilot
subcommand. That feature uses its own resolver (see
COPILOT_SUBPROCESS_SAFE.md); CI is one
of its signals as well, but the two paths are independent.
See: Startup Self-Update Prompt — Subprocess-Safe Skip.
UV_TOOL_BIN_DIR¶
Type: path
Used by: bootstrap.rs when installing amplifier
Override the directory where uv tool install places the amplifier binary. Defaults to ~/.local/bin.
IS_SANDBOX¶
Type: 1 to allow; 0 to refuse
Used by: every claude --dangerously-skip-permissions amplihack starts
(amplihack claude, recipe agent steps, the orchestration runner, the fleet
reasoner)
Claude Code refuses --dangerously-skip-permissions as root unless
IS_SANDBOX=1 is set. It accepts only the exact value 1. When amplihack runs
as root:
IS_SANDBOX=1, or a truthyCLAUDE_CODE_BUBBLEWRAP, is passed through.yes,true,onandyare passed toclaudeas1.0or any other value is never overridden, and amplihack fails before startingclaude.- Unset in a detected container (
CLAUDE_CODE_REMOTE=true,/.dockerenv,/run/.containerenv, or a container runtime in/proc/1/cgroup; the marker files count only outside WSL, which includes Docker Desktop containers on Windows, and only when/is PID 1's root, so not in achroot): amplihack setsIS_SANDBOX=1on theclaudechild only and prints a one-line notice on stderr. - Unset with no container detected: amplihack fails before starting
claude.
Not root: ignored. See Agent steps fail as root.
AMPLIHACK_TOPIC_NAME¶
Type: string
Values: any topic name — absence falls back to hive-graph
Used by: commands::hive_haymaker::run_hive_feed,
commands::hive_haymaker::run_hive_eval
Overrides the default hive event-bus topic name used by the hive feed and
hive eval commands. An explicit --topic CLI argument takes precedence; when
no argument is given, AMPLIHACK_TOPIC_NAME is consulted, and if it is unset the
topic defaults to hive-graph.
AMPLIHACK_PROJECT_ID¶
Type: string
Values: any project id — absence falls back to amplihack
Used by: amplihack_memory::cli_memory::learning
Sets the project id recorded on session-learning memory records. When unset, the
project id defaults to amplihack. Use this to segregate learned memories by
project.
Signal channel variables¶
These variables control the optional Signal channel (feature signal). They are
read only when the channel is active and, unlike the launcher variables above,
are documented authoritatively — with their TOML equivalents — in the
Signal channel reference. The two variables
below govern group strategy. The channel's default is per-session
groups: every amplihack session creates its own fresh Signal group
(amplihack-<session-id>-<unix-ts>) and leaves it at Stop, so no session can see
another session's messages. Reusing a single shared "rolling" group is strictly
opt-in.
AMPLIHACK_SIGNAL_REUSE_ROLLING_GROUP¶
Type: boolean (truthy: 1, true, yes, on)
TOML key: reuse_rolling_group
Default: false (per-session groups)
Read by: amplihack_signal::config::SignalConfig
Opt-in switch for sharing one long-lived group across every session. When truthy,
amplihack reuses the group named by AMPLIHACK_SIGNAL_ROLLING_GROUP_ID and does
not quit it at Stop, giving one persistent operator thread. When unset,
empty, or an explicit false value (0, false, no, off), the channel
resolves fail-closed to the per-session default — never to shared
visibility. Unknown non-empty tokens are rejected so typos are visible. A truthy
value without a non-empty AMPLIHACK_SIGNAL_ROLLING_GROUP_ID is rejected so
rolling mode cannot create an untracked group. Like every Signal setting, the
environment variable overrides the TOML key of the same name.
AMPLIHACK_SIGNAL_ROLLING_GROUP_ID¶
Type: string (signal-cli group id)
TOML key: rolling_group_id
Default: unset
Read by: amplihack_signal::config::SignalConfig
Binds rolling reuse to an existing group id. Only consulted when
AMPLIHACK_SIGNAL_REUSE_ROLLING_GROUP is truthy; it is ignored while the
per-session default is in effect. Setting this alone does not enable sharing
— both the opt-in flag and this id are required for a shared rolling group.
Related¶
- Agent Binary Routing — Why
AMPLIHACK_AGENT_BINARYexists and how recipe runner uses it - Run amplihack in Non-interactive Mode — CI and pipe usage guide
- Bootstrap Parity — How the Rust CLI matches the Python launcher's environment contract
- Memory Backend Reference —
AMPLIHACK_MEMORY_BACKENDvalues, storage paths, schema, and security - Signal Channel — Full reference for the Signal channel, including the per-session-default group strategy and the opt-in rolling-group variables
- Recipe Runner Logging — Progress, heartbeat, snippet, and JSONL configuration
- amplihack install — Variables read during installation
- Startup Self-Update Prompt — Subprocess-Safe Skip — How
CI,AMPLIHACK_AGENT_BINARY,AMPLIHACK_NONINTERACTIVE,--subprocess-safe, and non-TTY stdin each suppress theUpdate now? [y/N] (5s timeout):prompt - Manage Tool Update Notifications — npm pre-launch tool update notice (separate code path)