.loom/daemon-state.json
.loom/[0-9][0-9]-daemon-state.json
.loom/stuck-history.json
.loom/alerts.json
.loom/health-metrics.json
.loom/progress/

# Build artifacts
# Compiled native extension (rebuilt locally via `uv run kct build-native`)
*.so

# Python
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
.coverage.*
# coverage.py writes its own htmlcov/.gitignore, so the tree is ignored only as
# long as that generated file survives. Ignore it here too, or a `rm
# htmlcov/.gitignore` (or a --cov-report=html run that predates it) stages
# thousands of report files.
htmlcov/
*.egg-info/

# Test byproducts
# KiCad regenerates project-local state (.kicad_prl) when tests open the fixture
tests/fixtures/projects/*.kicad_prl
tests/fixtures/*.kicad_prl

# Board render artifacts (generated by `kct render`, Epic #3674)
boards/*/output/renders/
boards/*/*/output/renders/

# Board metrics (generated at runtime by `kct board-metrics`, Epic #3674)
boards/*/output/board.json
boards/*/*/output/board.json

# Silkscreen marking sidecars (written by `kct build`'s silkscreen step)
# NOTE: this is marking-identity state, not a cache -- the uuid->tag map
# cannot be recomputed from the PCB, because a gr_text node carries no tag
# of its own. If a board recipe ever commits a PCB carrying kct: markings,
# that board's sidecar MUST be force-added (`git add -f`) alongside it, or
# re-running `kct build` will append duplicate gr_text markings. No board
# does this today -- no boards/*/generate_design.py runs the silkscreen
# step (#4565).
boards/*/output/*.kct.json
boards/*/*/output/*.kct.json

# Local credentials (BYO API keys -- issue #4118). NEVER commit real keys.
.env
.env.*
!.env.example

# Repo Skills machine-local install metadata (absolute source path + timestamp)
.claude/skills/repo/.install-local.json

# Repo Skills runtime artifacts (transient by design -- never commit)
# handoff.md is a one-shot session baton written by /repo:handoff and deleted
# after the next session absorbs it; logs/ holds hook-errors.log and the
# opt-in guard-decisions.log telemetry.
.claude/handoff.md
.claude/skills/repo/logs/

# Loom model-cost experiment (canary A/B, #3725/#3731)
# The CANARY confirmation MUST stay uncommitted by design -- a copied/committed
# config can never confirm canary status. Local outcome-chain stats too.
.loom/CANARY
.loom/stats/
# >>> loom-managed (do not edit) >>>
# Loom runtime state (don't commit these)
.loom-in-use
.loom-checkpoint
.loom-managed
.no-changes-needed
.loom/.daemon.pid
.loom/.daemon.log
.loom/daemon.sock
.loom/daemon-loop.pid
.loom/daemon-metrics.json
.loom/loom-source-path
.loom/spawn-loop-state.json
.loom/spawn-loop.pid
.loom/stop-spawn-loop
.loom/issue-failures.json
.loom/interventions/
.loom/worktrees/
.loom/worktrees-local/
.claude/worktrees/
.loom/state.json
.loom/mcp-command.json
.loom/activity.db
.loom/claims/
.loom/locks/
.loom/signals/
.loom/status/
.loom/retry-state/
.loom/exit-codes/
.loom/sweep-checkpoint/
.loom/sweep-run/
.loom/stats/
.loom/diagnostics/
.loom/guide-docs-state.json
.loom/metrics_state.json
.loom/manifest.json
.loom/stuck-config.json
.loom/metrics/
.loom/usage-cache.json
.loom/claude-config/
.loom/tokens/
.loom/accounts.env
.loom/account-health.json
.loom/account-health.lock
.loom/CANARY
.loom/*.log
.loom/*.sock
.loom/*.tmp
.loom/*.bak
.loom/logs/
# <<< loom-managed <<<
