# Python
__pycache__/
*.py[cod]
*.egg-info/
*.egg
.eggs/
dist/
build/
.cache/pip/
.venv
venv/
env/

# Mypy / Ruff / Pytest / Hypothesis
.mypy_cache/
.ruff_cache/
.pytest_cache/
.hypothesis/
.coverage
htmlcov/

# Node — no trailing slash so a worktree's `node_modules` *symlink*
# (created by scripts/wt) is ignored too, not just real directories.
node_modules

# Coverage
coverage/
coverage.xml
# Generated by scripts/sonar-scan.sh / the sonar:scan CI job: a copy of the API
# coverage.xml with a resolvable <source> root injected for import (#2113).
coverage.sonar.xml

# uv lockfile. The api (APPLICATION), the scheduler (published LIBRARY), and the
# mcp server (self-hostable app + published PyPI package) all commit a resolved
# lock — for reproducible dev/CI installs and a scannable dependency surface: an
# SCA tool (security:osv) can audit a committed lockfile but not the version
# ranges a library declares. The published wheels still ship ranges from
# pyproject.toml; the lock is a repo-side artifact only (#904 api supply-chain
# hardening, #1153 scheduler OSV migration, #2122 mcp). Keep the blanket ignore
# for everything else.
uv.lock
!packages/api/uv.lock
!packages/scheduler/uv.lock
!packages/mcp/uv.lock

# Docker
*.override.yml

# OS
.DS_Store
Thumbs.db

# Editor
.idea/
.vscode/
*.swp
*.swo

# Docusaurus build cache
.docusaurus/

# Claude Code runtime state
.claude/scheduled_tasks.lock
.claude/worktrees/

# Playwright test runtime output
test-results/
packages/web/test-results/
packages/web/playwright-report/

# Rendered by init-prod.sh from one of the nginx/*.conf.template files at first
# run (#3189). A generated artifact, never committed.
nginx/active.conf.template

# Local dev attachment + media blobs (Closes #817)
packages/api/attachments/
packages/api/media/
# Workspace logo blobs (#969) — local-disk storage root; prod uses object storage
packages/api/branding/

# Workspace export test/runtime artifacts (written by export tests; never committed)
packages/api/workspace-exports/
# Project export bundle test/runtime artifacts (ADR-0219; never committed)
packages/api/project-exports/
# Program export bundle test/runtime artifacts (ADR-0219, #1958; never committed)
packages/api/program-exports/
# Program seed import payload test/runtime artifacts (ADR-0726, #2574; never committed)
packages/api/seed-imports/

# Per-worktree harness files — auto-generated per worktree/machine by scripts/wt
# (COMPOSE_PROJECT_NAME, isolated TRUEPPM_TEST_DB, owner marker, number reservation).
# Regenerated on every `wt new`; never committed. Tracking them leaks machine-specific
# data, collapses per-worktree test-DB isolation, and makes `wt prune` skip the
# worktree as "has local work". See #1690.
.envrc
.wt-owner
.wt-reservation

# The operator's real secrets. init-prod.sh WRITES this file at the repo root —
# SECRET_KEY (which is also the JWT signing key), DB_PASSWORD, REDIS_PASSWORD —
# and nothing else stopped `git add -A` from committing it. .env.example is the
# tracked template; .env never is (#3183).
.env
.env.*
!.env.example

# SonarCloud / sonar-scanner scratch output
.scannerwork/
.sonar/

# Schemathesis API-fuzz crash cache — one JSON record per crash fingerprint,
# written by the `fuzz` extra (packages/api/pyproject.toml) on every local run.
# Generated, machine-local, and large (289 files in one observed run); each
# record embeds the request headers and curl repro for its target. Never
# committed. See #2794.
.schemathesis/

# Captured docs-build output (#2797). website:build / pages redirect `npm run
# build` here so the exit code stays honest (a `| tee` would report tee's
# status), then check-mermaid-rendered.sh scans it for the [ERROR] lines Astro
# logs while still exiting 0. CI-local scratch; never committed.
website-build.log

# k6 perf/load metrics blob (#2816). `packages/api/perf/load.js` writes it to the
# working directory on every run — a CI artifact there, repo-root scratch when the
# harness is run locally per packages/api/perf/README.md. Machine-local and
# meaningless off the run that produced it; never committed.
perf-summary.json

# TLS material generated by init-prod.sh (#2829). `TLS_MODE=selfsigned` mints a
# lineage into certbot/conf/live/$DOMAIN/, and letsencrypt writes the real one to
# the same place — so this directory holds a PRIVATE KEY on any host that has run
# the documented production entrypoint, including a developer trying the prod
# compose drill locally. The drill removes it on teardown; this is the guard for
# the run that fails before teardown.
certbot/

# Local audit reports (docs/audit/). Generated by /pre-release, red-team, and
# state-of-repo runs; kept on the machine that produced them and never committed.
#
# This repo is PUBLIC. These reports enumerate unfixed defects with file:line
# detail — red-team-2026-08-06.md alone carries two CRITICAL and three HIGH
# findings, and C1 (no working way to revoke a stolen refresh token) is still
# live on main as of 2026-08-21. Committing them here publishes a working
# exploit description ahead of the fix. File the findings as issues instead —
# a tracker entry is the disclosure channel, a checked-in audit report is not.
docs/audit/
