﻿# === OS Files ===
.DS_Store
Thumbs.db
desktop.ini

# === VS Code ===
# All of it, including tasks.json: the Run menu can import VS Code tasks
# (`design/features/project-actions.md`), but this repository no longer carries its own
# copy - the file is per-machine editor state, not something a clone should inherit.
.vscode/*
*.code-workspace

# === Git ===
.git/
.claude/worktrees/
# Personal Claude Code settings: permission allow-rules and other per-machine
# choices. Untracked today, but nothing was stopping it being added, and this
# repository is public - an allow-rule list is one operator's trust decisions,
# not something a clone should inherit. `.claude/settings.json` (team-wide,
# committed on purpose) is deliberately NOT ignored.
.claude/settings.local.json
.agents/worktrees/
.codex/worktrees/
# Codex also registers worktrees at the bare path, not only under `.codex/`.
# An unignored checkout here is not merely noise: it raises this repository's
# dirty count, which is a precondition the land queue refuses on.
.worktrees/

# === Node.js ===
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
frontend/test-results/
# Playwright also lands here when the renderer suite is run from the repo root.
/test-results/
frontend/playwright-report/

# === Python ===
__pycache__/
*.py[cod]
*.pyo
*.pyd
env/
venv/
.venv/
*.egg-info/

# === Logs ===
*.log

# === Build / Dist ===
dist/
build/
out/
packaging/swe-mux.ico
.runtime/

# Content-hashed vite output, and the index.html that names it. These are the only files
# under src/swe_mux/static that churn: every `npm run build` renames the bundle, so
# tracking them dirtied the tree on every build, blocked the automatic fast-forward of
# the base branch at land time, and gave parallel agents meaningless conflicts over
# generated bundles. Packaging does not read them either — build_desktop.py builds its
# own copy into .runtime/desktop-frontend-build and publishes from there.
src/swe_mux/static/assets/
src/swe_mux/static/index.html

# Precompressed siblings written by frontend/scripts/compress-static.mjs after every build.
# The two rules above already cover most of them, which is why the exceptions went unnoticed:
# `index.html.gz` sits beside an ignored file, and `sw.js.gz` beside a tracked one. They churn
# for the same reason the bundle does and nothing needs them in git — aiohttp's FileResponse
# picks a `.gz` sibling up off disk when the client accepts gzip, so a tree that has not been
# built simply serves the uncompressed file.
src/swe_mux/static/**/*.gz

# The REST of src/swe_mux/static stays tracked on purpose, even though vite also
# generates it by copying frontend/public/ (and wipes it each build via emptyOutDir).
# Those copies are byte-stable, so they never churn, and `create_app` registers
# /notification-sounds and /icons only `if <dir>.is_dir()` — untracking them silently
# drops those routes in any tree that has not been built yet, which
# test_phase3_daily_workflow::test_phase3_routes_are_registered correctly fails on.

# === JetBrains IDEs ===
.idea/
*.iml

_agents-orchestrator/
.tmp-orca/
.tmp-omp/
.tmp-herdr/
.tmp-cmux/
.trash/

# === Operator-private notes ===
# Account setup, infrastructure configuration, and anything else that is about
# running this project rather than about the code. The repository is public, so
# this is the only place in the tree where "nobody else will read this" is true.
# It is NOT for secrets: keys and passwords belong in a password manager, and a
# gitignore rule is one `git add -f` away from not protecting them.
.private/

# === Project-local swe-mux state ===
# The whole directory, as of 2026-08-28. It used to be a split: the daemon's own runtime
# writes were ignored one path at a time while the repository-authored files beside them
# (`actions.toml`, `project-context.md`, `prompts/`) stayed tracked because a human wrote
# them for this repository. That split is gone - `.swe-mux/` is now treated as per-machine
# state end to end and nothing under it is carried in the repository.
#
# The reasoning that produced the individual rules still holds and is why the directory rule
# is the right generalisation rather than a shortcut:
#   - `notes/`, `attachments/`, and `preview-shots/` are generated on demand.
#   - `observations.json` is the observation inbox (spawn, control, and land approval rows):
#     pure per-machine runtime state with no meaning in a clone, appended to whenever an
#     agent asks for something, so tracking it made every such request a working-tree change.
#   - `config.toml` is typed Project config whose *format* is portable by design, and a clone
#     is meant to be able to carry one (`.docs/design/features/automation-enablement.md`) -
#     but the daemon rewrites the file whenever an automation is toggled or a grant changes,
#     so every switch flipped in the UI showed up as a pending commit. A clone therefore
#     starts with no opt-ins, which is the correct default for automations anyway.
# The same churn argument now covers the authored files too: they are one operator's local
# setup rather than something a public clone should inherit. The cost is that a fresh clone
# gets no declared Project Actions and no project context; both are authored in the UI.
.swe-mux/

# === Test / verification scratch ===
# Throwaway working directories written by live-agent and identity tests and by
# the verification runs. They hold binary mux.db copies and fake executables and
# must never be committed (4f744d8 did, accidentally).
.test-tmp-identity/
test-tmp-codex/
.verify/
# Per-test SQLite files under tests/. The fixture removes them, but a test that
# fails before closing its store leaves one behind (Windows will not unlink a
# file a live connection holds), and those are exactly what got committed before.
tests/.phase2-*.db*
# playwright-cli session output (snapshots, console logs) from driving the live UI
.playwright-cli/

# Operator scratch at the repo root. It has held real secrets (a Tailscale cert/key
# pair sat in .tmp/tailscale-cert-check/ and was tracked until this rule landed), so
# nothing under it belongs in a public clone.
.tmp/

# One-off UI mockups dropped at the repo root while designing a surface. They are a
# scratch artifact of the design pass, not a source file: nothing imports them, no
# build reads them, and they rot the moment the real component changes.
/sidebar-row-mockup.html

# Smart Turn v3 weights, fetched by tools/fetch_smart_turn.py (BSD-2-Clause, ~8 MB).
# An experiment behind frontend/smart-turn-lab.html; a binary this size does not
# belong in git history, and the lab tells you how to fetch it when it is absent.
frontend/models/
