# Python
__pycache__/
*.pyc
*.pyo
*.egg-info/
dist/
build/
.venv
venv/
*.so

# OS
.DS_Store
canonical-session-worktrees.json

# IDE
.vs/
.idea/
*.suo
*.user
*.userprefs

# Obsidian (commit config, ignore workspace cache)
documentation/.vscode/
documentation/.obsidian/workspace.json
documentation/.obsidian/workspace-mobile.json
documentation/.obsidian/plugins/
documentation/.obsidian/themes/
documentation/.obsidian/hotkeys.json

# AI tool config
.gemini
.gemini/

# Secrets (envchain loads from macOS Keychain — .env is only for local overrides)
.env

# direnv
.direnv/

# SQLite dev database
dev.db

# Claude Code workflow flags (transient, per-session)
.claude/no_jira_required
.claude/.rc-pair-state.json
.claude/settings.local.json

# Claude Code writes its install lock to a CWD-RELATIVE `claude/locks/` instead
# of under the user's state directory, so the directory appears in whatever
# checkout a session happens to be standing in. The cause is an empty-string
# XDG_STATE_HOME: the bundle resolves the base with `??`, which falls back only
# on null/undefined, so `join("", "claude", "locks")` stays relative.
#
# Not merely untidy. An automated working-tree sweep committed one of these, so
# a foreign machine's lock — carrying that machine's absolute home path — shipped
# to every clone, and it also made `git pull` refuse with "untracked working tree
# files would be overwritten by checkout". Ignoring the directory is what stops
# the next sweep from re-adding it; see the guard in
# tests/test_public_repo_hygiene.py.
claude/

# This project's own state directory, for the same reason and by the same
# mechanism, in our code rather than Claude Code's: `os.environ.get(var,
# default)` returns "" for a variable that is set-but-empty, so the fallback
# never fired and `Path("") / "ai-cli-utils"` stayed relative to the cwd. A
# captured process listing was committed here that way. The resolver is fixed
# (config.resolve_base_dir ignores empty and non-absolute values), so this entry
# is defence in depth against a stale build or an older install, not the fix.
ai-cli-utils/

# Test artifacts
test.db
.coverage
coverage.xml
htmlcov/
.ruff_cache/
.pytest_cache/

# Exported conversation transcripts (generated output)
docs/conversations/*
!docs/conversations/README.md

# Scratch / working notes
SCRATCH.md

# Claude Code workflow (transient, per-session)
.claude/signals/
.claude/state/
.claude/handoff-queue/claimed/
.claude/handoff-queue/completed/
.worktrees/

# Playwright MCP
.playwright-mcp/

# Note: uv.lock is tracked for reproducible CI (not ignored)

# Node
node_modules/
package-lock.json

# Logo archive (working drafts)
logos/archive/
.direnv
assets/iterm2-key-bindings/

# Demo recording intermediates
demo/demo.mov
demo/archive/

# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key
.beads/proxieddb/
# Dolt server state — machine-local runtime (host, pid, port, recorded_at). A pid and a
# port mean nothing in another clone, so committing it publishes noise a reader could act
# on. It arrived untracked once every machine began running a server, and stayed visible
# in `git status` where a `git add -A` would sweep it in.
.beads/.dolt-server-state.json
# >>> ai-harness canonical symlinks (AIH-119) — regenerated by install.sh; do not hand-edit, commit as normal >>>
docs/analysis/TEMPLATE.md
docs/analysis/STUB.md
docs/analysis/STUB.md.jinja
docs/audits/TEMPLATE.md
docs/audits/STUB.md
docs/audits/STUB.md.jinja
docs/bugs/TEMPLATE.md
docs/bugs/STUB.md
docs/bugs/STUB.md.jinja
docs/designs/TEMPLATE.md
docs/designs/STUB.md
docs/designs/STUB.md.jinja
docs/handoffs/TEMPLATE.md
docs/handoffs/STUB.md
docs/handoffs/STUB.md.jinja
docs/plans/TEMPLATE.md
docs/plans/STUB.md
docs/plans/STUB.md.jinja
docs/procedures/TEMPLATE.md
docs/procedures/STUB.md
docs/procedures/STUB.md.jinja
docs/procedures/ac-writing-practices.md
docs/procedures/autonomous-completion-format.md
docs/procedures/claude-token-efficiency.md
docs/procedures/reasoning-checkpoints.md
docs/procedures/root-cause-and-fix.md
docs/procedures/task-batch-presentation-format.md
docs/research/TEMPLATE.md
docs/research/STUB.md
docs/research/STUB.md.jinja
docs/test/TEMPLATE.md
docs/test/STUB.md
docs/test/STUB.md.jinja
docs/tools/TEMPLATE.md
docs/tools/STUB.md
docs/tools/STUB.md.jinja
docs/docket/TEMPLATE.md
docs/docket/STUB.md
docs/docket/STUB.md.jinja
docs/research/prompts/TEMPLATE.md
docs/prompts/fable/STUB.md
docs/prompts/fable/STUB.md.jinja
docs/specs/SPEC-TEMPLATE.md
docs/specs/STUB.md.jinja
docs/social/TEMPLATE.md
# <<< ai-harness canonical symlinks (AIH-119) <<<

# Repo-root gate/lock markers (e.g. .beads.gate.lock): machine-local coordination
# state, never repo content. Ignored in ai-harness since AIH-swgb4 but nowhere else,
# so a /sync-git dry-run on 2026-09-16 reported it would commit the zero-byte lock
# into this repo and four siblings (AIH-beads-gate-lock-gitignored-only-m1pq0).
/.*.lock
