- Do NOT attempt to install packages unless the user explicitly asks you to do
  so.  Only the packages specified in pyproject.toml are available.  You cannot add new packages.  If you desperately want another package, tell the user.
- Use `webapp/notifications.html` as the default UI file to edit; do not add or modify other notification UI files unless explicitly requested.
- If you modified Python files, use "ruff check" to check lint, "ruff format" to autoformat files and "pyrefly check ." to typecheck.  Do NOT do this if the change is HTML+JS only.
- Tests:
  - E2E (Playwright): run from `e2e/` via `npm test` (or `npm run test:headed|test:debug|test:ui`)
    - Allow a longer timeout for `npm test` in automation (recommend 5 minutes / 300000 ms).
    - Playwright auto-starts the API server with `uv run python -m ghinbox.api.server --test --no-reload --port 8001`
    - Base URL is `http://localhost:8001/app/`
    - Tests use port 8001 (not 8000) to avoid conflicts with production servers
    - Override with `TEST_PORT=XXXX npm test` if needed
  - Python tests: `uv run pytest` (only run if you modified Python)
  - There is no root `npm run test:e2e` script; use the `e2e/` package scripts.
- Fixtures:
  - Try not to invent fixtures from scratch; instead, we want to create production flows which we can extract fixtures from (this makes it easier to update the fixtures in the future.)  Use ezyang0 and htmlpurifierbot when running prod flows.
  - Update HTML fixtures from responses (non-interactive): `uv run python -m ghinbox.fixtures update --force`
  - Regenerate E2E JSON fixtures: `uv run python -m ghinbox.fixtures generate-e2e --force`
- Always run tests after making changes.
- Always add E2E tests for new features.  If I ask you to fix a bug, first make an E2E test that exhibits the bug and fails, and then fix it.
- There may be multiple coding agents running at the same time; don't worry
  too much about unexpected changes, we are running SCM checkpoints regularly.
