# Python
__pycache__/
*.py[cod]
*.egg-info/
.venv/
.mypy_cache/
.ruff_cache/
.pytest_cache/
.coverage
coverage.xml
htmlcov/
dist/
build/

# Node / frontend
node_modules/
frontend/*/dist/
*.tsbuildinfo
.pnpm-debug.log*
# pnpm relocates its content-addressable store next to the project when its
# default location is on another filesystem — which is what a bind mount is. The
# compose stack shadows that path with a volume; this is the backstop for any
# other environment that does the same thing.
.pnpm-store/

# Playwright output. The browsers themselves live in a per-user cache outside the
# repository (~/.cache/ms-playwright), so nothing here needs an entry for them.
test-results/
playwright-report/
# Visual baselines are taken in the Playwright container on the machine that compares
# them (docs/content/architecture/frontend/visual-baselines.md); the `visual` project
# runs only under VISIONSET_VISUAL, so nothing else ever looks for them.
frontend/app/e2e/*-snapshots/
blob-report/
playwright/.cache/

# The benchmark's own report. Machine-specific by construction — the numbers that
# matter are copied into docs/content/annotations.md, where they carry the machine that
# produced them; a committed file would just be one developer's laptop.
frontend/app/bench-results.json

# The documentation site. `docs/content/` is the source of truth and is committed;
# every path below is derived from it by `docs/scripts/sync-docs.mjs` or by Astro,
# and committing any of them would be the second copy this architecture exists to
# avoid. The projection is rebuilt before every dev, build and preview run, so a
# clean checkout needs nothing here. (`dist/` and `node_modules/` above already
# cover this directory's build output and its install.)
docs/src/content/docs/
docs/.astro/

# import-linter's analysis cache. Grimp writes a nested `.gitignore` holding `*`
# inside it, which git honours and hatchling does not read — so without this line
# the directory is invisible in `git status` and still ships inside the sdist.
.import_linter_cache/

# Compiled UI bundle travels in the wheel, never in git
src/visionset/_static/*
!src/visionset/_static/README.md
!src/visionset/_static/.gitkeep

# Workspace media (v1 committed 929 MB of fixture images — never again). The
# directory itself is tracked, through an empty file, and only its contents are
# ignored — because the compose stack bind-mounts it and Docker creates a missing
# bind-mount source as root, before any container starts and before any entry
# script could get ahead of it. A checkout that already carries the directory is
# one the daemon never has to invent, so the stack's own storage stays writable by
# whoever cloned.
**/workspace-data/*
!workspace-data/.gitkeep

# Compose reads `docker/.env` for the uid the dev stack runs as — a host fact,
# never a repository one. Unanchored so it holds wherever such a file lands.
.env

# Editors / OS
.DS_Store
.idea/
.vscode/
*.swp

# Coding-agent config: the canonical, committed source is .agents/skills/.
# Everything below is either generated by scripts/setup_agents.sh or personal to a
# contributor's machine — never committed.
.claude/
.cursor/
.codex/
CLAUDE.md

# Local planning/scratch notes
*-plan.md
*-plan-*.md
*.tmp.md

# Plans and research an agent writes for itself while working. They describe one
# task's approach, not the project, so they belong to the machine that ran it.
docs/superpowers/

# graphify: knowledge-graph artifacts stay local (regenerate with `graphify update .`)
graphify-out/

# What a browser session leaves in the working tree. The MCP Playwright server
# writes its traces and screenshots to `.playwright-mcp/`, and a screenshot taken to
# look at something is named for what it showed rather than for where it belongs —
# so both arrive as untracked noise in every `git status` taken afterwards, which is
# how a real untracked file gets missed.
.playwright-mcp/
*-demo.png
