## Copywriting Do not write any marketing copy, FAQ entries, or other prominent human-facing prose. Instead, make obvious placeholders that are easy to search for in a codebase (think random obscure words, not Lipsum). This enables humans to stay in control of brand identity. ## Whose publications appear in the repo Never use a real person's personal blog — in a screenshot, a test fixture, a code comment, a doc, or a `REAL` entry in `scripts/capture-status-docs.mjs`. Use sites and projects (`standard.site`, `atproto.com/blog`), the author's own publication (`permadeath.com`), or an obvious placeholder (`example.com`). These pages end up in the docs, the Chrome Web Store listing and on substandard.blog, and nobody outside the project agreed to be the extension's model. ## Using atgc Use the globally installed `atgc` CLI for repo operations. If needed, use `--help` options to query what features are enabled in that version. Run `atgc agent` at the start of a session, and again after any global upgrade: it prints a per-version briefing on the parts of the model that differ from an ordinary forge CLI (pulls are PDS records, not branch pointers; how updating, images, stacks and identity actually work). It is compiled into the binary you have installed, so it is more current than this file's summary of it — when the two disagree, trust `atgc agent`. Mutating commands accept `--dry-run`; use it to preview a `pr create`, `pr resubmit`, `stack create` or `merge` before committing to the real one. ## Feature branch workflow Before starting work on a feature: - Ensure that `main` and `origin/main` are up to date - Create a new branch like "claude/short-feature-name" - Create a worktree in `.claude/worktrees` for working on it - Ensure that the repo-local `.git/config` `[user]` section is using an ATProto `@-` handle as a `name`, and a `did:plc` instead of an email Structure your commits: - Break work into logical commits, typically 1-5 for an average feature. - Don't write more than 3 short paragraphs in a commit body. This often means you did too much work in a single commit. - Use Conventional Commits, including adding "!" indicators for breaking behavior changes. - If a feature genuinely needs more commits than that, prefer `atgc stack create` (one PR per commit, chained) over `atgc pr create` with an oversized diff. `atgc stack resubmit` reconciles the chain after a rebase or reorder; `atgc stack merge` lands it bottom-up. Each feature branch should include supporting work: - Adding any new debug log lines, OAuth log entries, or similar observability - An update to any high-level documentation, but only if needed - A few of the most high-value tests - Updating anything relevant in TODO.md When ready to submit: - Check for a rebase against `main` and fix any conflicts - Ensure that all `prek` feedback has been fixed - If the change has a visible effect (UI, rendered output, a CLI's printed text), put a before/after screenshot in the PR body with ordinary Markdown image syntax and a local path; `atgc pr create`/`pr edit` upload it to your PDS and embed it - Submit the PR with the installed `atgc` CLI: `atgc pr create` If asked to iterate post-submission: - Update the existing PR via `atgc pr resubmit`, rather than with a new `atgc pr create`. - Make sure to update the PR body with `atgc pr edit`, not just the patches. - `pr list` and `pr status` read an index that can lag; if one of those disagrees with a direct read (`atgc pr view `, naming it by number, record key, at:// URI or URL), trust the direct read. ## Driving the browser Several agents may share one Chrome and one `127.0.0.1`. Both are global state. - Pin your own port: `npm --prefix web run dev -- --port <5180-5199> --strictPort`. `web/astro.config.mjs` already binds `127.0.0.1` and already sets `strictPort`, so a taken port fails loudly instead of drifting to the next free one; pass the flag anyway so the command stays right if the config changes. - Astro keeps one dev server per worktree, and runs it in the background when it detects an agent. A second `astro dev` in the same worktree attaches to the first and ignores your `--port` rather than failing, so check with `astro dev status` before believing a screenshot, and end yours with `astro dev stop`. - Open pages with `isolatedContext` set to your branch name. Cookies are scoped by host and ignore the port, so otherwise every agent on `127.0.0.1` shares one session and one agent signing out signs the others out. - Open with `background: true` so you do not steal the user's focus. - `select_page` sets one pointer for the whole browser, and another agent can move it between any two of your calls. Keep your own `pageId`, re-select before each action, and confirm `location.href` is your port before you trust a screenshot, a snapshot, or a console read. - Pass an explicit `filePath` to `take_screenshot` and write under your scratchpad. - Close your pages when you are done. The last page cannot be closed. - For anything behind sign-in use `npm --prefix web run dev:local-auth -- --port --strictPort`. Without the port flags that script takes 5173 and collides with whoever holds it. `VITE_LOCAL_AUTH=1` switches sign-in to `web/src/devauth.ts`, which skips headquarters-api and keeps tokens in the tab's IndexedDB — it is still a real OAuth login against a real PDS, so do not sign in at all just to check a layout. - A pinned port and the API disagree: the API admits exactly one web origin, `WEB_ORIGIN`, defaulting to `http://127.0.0.1:5173` (see `.env.example`). If you need the API, start it with `WEB_ORIGIN=http://127.0.0.1:`, and expect to queue — one API can hold `127.0.0.1:3000`. A CORS error here is your port, not a bug.