taloncjones

dotfiles-config-and-flags

Catalog of every environment variable, script flag, and config knob in this dotfiles repo -- consumer, default, effect, and whether it is production, test-only, or emergency-bypass. Load when asking "what does VAR do", "is there a flag for X", "how do I skip a hook", "what reads CLAUDE_CONFIG_DIR / CLAUDE_CODE_REMOTE / GSD_HOOK_REPAIR" (the retired ECC's `ECC_VENDOR_LANGS` no longer exists), "why is --local ignored", "what keys does settings.json.tmpl own", or before adding a new flag. NOT for diagnosing breakage (dotfiles-debugging-playbook), running the update/plugin lifecycle (dotfiles-run-and-operate), platform semantics of the vars Claude Code itself defines (claude-code-platform-reference), or recreating a machine (dotfiles-build-and-env).

taloncjones 0 Updated 3d ago
GitHub

Install

npx skillscat add taloncjones/dotfiles/dotfiles-config-and-flags

Install via the SkillsCat registry.

SKILL.md

Dotfiles Config and Flags

Every configuration axis in this repo, as tables: environment variables the
repo's own code consumes, flags accepted by its scripts and functions, and
edit-in-file knobs. Each entry names the consumer (file + function), the
default, the effect, and its class -- production, test-only, internal, or
emergency-bypass. Verified against the working tree on 2026-07-02.

[WARNING] The bypass variables (DOTFILES_SKIP_COMMIT_MSG_GUARD, ECC_SKIP_GIT_HOOKS, ECC_SKIP_PRECOMMIT, ECC_SKIP_PREPUSH -- named for the retired ECC, whose hooks they still gate) exist for
emergencies (a hook itself is broken, or you are committing the fix to a hook
that blocks its own diff). They are not a normal-workflow tool: routing around
the guard hooks to land content they would block violates the repo's change
gates. State in the commit/PR why a bypass was used.

[WARNING] Several ALL-CAPS names that look like env vars are NOT overridable
from the environment: zsh/functions.zsh assigns them unconditionally at
source time (plain VAR=value, no ${VAR:=...}), so an exported value is
clobbered when the shell starts. They are edit-in-file knobs. Marked
"edit-in-file" below.

When NOT to use this skill

You actually want Use instead
Something is broken and you need triage dotfiles-debugging-playbook
Day-to-day update/plugin/repair operations dotfiles-run-and-operate
How Claude Code itself treats config dirs, plugins, hooks, cloud containers claude-code-platform-reference
Fresh-machine or cloud-container setup dotfiles-build-and-env
Why a design decision exists (two config dirs, seed-once settings) dotfiles-architecture-contract
Prove a var actually took effect (symlink/plugin/identity/hook checks) dotfiles-verification-toolkit

Definitions

  • Config dir: a Claude Code state directory (~/.claude personal,
    ~/.claude-work work), selected by CLAUDE_CONFIG_DIR.
  • Guard hook: a Python script in claude/hooks/ registered in
    claude/settings.json.tmpl; exit 2 blocks the tool call.
  • Git hook: a script in git/hooks/, active via
    core.hooksPath=~/.config/git/hooks.
  • ECC: the retired "Everything Claude Code" plugin (formerly ecc@ecc, from github.com/affaan-m/ECC), retired 2026-09; no variant is installed and no
    install path remains -- ecc-uninstall tooling only. GSD: "Get Shit
    Done", retired npm tool; no variant is installed and no install path
    remains -- uninstall tooling only.
  • Edit-in-file: change by editing the assignment in the repo and reloading,
    not by exporting.

Environment variables -- production runtime

Var Consumer Default Effect Class
DOTFILEDIR Everything: zsh/aliases.zsh, zsh/functions.zsh, all install/ scripts, bootstrap-cloud.sh Computed Absolute path to this repo. Set three independent ways: interactive shells by the symlink-resolving block in zsh/.zshrc (DOTFILEDIR="$(dirname "$ZSHDIR")", exported, then $DOTFILEDIR/bin goes on PATH); install scripts by sourcing install/common/resolve_dotfiledir.sh; bootstrap-cloud.sh computes its own at the top. Do not hand-set; a wrong value silently retargets every symlink and function production (derived)
CLAUDE_CONFIG_DIR _claude_config_dir() + claude() wrapper in zsh/claude-account.zsh; claude/hooks/account_guard.py; claude/statusline.js (process.env.CLAUDE_CONFIG_DIR); bin/identity-doctor; set per-invocation by sweep_retired_claude_plugins (install/common/claude-links.sh) unset (Claude Code then uses ~/.claude) Claude Code's native account-isolation var. A pre-set value ALWAYS wins over directory-based routing -- identity-doctor warns when it is exported in your shell. The sweep sets it per CLI call, and unsets it for ~/.claude production
CLAUDE_WORK_CONFIG_DIR Assigned ${CLAUDE_WORK_CONFIG_DIR:-$HOME/.claude-work} in zsh/claude-account.zsh; read from env with the same default by account_guard.py ~/.claude-work Which config dir the work account lives in. The zsh assignment uses parameter-expansion defaulting, so a pre-set exported value is honored (not clobbered) by both the wrapper and the Python hook production
CLAUDE_WORK_TREE Assigned ${CLAUDE_WORK_TREE:-$HOME/Git/work} in zsh/claude-account.zsh; read from env with the same default by account_guard.py and bin/identity-doctor ~/Git/work Directory subtree that routes claude launches to the work account (symlinks resolved on both sides via zsh :A); a pre-set exported value is honored, not clobbered production
OP_ENV_FILE bin/op-env (locate, sign); exported by op-env shell-exports unset (then op.env at the main checkout root) Path of the project's op.env; op-env-sign reads the token file through it, never the token from the environment production
OP_ENV_ACTIVE bin/op-env status; scrubbed by bin/dotfiles-tests unset 1 in a launch that evaluated op-env shell-exports internal (do not set)
OP_ENV_OP_TIMEOUT bin/op-env 20 Seconds bound on each op call (timeout, gtimeout, else perl alarm) production
OP_ENV_SIGNING_SOCK bin/op-env ~/.local/state/dotfiles/op-env-signing.sock Socket of the plain ssh-agent that holds the signing key; also a test seam production
OP_SERVICE_ACCOUNT_TOKEN, OP_SIGNING_KEY, OP_SIGNING_PUBKEY, OP_SIGNING_TTL op.env keys, read by bin/op-env and written by bin/setup-op; never exported none, none, none, 1h Service-account token; op://VAULT/ITEM of the SSH signing key; its public key; ssh-add -t lifetime production
OP_ENV_ALLOW op.env key, read by bin/op-env and kept across --rotate and --signing-key by bin/setup-op; never exported none Comma-separated uppercase names that project.env may use beyond the _TOKEN, _KEY, _SECRET, _PASSWORD, _PAT suffix rule; the reserved floor names stay refused production
ANTHROPIC_DEFAULT_OPUS_MODEL Claude Code model alias resolution; set through env in claude/settings.json.tmpl unset (deliberately) Pins the opus alias and the plan-mode half of opusplan to one model ID. Left unset so the alias tracks the newest Opus release; reconcile_claude_settings_file sweeps any ANTHROPIC_DEFAULT_<FAMILY>_MODEL the template does not define, because a stale pin would otherwise survive the env union forever. The same applies to the SONNET, HAIKU, and FABLE variants production
ZSH_CACHE_DIR ecc-uninstall, gsd-uninstall in zsh/functions.zsh fallback ~/.cache/zsh Where the retired 14-day "Stale: ecc" shell nag (_claude_plugin_epoch_write()/_claude_plugin_check_update(), both removed 2026-09) used to write its .ecc-update staleness stamp; that leftover stamp is now only removed, by ecc-uninstall. A legacy .gsd-update stamp has no writer anymore and is only removed there by gsd-uninstall. Set by oh-my-zsh, not by this repo; every repo consumer supplies the fallback production (external)
XDG_CACHE_HOME _claude_code_update_check() in zsh/functions.zsh fallback ~/.cache Base for the 24h-cached Claude Code CLI update check ($XDG_CACHE_HOME/dotfiles/claude-code-update-check) production (external)
XDG_CONFIG_HOME install/common/herdr_manifest.py fallback ~/.config Base for the generated herdr override $XDG_CONFIG_HOME/herdr/agent-detection/claude.toml production (external)
XDG_STATE_HOME install/common/herdr_manifest.py fallback ~/.local/state Base for herdr's cached remote manifest $XDG_STATE_HOME/herdr/agent-detection/remote/claude.toml, the generator's input production (external)
JIRA_URL Referenced in claude/global-instructions.md PR/plan templates; cached by claude/hooks/cache_jira_url.py from Atlassian MCP results unset Jira base URL for PR links and plan headers. The hook derives it from MCP traffic; not a var you export production (derived)
ZSH_CUSTOM install/install.sh (oh-my-zsh plugin clones) fallback ~/.oh-my-zsh/custom Where zsh-autosuggestions / zsh-syntax-highlighting get cloned during install. Set by oh-my-zsh, not by this repo; the installer supplies the fallback production (external)

Workflow launchers also bind WORKFLOW_PERSONAL_ACCOUNT=1 for a selected
personal account. This internal selector is consumed by
claude/skills/lib/workflow_context.py and unset when reusing a pane for a
work/custom account. It preserves work repository plugin preferences, unlike
the machine-wide CLAUDE_PERSONAL_ONLY=1 policy. Do not set it globally.

Environment variables -- platform-provided (cloud containers)

Set by the claude.ai/code platform, never by you. Full platform semantics:
claude-code-platform-reference.

Var Consumer Value Effect Class
CLAUDE_CODE_REMOTE .claude/hooks/session-start.sh (!= "true" -> exit 0) true in cloud containers, unset on real machines Gates the SessionStart self-heal: only in a cloud container does the hook run bootstrap-cloud.sh. On a real machine the hook is a no-op BY DESIGN production
CLAUDE_PROJECT_DIR .claude/hooks/session-start.sh (repo root, with a BASH_SOURCE fallback); the hook command string in .claude/settings.json repo checkout root Lets the committed hook registration find the repo without hardcoded paths production

Environment variables -- git hook behavior and bypass

All consumed by scripts in git/hooks/ (active via
core.hooksPath=~/.config/git/hooks -> $DOTFILEDIR/git/hooks).

Var Consumer Default Effect Class
DOTFILES_SKIP_COMMIT_MSG_GUARD git/hooks/commit-msg (first check) 0 =1 skips the attribution/emoji commit-message guard for one commit: DOTFILES_SKIP_COMMIT_MSG_GUARD=1 git commit ... emergency-bypass
ECC_SKIP_GIT_HOOKS git/hooks/pre-commit AND git/hooks/pre-push (first check in each) 0 =1 skips BOTH hooks (derived from the retired ECC: secret scan pre-commit, verification pre-push) emergency-bypass
ECC_SKIP_PRECOMMIT (retired-ECC name) git/hooks/pre-commit 0 =1 skips only pre-commit emergency-bypass
ECC_SKIP_PREPUSH (retired-ECC name) git/hooks/pre-push 0 =1 skips only pre-push emergency-bypass
GSD_HOOK_REPAIR git/hooks/post-checkout 0 =1 = maintenance mode: replaces wrong-shape .todos / .planning/* entries in a worktree with the canonical symlinks to main. Without it the hook only WARNs production (maintenance)
GSD_HOOK_ISOLATE git/hooks/post-checkout 0 =1 = workspace mode: converts leftover maintenance symlinks (writes would leak to main) into per-worktree copies seeded from main production (maintenance)
ECC_PREPUSH_AUDIT (retired-ECC name) git/hooks/pre-push 0 =1 adds a dependency audit (npm audit --omit=dev or equivalent for the detected package manager) to the pre-push verification flow production (opt-in)

File-based gates (no env var, retired-ECC naming): a .ecc-hooks-disable or .git/ecc-hooks-disable file in a repo disables pre-commit and pre-push for
that repo entirely. Same bypass caveat as above. Both hooks self-skip when the
repo is not a work tree. The rg-absence self-skip (with a printed notice)
exists ONLY in git/hooks/commit-msg; pre-push never invokes rg, and
[WARNING] pre-commit's secret scan silently finds NOTHING when rg is
missing (the rg call sits inside an if-condition with stderr discarded) --
silent degradation, not a documented skip.

Environment variables -- plugin, vendoring, and tool knobs

Var Consumer Default Effect Class
ECC_REPO_URL (retired, variable removed) was ecc-install in zsh/functions.zsh; also an independent copy in bootstrap-cloud.sh N/A Retired along with ecc-install/ecc-update (2026-09); no longer defined anywhere retired
ECC_REPO_DIR ecc-uninstall only in zsh/functions.zsh (retired) ~/Git/personal/ECC Local clone of the retired ECC -- ecc-uninstall sweeps it; the ecc-update hard-reset that used to refresh it is gone. Edit-in-file production
GSD_REDUX_PKG _gsd_run() in zsh/functions.zsh @opengsd/get-shit-done-redux@latest Referenced only so gsd-uninstall can run the official npx uninstaller -- the install path is removed and no GSD variant is sanctioned. The original get-shit-done-cc is compromised (token rug-pull, commit 9ad4dc8 retirement); gsd-uninstall purges it. Edit-in-file production
PLUGIN_RETRIES / PLUGIN_RETRY_MAX_DELAY ensure_plugin() in bootstrap-cloud.sh 8 / 15 (seconds) Retry budget for cloud plugin installs. The cap is load-bearing: uncapped doubling could blow the Setup script's ~5-minute limit (commit da54e17). Edit-in-file constants, not env production

GATEGUARD_BASH_ROUTINE_DISABLED and GATEGUARD_EXEMPT_GLOBS (the retired ECC GateGuard hook's tuning knobs) are gone: both keys were removed from claude/settings.json.tmpl along with the rest of the retired ECC (2026-09).

Environment variables -- test-only

Used to make test suites deterministic. Never set in production.

Var Consumer Default Effect
TODOS_TODAY today() in claude/skills/todos/scripts/todos.sh $(date +%Y-%m-%d) Pins "today" for date-relative todo logic; used by todos_test.sh
TODOS_REGISTRY registry_file() in claude/skills/todos/scripts/todos.sh ~/.claude/todos/repos.txt Repo-registry file location; tests point it at a temp file
WS_GH_CAP ws_gather_github() in claude/skills/lib/work-state.sh 200 Per-query gh pr list --limit; results at the cap set truncated:true. Tests set WS_GH_CAP=1
GH claude/skills/lib/work-state.sh (: "${GH:=gh}") gh Path to the gh binary; tests substitute a stub
SWEEP_TEST_BEFORE_RECHECK sweep_retired_claude_plugins prune in install/common/claude-links.sh unset A shell command run with sh -c after the prune writes its temp file and before it re-reads the registry, so install/claude-links.test.sh can simulate a concurrent writer

Environment variables -- internal (do not set)

Var Where Effect
BREW_FAILED Set/exported in install/macos/macos.sh and install/linux/linux.sh when brew bundle fails; read at the end of install/install.sh Defers the "some brew packages failed" warning to the end of the install instead of aborting it
NO_PLUGINS Internal to bootstrap-cloud.sh arg parsing Backing variable for --no-plugins; use the flag
LAZYGIT_NEW_DIR_FILE Exported by lg() in zsh/functions.zsh Handshake file lazygit writes its exit directory to so lg can cd after it quits

Environment variables -- machine-local device file

zsh/scripts/airpods.zsh and zsh/scripts/raycast/bt.sh source
~/.config/dotfiles/devices.zsh (machine-local, never committed) for:

Var Effect
AIRPODS_MAC Bluetooth MAC for the AirPods connect/disconnect helpers (blueutil --paired to find it)
MOUSE_MAC Bluetooth MAC for the mouse toggle in the Raycast script

Missing file -> the scripts print an [INFO] pointing here; nothing breaks.

Script and function flags

Command Flags Notes
bootstrap-cloud.sh --no-plugins Skip plugin installs (used by the smoke test; useful offline). Any other arg exits 2
bin/dotfiles-tests --list Print the suites without running. No other flags
claude() wrapper (zsh/claude-account.zsh) --personal Force the personal config dir from inside ~/Git/work; stripped, NOT forwarded to the CLI. All other args forwarded verbatim
gsd-uninstall -l/--local, -g/--global, --claude, --codex Parsed by _gsd_parse_args(). Default: global scope, both runtimes when the codex CLI exists (else Claude only). gsd-install/gsd-update were removed when GSD was fully retired
bootstrap.sh, install/install.sh, bin/identity-doctor, bin/identity-setup, bin/dotfiles-repair none No argument parsing; run bare

Why Claude plugins ignored --local: Historical, now retired -- the
retired Superpowers and ECC install functions (both retired 2026-09) accepted
-l/--local/-g/--global for muscle-memory compatibility with GSD's shared
parser, printed [WARNING] ... global-only; ignoring --local., and proceeded
globally into BOTH config dirs. Claude Code plugins install into a config dir
(claude plugins install under a CLAUDE_CONFIG_DIR), which is per-ACCOUNT
state -- there was no per-project plugin install for those functions to
target. The -l/--local spelling remains in the shared parser only because
GSD genuinely supports it (its installer writes ./.claude / ./.codex in
the current directory); no plugin install function reads it any more.

Config knobs (edit-in-file)

ECC rules vendoring -- RETIRED (2026-07-02, ahead of ECC's own 2026-09 retirement)

ECC_VENDOR_LANGS and ecc-sync-rules no longer exist, and neither does the rest of the retired ECC or its marketplace clone. Any language dirs left under claude/rules/ from an older machine are inert leftovers to delete by hand (the ecc-install/ecc-update functions that used to print the removal command are themselves retired).

settings.json key ownership

Two different settings files; do not conflate them:

File Role Owner of keys
claude/settings.json.tmpl Template seeded to ~/.claude/settings.json and ~/.claude-work/settings.json, then reconciled on every install/update; machine copies remain real files Dotfiles owns model (a config dir's machine-local settings.override.json may override it), env, permissions, hooks, statusLine, tui. Plugin installers write enabledPlugins and extraKnownMarketplaces into the MACHINE copies (never edit those two by hand there)
.claude/settings.json (repo-committed) enabledPlugins pins Superpowers off (retired 2026-09; ECC retired 2026-09 too), and the SessionStart hook registration runs bootstrap-cloud.sh for assets, settings and git identity Dotfiles owns all of it; no plugin declaration remains, since none is installed in cloud any more

Template tui=fullscreen keeps both accounts on one layout: the herdr-fleet
pane docks beside the transcript and auto-opens only in fullscreen.

Template env block sets a telemetry knob for every session:
CLAUDE_CODE_DISABLE_TELEMETRY=1 (Claude Code CLI). It previously also set
ECC_CONTEXT_MONITOR_COST_WARNINGS=0 for the now-retired ECC plugin; that
key is gone. The top-level
model=fable[1m] is the default for new sessions: family aliases
(fable, opus, sonnet, haiku, optionally suffixed [1m]) resolve to the
newest release of that family, so no session setting names a model version.
A config dir that needs a different default (for example the work account on
opus) keeps an owner-created, untracked <config-dir>/settings.override.json
such as {"model":"opus"}; the reconcile honours its model only, warns on
anything else, and never creates the file.

reconcile_claude_settings_file in install/common/claude-links.sh propagates
template-owned keys to existing machine settings on every install/update while
unioning plugin keys with live state winning. Cloud delegates to the same
reconciler. claude/hooks/claude-hooks.test.sh drift-checks both machine
copies.

Statusline

statusLine in claude/settings.json.tmpl runs
node ~/.claude/statusline.js. The script reads CLAUDE_CONFIG_DIR (falls
back to ~/.claude) so the work account renders its own state. No statusline
= usually node missing (bootstrap-cloud.sh warns about exactly this).

How to add a flag or env var (checklist)

  • Name it: DOTFILES_* for repo-wide behavior, tool prefix (ECC_* -- retired, surviving only on git-hook bypass vars --, GSD_*, TODOS_*, WS_*) for a subsystem. ALL_CAPS, underscores.
  • One consumer reads it with an explicit default:
    "${MY_VAR:-default}" -- never bare $MY_VAR under set -u.
  • Decide the class: production, test-only, or bypass. A bypass flag must
    default to OFF and print nothing when unset.
  • If it must be env-overridable from zsh, use : "${VAR:=default}"
    (see GH in claude/skills/lib/work-state.sh) or the equivalent
    VAR="${VAR:-default}" form (see CLAUDE_WORK_CONFIG_DIR/
    CLAUDE_WORK_TREE in zsh/claude-account.zsh), NOT a plain
    assignment (which clobbers exports -- see warning at top).
  • Document the flag in the consumer's header comment (house pattern:
    bootstrap-cloud.sh "Flags:" block, post-checkout header).
  • Test it: extend the matching suite (bin/dotfiles-tests --list for the
    inventory; todos_test.sh and test_work_state.sh show the env-injection
    pattern; post-checkout.test.sh shows the grep-the-gate pattern).
  • Add a row to THIS skill and to dotfiles-validation-and-qa if a new
    suite appeared.
  • Run bin/dotfiles-tests before committing.

Provenance and maintenance

All facts verified against the working tree on 2026-07-02 (baseline: all nine
test suites passing; bin/dotfiles-tests and CI added same day, commit
465ee17; the retired Superpowers install path's marketplace-by-URL fix
landed as commit 5b799dd, before its 2026-09 retirement).
Line numbers avoided above in favor of function/file anchors because they
drift. Re-verify before trusting:

Run everything below from the repo checkout root ($DOTFILEDIR in interactive
shells; if unset, substitute your checkout path -- canonical machine path
~/Git/personal/dotfiles, cloud containers use the platform checkout):

# Whole-catalog sweep: ALL-CAPS tokens consumed by repo scripts. NO extension
# filter -- the git hooks (git/hooks/{commit-msg,pre-commit,pre-push,post-checkout})
# and the bin/ scripts are extensionless and would be silently skipped by
# --include='*.sh'-style filters.
grep -rn -oE '\$\{?[A-Z][A-Z0-9_]{2,}\}?' \
  . --exclude-dir=.git --exclude-dir=node_modules \
  | grep -oE '[A-Z][A-Z0-9_]{2,}' | sort -u
# Interpretation: hits with the documented prefixes (DOTFILES_, CLAUDE_,
# ECC_ -- retired, only the git-hook bypass vars remain --, GSD_, TODOS_, WS_, PLUGIN_) that are absent from this file mean the catalog
# has drifted. Other hits are mostly single-script internal locals (BAD, CFG,
# OUT, ...) and are EXPECTED to be absent; investigate only ones you do not
# recognize.

# Per-var consumer check (substitute any var name)
grep -rn 'CLAUDE_CODE_REMOTE' . --exclude-dir=.git

# Bypass gates still where documented (ECC_* names survive only here; ECC itself is retired)
grep -n 'DOTFILES_SKIP_COMMIT_MSG_GUARD' git/hooks/commit-msg
grep -n 'ECC_SKIP' git/hooks/pre-commit git/hooks/pre-push  # retired-ECC naming
grep -n 'GSD_HOOK_REPAIR\|GSD_HOOK_ISOLATE' git/hooks/post-checkout
grep -n 'ECC_PREPUSH_AUDIT' git/hooks/pre-push  # retired-ECC naming

# Flags still as documented
grep -n 'no-plugins' bootstrap-cloud.sh
grep -n -- '--list' bin/dotfiles-tests
grep -n '_claude_plugin_scope\|_gsd_parse_args' zsh/functions.zsh

# Edit-in-file knob values (ECC_REPO_URL is gone -- retired with ECC itself)
grep -n 'ECC_REPO_DIR=\|GSD_REDUX_PKG=' zsh/functions.zsh  # ECC_REPO_DIR: ecc-uninstall only, retired
grep -n 'PLUGIN_RETRIES=\|PLUGIN_RETRY_MAX_DELAY=' bootstrap-cloud.sh

# settings ownership + statusline
grep -n '"env"\|statusLine\|enabledPlugins' claude/settings.json.tmpl .claude/settings.json

Volatile facts most likely to drift: the plugin retry constants, the template
env keys, and the test-suite count (bin/dotfiles-tests --list). Upstream
URLs pinned as of today:
https://github.com/anthropics/claude-plugins-official.git,
@opengsd/get-shit-done-redux on npm (the retired ECC's https://github.com/affaan-m/ECC.git is no longer pinned anywhere).