# Dependencies
node_modules/

# Build output
dist/
build/

# Runtime data (app registry, history, runs, migration state). Override the
# directory-level `data/` rule from the global ~/.gitignore so git descends
# into data/ and evaluates the negation below; then re-exclude everything
# inside except the .gitkeep that pins the empty directory. Seed/template
# content lives in data.sample/ and is copied in by scripts/setup-data.js;
# migration scripts live in scripts/migrations/.
!data/
data/*
!data/.gitkeep

# Environment files
.env
.env.local
.env.*.local

# Logs
logs/
*.log
npm-debug.log*

# Screenshots
*.png
!client/public/portos-logo.png
!docs/media/portos-logo.png
!data.sample/templates/*.png

# OS files
.DS_Store
Thumbs.db

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

# PM2
.pm2/

# Playwright
.playwright-mcp

# Claude worktrees
.claude/worktrees/
.worktrees/
.claude/settings.local.json
.claude/scheduled_tasks.lock

# BTW messages (ephemeral agent context, cleaned up after ingestion)
BTW.md

# Browser service node_modules (code is committed)
browser/node_modules/

# Browser service runtime data (CDP profiles, cache, downloads)
browser/data/

# Sub-package lock files. Root package.json does NOT declare these as
# workspaces; `npm run setup` runs `npm install --prefix <pkg>` for each,
# generating their own lockfiles locally. The root package-lock.json only
# tracks root devDependencies (pm2) — the `client`/`server` entries you may
# see there are stale `extraneous: true` leftovers and are not authoritative.
browser/package-lock.json
client/package-lock.json
server/package-lock.json
__pycache__/
