Troubleshooting & common HALTs

This page enumerates the most common error / HALT messages produced by GAIA skills, their canonical workarounds or fixes, and the framework environment variables that operators reach for to debug or unblock a run.

Common HALTs and their workarounds

compliance.ui_present=true but no threat-model.md found (greenfield UI project)

Surface: /gaia-create-arch setup.sh exits 1 in Phase 3 (before any sprint exists).

Cause: The threat-model gate fires whenever compliance.ui_present: true in .gaia/config/project-config.yaml, but on a greenfield project threat-model.md is produced AFTER architecture by design. The advertised --bypass gaia-threat-model --reason "<text>" flag requires a resolvable SPRINT_ID, which doesn't exist pre-sprint-plan — a chicken-and-egg block.

Fix landed: The gate now degrades to a WARNING in the pre-sprint phase (no .gaia/state/sprint-status.yaml, no SPRINT_ID env), and the hard die only fires once a sprint is active — at which point --bypass is also recordable. Upgrade to v1.180.4+ if you still hit this on a fresh project. As a one-off workaround on older versions: export GAIA_STRICT_LIFECYCLE=0 for the single invocation (but this disables every strict-lifecycle gate, not just this one — surgical, not preferred).

HALT: no non-empty test-plan artifact found (post-/gaia-test-strategy)

Surface: /gaia-create-epics setup.sh.

Cause: /gaia-test-strategy --plan writes test-strategy.md under .gaia/artifacts/planning-artifacts/ (the canonical location), and also writes a sibling test-plan.md alias there. On older plugin versions create-epics setup.sh referenced an unbound ${PLANNING_ARTIFACTS} variable and looked only under test-artifacts/ — false HALT.

Fix landed: create-epics setup.sh routes through the shared resolve-artifact-path.sh test_plan helper which puts .gaia/artifacts/planning-artifacts/ at rung 1. Upgrade and retry.

traceability-matrix.md not found at .gaia/artifacts/test-artifacts/strategy/...

Surface: /gaia-dev-story traceability gate.

Cause: /gaia-trace on a greenfield project writes the matrix to the canonical .gaia/artifacts/planning-artifacts/traceability-matrix.md. Older dev-story setup.sh only checked test-artifacts/strategy/ — false HALT.

Fix landed: dev-story setup.sh routes through the shared resolver. Upgrade and retry.

WARNING: story 'X' has sprint_id 'sprint-N' but sprint-status.yaml is missing at ./.gaia/artifacts/implementation-artifacts/sprint-status.yaml

Surface: every /gaia-dev-story transition.

Cause: The canonical home for sprint-status.yaml is .gaia/state/ (the mutable-runtime-state tier). Older transition-story-status.sh hardcoded .gaia/artifacts/implementation-artifacts/ as its default lookup — every transition WARNed and the yaml surface was silently NOT updated.

Fix landed: transition-story-status.sh routes through resolve-artifact-path.sh sprint_status. Upgrade. On older versions, recover state with sprint-state.sh reconcile --sprint-id sprint-N after the fact.

HALT: retro finalize gate sentinel missing — Step 7 (Val sidecar write) must run before finalize

Surface: /gaia-retro finalize.sh under GAIA_FINALIZE_SENTINEL_REQUIRED=1 (default in CI).

Cause: Step 7 (Val sidecar write via val-sidecar-write.sh) is REQUIRED before finalize — it's not optional. The retro skill cannot complete without it.

Fix: Re-run /gaia-retro and let Step 7 execute. Do NOT skip it. See the retro page's Step 7 detail.

payload agent 'gaia:validator' must be 'val'

Surface: /gaia-sprint-review write-val-sentinel.sh.

Cause: The sentinel payload's .agent field must be the literal string "val" (the persona identifier) — NOT the subagent registration name "gaia:validator". The orchestrator MUST set or normalize this before piping the payload.

Fix: Before write-val-sentinel.sh, pipe the Val return through jq '. + {agent: "val"}' (or set it manually in the dispatch wrapper).

auto-rename-migration.sh: HALT: non-interactive auto-rename migration requires --force AND GAIA_MIGRATE_ALLOW_FORCE=1

Surface: /gaia-config-ci auto-rename pass under GAIA_NONINTERACTIVE=1.

Cause: Defense-in-depth for the file-rename security control. Either env var alone is insufficient.

Fix: Pass BOTH --force AND GAIA_MIGRATE_ALLOW_FORCE=1 in the same invocation. Or run interactively (drop GAIA_NONINTERACTIVE).

Statusline doesn't reflect my plugin update

Surface: after running /plugin update, the statusline keeps showing old behavior (no gradient, missing rate-limit countdown, missing dirty-file counts, etc.).

Cause: Plugin updates refresh the cache at ~/.claude/plugins/cache/gaiastudio-ai-gaia-framework/gaia/<version>/, not the standalone runtime install at ~/.claude/gaia-statusline/. The self-heal block lets the install re-copy itself from cache on each render — but the FIRST upgrade onto a pre-self-heal runtime has to be bootstrapped manually.

Fix (one-time per machine):

bash "$(ls -td ~/.claude/plugins/cache/gaiastudio-ai-gaia-framework/gaia/*/scripts/install-statusline.sh | head -1)"
ls -1 ~/.claude/plugins/cache/gaiastudio-ai-gaia-framework/gaia/ | sort -V | tail -1 \
  > ~/.claude/gaia-statusline/.installed-version

After this single run, every future /plugin update self-heals automatically.

Environment variable overrides (operator escape hatches)

These environment variables modify framework behavior for debugging, automation, or one-off bypass. They are intentionally documented here in one place — most are not surfaced on individual command pages.

Variable Effect Where it's read
GAIA_YOLO_FLAG=1 Enables YOLO mode for the current invocation — auto-selects defaults, auto-continues template-output prompts, never auto-bypasses hard gates (Val CRITICAL, 3-attempt fix cap). yolo-mode.sh, consumed by every skill that declares yolo_steps.
GAIA_YOLO_MODE=1 Inherited form for subagent dispatch — set automatically by parent skills when YOLO is active. Treat as read-only. yolo-mode.sh.
GAIA_STRICT_LIFECYCLE=0 Disables ALL strict-lifecycle gates globally (every prerequisite enforcer degrades to WARNING). Very coarse — prefer per-skill --bypass <skill> --reason when possible. lifecycle-strict-mode.sh (consumed by every setup.sh with a strict gate).
GAIA_NONINTERACTIVE=1 Indicates the run has no TTY. The auto-rename security control requires --force AND GAIA_MIGRATE_ALLOW_FORCE=1 on top of this. auto-rename-migration.sh.
GAIA_FINALIZE_SENTINEL_REQUIRED=1 Default ON in CI and most production configs. Makes the Val sidecar write a hard precondition for finalize on every skill that has a sentinel contract (retro, sprint-review, add-feature, etc.). Each skill's finalize.sh.
GAIA_TEST_STRATEGY_NO_AUTOSTUB=1 Disables the auto-stub hydration in /gaia-test-strategy/finalize.sh (which adds empty test_execution + test_execution_bridge stubs to project-config.yaml when missing). Set when you want explicit control of the config. gaia-test-strategy/scripts/finalize.sh.
PROJECT_PATH / GAIA_PROJECT_ROOT / PROJECT_ROOT Project-root override for runtime scripts (used by fixtures and out-of-CWD invocations). Resolution order: CLAUDE_PROJECT_ROOT → GAIA_PROJECT_ROOT → PROJECT_ROOT → PROJECT_PATH → PWD. resolve-artifact-path.sh, sprint-state.sh, dashboards, statusline.
SPRINT_STATUS_YAML=<path> Pin the sprint-status.yaml lookup to an explicit path (bypasses the canonical resolver). Used by bats fixtures. sprint-state.sh, sprint-status-dashboard.sh, transition-story-status.sh.
CI_SETUP_ARTIFACT=<path> Pin the ci-setup.md artifact lookup. By default, when unset, finalize.sh defaults to .gaia/artifacts/test-artifacts/ci-setup.md via the shared resolver — checklist actually runs (was silently skipped pre-fix). gaia-ci-setup/scripts/finalize.sh.

Canonical path cheat-sheet

If a script or doc still says one of the legacy paths on the left, treat that as drift. The canonical paths are on the right.

LegacyCanonicalWhat lives here
docs/planning-artifacts/.gaia/artifacts/planning-artifacts/PRD, architecture, epics-and-stories, threat-model, infrastructure-design, traceability-matrix, test-strategy, test-plan, action-items (write target only — see state tier).
docs/implementation-artifacts/.gaia/artifacts/implementation-artifacts/Story files (per-epic epic-{slug}/{key}-{slug}/story.md), review reports, retros, sprint reviews, sprint archives.
docs/test-artifacts/.gaia/artifacts/test-artifacts/ci-setup.md (only). NOTE: test-plan.md, test-strategy.md, traceability-matrix.md moved OUT of here to planning-artifacts/.
docs/creative-artifacts/.gaia/artifacts/creative-artifacts/Brainstorms, product briefs.
docs/implementation-artifacts/sprint-status.yaml.gaia/state/sprint-status.yamlMutable runtime state — separate "state tier". NOT under artifacts/.
_memory/.gaia/memory/Sidecar decision logs, checkpoints, lifecycle events.
config/.gaia/config/project-config.yaml, test-environment.yaml, test-environment.yaml.example.

Platform requirements

GAIA's orchestration + adapter scripts run on macOS, Linux, and Windows. The portability matrix below documents what each platform needs for a clean lifecycle run.

macOS

  • Bash: macOS ships /bin/bash 3.2.57 as the system default. The deterministic-tools chain (detect-signals.sh, brownfield orchestrator.sh, validate-platform-stack.sh, the dead-code + grype/syft adapters) is bash-3.2 compatible. Bash 4.0+ is recommended for performance (longer-form scripts under plugins/gaia/scripts/lib/ still benefit from declare -A + mapfile) but no longer required for Tier-2 scanning to function. To upgrade: brew install bash and ensure /opt/homebrew/bin (Apple Silicon) or /usr/local/bin (Intel) precedes /bin in PATH.
  • Scanner tools: install grype + syft + cdxgen + vulture + semgrep via Homebrew / pip, OR opt into the Docker runner cascade (brownfield.tools.runner: docker) so the bundled gaia-tools image supplies them.
  • Diagnostic: gaia-doctor probes installation state and prints the achievable scan tier with concrete remediation commands.

Linux

  • Bash: distros ship bash 4+ or 5+; no special configuration required.
  • Scanner tools: same options as macOS — host PATH install, or the Docker runner cascade.
  • CI: the canonical CI matrix is Ubuntu LTS; the bats suite under plugins/gaia/tests/ assumes bash 4+ by default on Linux runners.

Windows

  • Recommended path: WSL2 + Ubuntu. Install WSL2 (wsl --install), then a current Ubuntu image. GAIA runs natively in the WSL2 shell — same behavior as Linux.
  • Alternative path: Git Bash. Git for Windows ships a recent bash that runs the deterministic-tools chain. Some adapter scripts assume POSIX tools (find, sed -E, awk) — Git Bash provides all of these.
  • Not supported: raw Windows cmd.exe / PowerShell. The orchestration scripts are bash-only by design. A future port may add a PowerShell entrypoint, but the current product surface assumes a POSIX shell.
  • Scanner tools: the Docker runner cascade is the cleanest path on Windows — the bundled gaia-tools image supplies grype/syft/cdxgen/vulture/semgrep without needing each one installed on the host. Enable via /gaia-config-brownfield (brownfield.tools.runner: docker) after Docker Desktop is running.

Cross-platform CI

The plugin's CI matrix runs the bats suite on ubuntu-latest, macos-latest, and windows-latest (Git Bash). Regressions in bash 3.2 portability or POSIX-tool assumptions fail the macOS / Windows jobs before merge.

Statusline issues

Statusline doesn't refresh after a plugin update

See above for the one-time bootstrap. The self-heal logic means subsequent updates self-heal automatically — but the FIRST upgrade onto a pre-self-heal runtime needs a manual install-statusline.sh run.

Statusline shows a stale update arrow after the plugin already updated

The update detector compares the installed semver to the latest-release-cached semver. A stale arrow that lingers after an update was fixed (semver-aware "> not ≠"). Upgrade to v1.180.3+.

Rate-limit display shows ".../.." for one or both windows

The runtime hides missing windows by design — Pro/Max accounts only see the rate-limit JSON after their first API response in the session. Wait for a few interactions; the field will populate.

Test Execution Bridge issues

/gaia-bridge-enable never completes

The test-environment.yaml.example file under .gaia/config/ carries an explicit GAIA-MANIFEST-TEMPLATE guard line that intentionally fails Layer 0 readiness until the file is renamed to test-environment.yaml AND the template guard is removed. The bridge skill installs the .example for you (idempotent), but does NOT auto-promote it — that requires operator intent (you pick + edit runners). See /gaia-bridge-enable.

Reviews report --execution-evidence missing

Make sure the bridge is enabled (test_execution_bridge.bridge_enabled: true in .gaia/config/project-config.yaml) AND a test-environment.yaml manifest exists with runners that the bridge can dispatch. Without both, reviews can write PASSED without execution evidence and the gate refuses to accept the verdict.