diff --git a/.claude/docs/AGENT_FAILURES.md b/.claude/docs/AGENT_FAILURES.md index 7cd1eeaa31a..7de5c184b87 100644 --- a/.claude/docs/AGENT_FAILURES.md +++ b/.claude/docs/AGENT_FAILURES.md @@ -53,8 +53,12 @@ shown below when adding new failures. - How to reproduce: Run a Playwright test from `site` with `pnpm playwright:test`, let it fail, and discard the generated output before reporting the failure. -- How to diagnose: Check `site/e2e/playwright.config.ts`, `site/e2e/README.md`, - and the terminal output for the report or `test-results` location. +- How to diagnose: Playwright writes per-test failure artifacts (screenshots, + videos, and traces) to `site/test-results/`, the HTML report to + `site/playwright-report/`, and the coderd debug log to + `site/e2e/test-results/debug.log`. In CI, the `test-e2e` job uploads + artifacts named `playwright-artifacts-`, `coderd-debug-logs-`, and + `debug-pprof-dumps-`, each followed by the matrix job name and commit SHA. - Existing docs or tools: [Frontend Development Guidelines](../../site/AGENTS.md), `site/e2e/README.md`, and `pnpm playwright:test`. - Missing harness piece: No central checklist tells agents which browser @@ -102,7 +106,7 @@ shown below when adding new failures. - How to diagnose: Search the test diff for `time.Sleep`. Inspect whether the code under test can use `quartz` or another explicit synchronization point. - Existing docs or tools: `AGENTS.md`, [Testing Patterns and Best Practices](TESTING.md), - and the quartz README referenced from `AGENTS.md`. + and the quartz README linked from `TESTING.md`. - Missing harness piece: Agents need a failure entry that labels sleep-based waiting as a flake risk before review. - Proposed prevention: Replace `time.Sleep` with a fake clock, trapped ticker, diff --git a/.claude/docs/FRONTEND_PATTERNS.md b/.claude/docs/FRONTEND_PATTERNS.md index 7ad2e5b1339..6b80efde782 100644 --- a/.claude/docs/FRONTEND_PATTERNS.md +++ b/.claude/docs/FRONTEND_PATTERNS.md @@ -27,6 +27,9 @@ function actually exercises the interaction. Jest/RTL tests are for pure logic not only the happy path. - Assert both sides of an invariant: the item that changed and a neighboring item that must not change. +- When a component depends on the current time or date, accept it as a prop or + via context instead of reading `new Date()` or `Date.now()` internally, so + stories render deterministically without mocking globals. **Incorrect (interaction test in Jest/RTL):** @@ -61,6 +64,8 @@ export const SelectModel: Story = { - Use generated types from `api/typesGenerated.ts` for all API data. Never re-declare a type that the backend already generates. - If a component requires a prop to function, make the prop required. +- Avoid `@ts-ignore` and `biome-ignore` suppression comments. Seek a + better-typed alternative first, and document why when one is unavoidable. **Incorrect:** @@ -121,6 +126,9 @@ Every view that renders server data must handle this matrix: - When a mutation partially fails, the UI must reflect what succeeded and what did not (see FE7 for cache invalidation). - Render a visible fallback ("Untitled", "N/A") for nullable display data. +- Never use `key={String(booleanState)}` to force a remount. When the boolean + flips, React synchronously unmounts and remounts the subtree, discarding its + state and killing exit animations. ## FE6: Accessibility is behavior, not decoration @@ -133,6 +141,9 @@ Every view that renders server data must handle this matrix: - Preserve focus position across dialogs and route transitions. - When visually hiding an interactive element, also remove it from the tab order and accessibility tree, or conditionally render it out of the DOM. +- Generate IDs for form elements, labels, and ARIA attributes with + `React.useId()`. Hard-coded string IDs collide when a component renders more + than once on a page. ## FE7: React Query discipline diff --git a/AGENTS.md b/AGENTS.md index 5a48049c38b..1e58f9467f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,253 +1,85 @@ # Coder Development Guidelines -You are an experienced, pragmatic software engineer. You don't over-engineer a solution when a simple one is possible. -Rule #1: If you want exception to ANY rule, YOU MUST STOP and get explicit permission first. BREAKING THE LETTER OR SPIRIT OF THE RULES IS FAILURE. - -## Agent navigation - -- Day-to-day: Start with [Development Workflows and Guidelines](.claude/docs/WORKFLOWS.md) for dev servers, git workflow, hooks, and routine checks. -- Observability and isolation: Use [Observability Guide for Agents](.claude/docs/OBSERVABILITY.md) for logs, tracing, and metrics, and [Development Isolation Guide for Agents](.claude/docs/DEV_ISOLATION.md) for ports, state, readiness, and cleanup. -- Failures: Use [Agent Failure Catalog](.claude/docs/AGENT_FAILURES.md) for repeatable failure formats and seeded diagnostics. -- Language and area docs: Use [Modern Go](.claude/docs/GO.md), [Testing Patterns and Best Practices](.claude/docs/TESTING.md), [Database Development Patterns](.claude/docs/DATABASE.md), [OAuth2 Development Guide](.claude/docs/OAUTH2.md), [Coder Architecture](.claude/docs/ARCHITECTURE.md), [Troubleshooting Guide](.claude/docs/TROUBLESHOOTING.md), [Documentation Style Guide](.claude/docs/DOCS_STYLE_GUIDE.md), and [Pull Request Description Style Guide](.claude/docs/PR_STYLE_GUIDE.md) when that area is in scope. -- Docs content scope: Use [Coder Docs Content Guidelines](docs/.style/content-guidelines.md) to decide whether a piece of content belongs in `docs/` at all. The Documentation Style Guide above covers prose and formatting; the content guidelines govern scope and routing and supersede the style guide on conflicts. -- Compatibility: `.agents/docs` symlinks to `.claude/docs` for agent runtimes that look there. -- Frontend: Read [Frontend Development Guidelines](site/AGENTS.md) before changing anything under `site/`. For code under `site/src/`, the [Frontend Patterns](.claude/docs/FRONTEND_PATTERNS.md) rule contract (FE1 to FE10) applies. -- Docs prose: For prose-only edits to existing `docs/` pages, refer to the prose style guide at [`docs/.style/style-guide/`](docs/.style/style-guide/README.md). - For supporting agent-specific guidance, refer to [`.claude/docs/DOCS_STYLE_GUIDE.md`](.claude/docs/DOCS_STYLE_GUIDE.md), which covers structure, research, and content patterns. -- Docs authoring: For new, moved, or restructured `docs/` pages, or when unsure, load the [`write-docs` skill](.claude/skills/write-docs/SKILL.md) first. It points at the canonical content guidelines and the prose style guide above, then walks research, routing, Diátaxis mode, structure, and validation. - -## Foundational rules - -- Doing it right is better than doing it fast. You are not in a rush. NEVER skip steps or take shortcuts. -- Tedious, systematic work is often the correct solution. Don't abandon an approach because it's repetitive - abandon it only if it's technically wrong. -- Honesty is a core value. - -## Our relationship - -- Act as a critical peer reviewer. Your job is to disagree with me when I'm wrong, not to please me. Prioritize accuracy and reasoning over agreement. -- YOU MUST speak up immediately when you don't know something or we're in over our heads -- YOU MUST call out bad ideas, unreasonable expectations, and mistakes - I depend on this -- NEVER be agreeable just to be nice - I NEED your HONEST technical judgment -- NEVER write the phrase "You're absolutely right!" You are not a sycophant. We're working together because I value your opinion. Do not agree with me unless you can justify it with evidence or reasoning. -- YOU MUST ALWAYS STOP and ask for clarification rather than making assumptions. -- If you're having trouble, YOU MUST STOP and ask for help, especially for tasks where human input would be valuable. -- When you disagree with my approach, YOU MUST push back. Cite specific technical reasons if you have them, but if it's just a gut feeling, say so. -- If you're uncomfortable pushing back out loud, just say "Houston, we have a problem". I'll know what you mean -- We discuss architectutral decisions (framework changes, major refactoring, system design) together before implementation. Routine fixes and clear implementations don't need discussion. - -## Proactiveness - -When asked to do something, just do it - including obvious follow-up actions needed to complete the task properly. -Only pause to ask for confirmation when: - -- Multiple valid approaches exist and the choice matters -- The action would delete or significantly restructure existing code -- You genuinely don't understand what's being asked -- Your partner asked a question (answer the question, don't jump to implementation) - -@.claude/docs/WORKFLOWS.md -@package.json - -## Essential Commands - -| Task | Command | Notes | -|-----------------|--------------------------|-------------------------------------| -| **Development** | `./scripts/develop.sh` | ⚠️ Don't use manual build | -| **Build** | `make build` | Fat binaries (includes server) | -| **Build Slim** | `make build-slim` | Slim binaries | -| **Test** | `make test` | Full test suite | -| **Test Single** | `make test RUN=TestName` | Faster than full suite | -| **Test Race** | `make test-race` | Run tests with Go race detector | -| **Lint** | `make lint` | Always run after changes | -| **Generate** | `make gen` | After database changes | -| **Format** | `make fmt` | Auto-format code | -| **Clean** | `make clean` | Clean build artifacts | -| **Pre-commit** | `make pre-commit` | Fast CI checks (gen/fmt/lint/build) | -| **Pre-push** | `make pre-push` | Heavier CI checks (allowlisted) | - -### Documentation Commands - -- `pnpm run format-docs` - Format markdown tables in docs -- `pnpm run lint-docs` - Lint and fix markdown files -- `pnpm run storybook` - Run Storybook (from site directory) - -## Critical Patterns - -Detailed workflow and topic guidance lives in the imported docs. Keep root -instructions focused on guardrails that agents should see immediately. - -- **Database changes**: Follow - [Database Development Patterns](.claude/docs/DATABASE.md). Modify - `coderd/database/queries/*.sql`, run `make gen`, update - `enterprise/audit/table.go` for audit errors, then run `make gen` again. -- **LSP navigation**: Use LSP tools first. See - [Modern Go](.claude/docs/GO.md) for Go LSP and - [Frontend Development Guidelines](site/AGENTS.md) for TypeScript LSP. -- **OAuth2 and authorization**: Follow - [OAuth2 Development Guide](.claude/docs/OAUTH2.md). OAuth2 endpoints must - use RFC-compliant errors such as `writeOAuth2Error(...)`, and public - endpoints that need system access should use `dbauthz.AsSystemRestricted`. -- **Chatd**: consult [Chatd Architecture](coderd/x/chatd/ARCHITECTURE.md) to - understand the architecture of the chatd subsystem. If the chatd subsystem - is changed in ways that affect the architecture, the architecture document - must be updated. You must not do it yourself though: leave TODO items in - sections that need to be added or updated, but the actual changes must be - made by a human - the PR author. That ensures the architecture document - remains clear and readable to other humans. -- **API design**: Follow the API guardrails in - [Development Workflows and Guidelines](.claude/docs/WORKFLOWS.md), - including swagger annotations for new public HTTP endpoints. -- **Transactions and conversions**: Keep `InTx` work on the transaction - handle, and prefer explicit db-to-SDK converters. See - [Database Development Patterns](.claude/docs/DATABASE.md). -- **Testing**: Follow - [Testing Patterns and Best Practices](.claude/docs/TESTING.md). Use unique - identifiers in concurrent tests and do not use `time.Sleep` to mitigate - timing issues. -- **Frontend**: Read [Frontend Development Guidelines](site/AGENTS.md) - before changing anything under `site/`. Reuse shared UI primitives when - possible and prefer Storybook stories for component and page testing. -- **GitHub Actions permissions**: Follow least privilege as recommended by - OpenSSF Scorecard. Do not set write permissions at the workflow - (top) level. Default every workflow to `permissions: {}` at the top level - and grant only the specific permissions each job needs under - `jobs..permissions`. - -## Quick Reference - -### Full workflows available in imported WORKFLOWS.md - -### Git Hooks (MANDATORY - DO NOT SKIP) - -You MUST install and use the git hooks. NEVER bypass them with -`--no-verify`. Skipping hooks wastes CI cycles and is unacceptable. - -The first run can be slow while caches warm up. Wait for hooks to complete, -even when `git commit` or `git push` appears to hang. - -See [Development Workflows and Guidelines](.claude/docs/WORKFLOWS.md) for -hook setup, pre-commit behavior, pre-push behavior, and failure handling. - -### Git Workflow - -When working on existing PRs, check out the branch first. See -[Development Workflows and Guidelines](.claude/docs/WORKFLOWS.md) for the -full workflow. Don't use `git push --force` unless explicitly requested. - -### New Feature Checklist - -See [Development Workflows and Guidelines](.claude/docs/WORKFLOWS.md) for -the new feature checklist, including `git pull`, database migration checks, -and audit table checks. - -## Architecture - -- **coderd**: Main API service -- **provisionerd**: Infrastructure provisioning -- **Agents**: Workspace services (SSH, port forwarding) -- **Database**: PostgreSQL with `dbauthz` authorization - -## Code Style - -### Detailed guidelines in imported WORKFLOWS.md - -- Follow [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) -- Commit format: `type(scope): message` -- PR titles follow the same `type(scope): message` format. -- When you use a scope, it must be a real filesystem path containing every - changed file. -- Use a broader path scope, or omit the scope, for cross-cutting changes. -- Example: `fix(coderd/chatd): ...` for changes only in `coderd/chatd/`. - -### Frontend Patterns - -- Prefer existing shared UI components and utilities over custom - implementations. Reuse common primitives such as loading, table, and error - handling components when they fit the use case. -- Use Storybook stories for all component and page testing, including - visual presentation, user interactions, keyboard navigation, focus - management, and accessibility behavior. Do not create standalone - vitest/RTL test files for components or pages. Stories double as living - documentation, visual regression coverage, and interaction test suites - via `play` functions. Reserve plain vitest files for pure logic only: - utility functions, data transformations, hooks tested via - `renderHook()` that do not require DOM assertions, and query/cache - operations with no rendered output. - -### Writing Comments and Avoiding Unnecessary Changes - -See [Modern Go](.claude/docs/GO.md) for comment formatting and the rule to -avoid unrelated edits. Preserve existing comments that explain non-obvious -behavior unless the task directly requires changing them. - -Comments MUST be **substantive** and **concise**. Describe the **behaviour** -of the code, not the reasoning the agent used to produce the change. Do not -leave comments like `// Added per PR feedback` or `// Refactored for -clarity`. Instead, explain what the code does and why the behaviour matters. - -### No Emdash or Endash - -Do not use emdash (U+2014), endash (U+2013), or ` -- ` as punctuation -in code, comments, string literals, or documentation. Use commas, -semicolons, or periods instead. Restructure the sentence if needed. -Do not replace an emdash with ` -- `. Unicode emdash and endash are -caught by `make lint/emdash`. - -```go -// Good: uses a period to separate the clauses. -// This is slow. We should cache it. - -// Good: uses a comma to join related clauses. -// This is slow, so we should cache it. -``` - -## Detailed Development Guides - -@.claude/docs/ARCHITECTURE.md -@.claude/docs/GO.md -@.claude/docs/OAUTH2.md -@.claude/docs/TESTING.md -@.claude/docs/TROUBLESHOOTING.md -@.claude/docs/DATABASE.md -@.claude/docs/PR_STYLE_GUIDE.md -@.claude/docs/DOCS_STYLE_GUIDE.md - -If your agent tool does not auto-load `@`-referenced files, read these -manually before starting work: - -**Always read:** - -- `.claude/docs/WORKFLOWS.md` - dev server, git workflow, hooks - -**Read when relevant to your task:** - -- `.claude/docs/GO.md` - Go patterns and modern Go usage (any Go changes) -- `.claude/docs/TESTING.md` - testing patterns, race conditions (any test changes) -- `.claude/docs/DATABASE.md` - migrations, SQLC, audit table (any DB changes) -- `.claude/docs/ARCHITECTURE.md` - system overview (orientation or architecture work) -- `.claude/docs/PR_STYLE_GUIDE.md` - PR description format (when writing PRs) -- `.claude/docs/OAUTH2.md` - OAuth2 and RFC compliance (when touching auth) -- `.claude/docs/TROUBLESHOOTING.md` - common failures and fixes (when stuck) -- `.claude/docs/DOCS_STYLE_GUIDE.md` - docs prose and formatting (when writing `docs/`) -- `docs/.style/content-guidelines.md` - canonical content scope and routing rules (when writing `docs/`; governs on conflicts with the style guide) -- `.claude/skills/write-docs/SKILL.md` - authoring workflow and guardrails (for new, moved, or restructured `docs/` pages) - -**For frontend work**, also read `site/AGENTS.md` before making any changes -in `site/`. - -## Local Configuration - -These files may be gitignored, read manually if not auto-loaded. - -@AGENTS.local.md - -## Common Pitfalls - -1. **Audit table errors** → Update `enterprise/audit/table.go` -2. **OAuth2 errors** → Return RFC-compliant format -3. **Race conditions** → Use unique test identifiers -4. **Missing newlines** → Ensure files end with newline - ---- - -*This file stays lean and actionable. Detailed workflows and explanations are imported automatically.* +Make the smallest correct change, follow existing patterns, and verify the result. Ask only when the request is unclear, a meaningful design choice remains, or the action is destructive. If you want an exception to any rule in these documents, stop and get explicit permission first. + +Prioritize correctness over agreement. State uncertainty instead of guessing, and push back on technically unsound requests with evidence. + +## Task-specific guidance + +Load only the guidance relevant to the task: + +| Scope | Guidance | +|-----------------------------------------------------|---------------------------------------------------------| +| Development servers, Git, hooks, and routine checks | [WORKFLOWS.md](.claude/docs/WORKFLOWS.md) | +| API endpoints and Swagger | [WORKFLOWS.md](.claude/docs/WORKFLOWS.md) | +| Go | [GO.md](.claude/docs/GO.md) | +| Tests and concurrency | [TESTING.md](.claude/docs/TESTING.md) | +| Database and SQLC | [DATABASE.md](.claude/docs/DATABASE.md) | +| OAuth2 and authorization | [OAUTH2.md](.claude/docs/OAUTH2.md) | +| Architecture | [ARCHITECTURE.md](.claude/docs/ARCHITECTURE.md) | +| Troubleshooting | [TROUBLESHOOTING.md](.claude/docs/TROUBLESHOOTING.md) | +| Observability | [OBSERVABILITY.md](.claude/docs/OBSERVABILITY.md) | +| Isolation, ports, and cleanup | [DEV_ISOLATION.md](.claude/docs/DEV_ISOLATION.md) | +| Failure reports | [AGENT_FAILURES.md](.claude/docs/AGENT_FAILURES.md) | +| PR descriptions | [PR_STYLE_GUIDE.md](.claude/docs/PR_STYLE_GUIDE.md) | +| Existing docs prose | [docs style guide](docs/.style/style-guide/README.md) | +| Docs scope and routing | [content guidelines](docs/.style/content-guidelines.md) | +| Docs structure and research | [DOCS_STYLE_GUIDE.md](.claude/docs/DOCS_STYLE_GUIDE.md) | +| New, moved, or restructured docs | [write-docs skill](.claude/skills/write-docs/SKILL.md) | +| Frontend | [site/AGENTS.md](site/AGENTS.md) | + +For changes under `site/src/`, also read [FRONTEND_PATTERNS.md](.claude/docs/FRONTEND_PATTERNS.md). For chatd work, read [coderd/x/chatd/ARCHITECTURE.md](coderd/x/chatd/ARCHITECTURE.md). When the docs style guide and the content guidelines conflict, the content guidelines govern scope and routing. + +## Workflow + +- Inspect the working tree before editing. For an existing PR, check out its branch first. +- Discuss architectural decisions such as framework changes, major refactoring, and system design before implementing them. Routine fixes and clear implementations do not need discussion. +- When asked a question, answer the question instead of jumping to implementation. +- Install and use the repository Git hooks. Never bypass them with `--no-verify`. Wait for slow first runs while caches warm. +- Prefer targeted tests and checks while iterating. Run the broader checks required by the affected area before handoff. +- Do not force-push unless explicitly requested. +- Commit and PR titles use `type(scope): message`. A scope must be a real path containing every changed file. Use a broader scope or no scope for cross-cutting changes. + +## Essential commands + +| Task | Command | +|-------------------|--------------------------| +| Develop | `./scripts/develop.sh` | +| Build | `make build` | +| Build slim | `make build-slim` | +| Test | `make test` | +| Test one | `make test RUN=TestName` | +| Race test | `make test-race` | +| Lint | `make lint` | +| Generate | `make gen` | +| Format | `make fmt` | +| Pre-commit checks | `make pre-commit` | +| Pre-push checks | `make pre-push` | + +Docs use `pnpm run format-docs` and `pnpm run lint-docs`. Frontend commands live in `site/AGENTS.md`. + +## Repository guardrails + +- **Database changes:** edit `coderd/database/queries/*.sql`, run `make gen`, update `enterprise/audit/table.go` for audit errors, then run `make gen` again. +- **OAuth2:** return RFC-compliant errors such as `writeOAuth2Error(...)`. Public endpoints that need system access use `dbauthz.AsSystemRestricted`. +- **Chatd:** when a change affects the documented architecture, do not edit the architecture document yourself. Leave TODO items in the affected sections; the human PR author writes the actual updates. +- **Public API:** add the required Swagger annotations for new public HTTP endpoints. +- **Transactions:** keep `InTx` work on the transaction handle. Prefer explicit database-to-SDK converters. +- **Concurrent tests:** call `t.Parallel()`, use unique identifiers, and do not use `time.Sleep` to mask timing problems. +- **Frontend:** reuse shared UI primitives and test components or pages through Storybook stories. Plain Vitest files are for pure logic only. +- **GitHub Actions:** set top-level `permissions: {}` and grant only required permissions per job. + +## Code and writing style + +- Follow the [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) for Go code. +- Use language-server navigation when available. +- Name code for what it does, not its implementation or history. Wrap errors with context. +- Document exported symbols with idiomatic Go doc comments or JSDoc. +- Avoid unrelated edits. Preserve comments that explain non-obvious behavior. +- Comments must be concise and substantive. Explain behavior, constraints, or rationale, not the history of the edit. +- Do not use em dashes, en dashes, or spaced double hyphens as punctuation in code, comments, strings, or documentation. +- Ensure files end with a newline. + +## Local configuration + +Read `AGENTS.local.md` when present. It may be gitignored and is not imported automatically. diff --git a/site/AGENTS.md b/site/AGENTS.md index 6640567b485..1471db301b8 100644 --- a/site/AGENTS.md +++ b/site/AGENTS.md @@ -1,344 +1,91 @@ # Frontend Development Guidelines -## Frontend Non-Negotiables (FE rules) - -Read [Frontend Patterns](../.claude/docs/FRONTEND_PATTERNS.md) before changing -anything under `site/src/`. It is the canonical contract behind these rule -IDs; reviewers cite them as FE1 to FE10. - -- **FE1**: UI behavior changes ship with Storybook stories whose `play` - function exercises the real interaction. Jest/RTL is for pure logic only. -- **FE2**: No `any`, no `as unknown as`, no avoidable `as` casts. Use - generated types from `api/typesGenerated.ts`. -- **FE3**: Search for an existing component or helper before writing one. - Keep PRs single-purpose. -- **FE4**: No comments that restate identifiers, assertions, or control flow. -- **FE5**: Every view handles loading, error, empty, and refetch states - without clobbering user state. -- **FE6**: Interactive elements stay keyboard-reachable with correct - accessible names. -- **FE7**: All server data through react-query. Import query key constants, - never re-type them as string literals. -- **FE8**: `useEffect` only to synchronize with external systems. Never - derive state or chain fetches in effects. -- **FE9**: Share entity fixtures as `Mock*` constants; compose story query - wiring inline per story. -- **FE10**: Tests query semantic roles and names. No `querySelector` or - class-name assertions. - -## TypeScript LSP Navigation (USE FIRST) - -When investigating or editing TypeScript/React code, always use the TypeScript language server tools for accurate navigation: - -- **Find component/function definitions**: `mcp__typescript-language-server__definition ComponentName` - - Example: `mcp__typescript-language-server__definition LoginPage` -- **Find all usages**: `mcp__typescript-language-server__references ComponentName` - - Example: `mcp__typescript-language-server__references useAuthenticate` -- **Get type information**: `mcp__typescript-language-server__hover site/src/pages/LoginPage.tsx 42 15` -- **Check for errors**: `mcp__typescript-language-server__diagnostics site/src/pages/LoginPage.tsx` -- **Rename symbols**: `mcp__typescript-language-server__rename_symbol site/src/components/Button.tsx 10 5 PrimaryButton` -- **Edit files**: `mcp__typescript-language-server__edit_file` for multi-line edits - -## Bash commands - -- `pnpm dev` - Start Vite development server -- `pnpm storybook --no-open` - Start Storybook dev server -- `pnpm test:storybook` - Run storybook story tests (play functions) via Vitest + Playwright -- `pnpm test:storybook src/path/to/component.stories.tsx` - Run a single story file -- `pnpm test` - Run jest unit tests -- `pnpm test -- path/to/specific.test.ts` - Run a single test file -- `pnpm lint` - Run complete linting suite (Biome + TypeScript + circular deps + knip) -- `pnpm lint:fix` - Auto-fix linting issues where possible -- `pnpm playwright:test` - Run playwright e2e tests. When running e2e tests, remind the user that a license is required to run all the tests -- `pnpm format` - Format frontend code. Always run before creating a PR - -## Storybook MCP - -The `.mcp.json` at the repo root includes a Storybook MCP server -(`http://localhost:6006/mcp`). It provides tools for searching components, -reading stories, and capturing screenshots directly from Storybook. - -Because it is an HTTP-type MCP server, Storybook must already be running -before the MCP client can connect. Start it first: - -```sh -pnpm storybook --no-open -``` - -## Failure artifacts - -Playwright writes per-test failure artifacts to `site/test-results/` when -running `pnpm playwright:test` from `site/`. Failed tests keep screenshots, -videos, and traces through the Playwright config. The HTML report is written -to `site/playwright-report/`, and the coderd debug log is written to -`site/e2e/test-results/debug.log`. - -In CI, the `test-e2e` job uploads failure artifacts to the workflow run's -Artifacts section. Look for artifact names prefixed with -`playwright-artifacts-`, followed by the matrix job name and commit SHA. -Debug logs and pprof dumps use the same job name and commit SHA convention. - -## Components - -- Use shadcn/ui components first - check `site/src/components` for existing implementations. -- Do not use shadcn CLI - manually add components to maintain consistency -- The modules folder should contain components with business logic specific to the codebase. -- Create custom components only when shadcn alternatives don't exist -- **Before creating any new component**, search the codebase for existing - implementations. Check `site/src/components/` for shared primitives - (Table, Badge, icons, error handlers) and sibling files for local - helpers. Duplicating existing components wastes effort and creates - maintenance burden. -- **Modifying core components is a cross-cutting change.** Treat new - exports or visual changes in `site/src/components/` differently from - feature-folder edits. They affect every consumer across the site, so - coordinate with design before extending them. When you need a small - variant of a shared primitive (for example, a separator with - feature-specific styling), define it locally in your feature folder - first and graduate it later if a shared design lands. -- Keep component files under ~500 lines. When a file grows beyond that, - extract logical sections into sub-components or a folder with an - index file. - -## Styling - -- Use Tailwind CSS for styling. -- Use custom Tailwind classes in tailwind.config.js. -- Responsive design - use Tailwind's responsive prefixes (sm:, md:, lg:, xl:) -- Do not use `dark:` prefix for dark mode - -## Tailwind Best Practices - -- Group related classes -- Use semantic color names from the theme inside `tailwind.config.js` including `content`, `surface`, `border`, `highlight` semantic tokens -- Prefer Tailwind utilities over custom CSS when possible - -## General Code style - -- Use ES modules (import/export) syntax, not CommonJS (require) -- Destructure imports when possible (eg. import { foo } from 'bar') -- Prefer `for...of` over `forEach` for iteration -- **Biome** handles both linting and formatting (not ESLint/Prettier) -- Access browser globals like `location`, `navigator`, and `document` - directly. Do not prefix them with `window.` (e.g., write - `location.href`, not `window.location.href`). They are globally - available in every browser context. -- Do not use `typeof window`, `typeof document`, or similar runtime checks for browser globals. Coder is a pure SPA so these globals are always available. -- Always use react-query for data fetching. Do not attempt to manage any - data life cycle manually. Do not ever call an `API` function directly - within a component. -- **Match existing patterns** in the same file before introducing new - conventions. For example, if sibling API methods use a shared helper - like `getURLWithSearchParams`, do not manually build `URLSearchParams`. - If sibling components initialize state with `useMemo`, don't switch to - `useState(initialFn)` in the same file without reason. -- Match errors by error code or HTTP status, never by comparing error - message strings. String matching is brittle; messages change, get - localized, or get reformatted. -- Do not use emdash (U+2014), endash (U+2013), or ` -- ` as punctuation - in code, comments, string literals, or documentation. Use commas, - semicolons, or periods instead. Restructure the sentence if needed. -- For JSX boolean props that are `true`, use the shorthand form - (``) instead of ``. The two are - equivalent; the shorthand is the React convention and reduces noise. -- **Avoid unnecessary indirection.** Inline single-use module-level - constants, single-use aliases, and one-line helpers that just return a - single field at the call site. Do not create wrapper hooks that only - delegate to a library hook plus a couple of derived booleans. Inline - the call at each site instead. Indirection should pay for itself with - shared usage or non-trivial logic; otherwise it adds a layer reviewers - have to navigate without explaining anything. -- **Re-evaluate helpers after upstream refactors.** When you change how - a value is computed (for example, by moving fallback logic into the - builder), check whether existing helpers that consumed that value have - collapsed to a pass-through. If a helper now just returns a single - field, delete it and inline the field access at the call sites. - -## TypeScript Type Safety - -- **Never use `as unknown as X`** double assertions. They bypass - TypeScript's type system entirely and hide real type incompatibilities. - If types don't align, fix the types at the source. -- **Prefer type annotations over `as` casts.** When narrowing is needed, - use type guards or conditional checks instead of assertions. -- **Avoid the non-null assertion operator (`!.`)**. If a value could be - null/undefined, add a proper guard or narrow the type. If it can never - be null, fix the upstream type definition to reflect that. -- **Use generated types from `api/typesGenerated.ts`** for all - API/server types. Never manually re-declare types that already exist in - generated code — duplicated types drift out of sync with the backend. -- If a component's implementation depends on a prop being present, make - that prop **required** in the type definition. Optional props that are - actually required create a false sense of flexibility and hide bugs. -- Avoid `// @ts-ignore` and `// eslint-disable`. If they seem necessary, - document why and seek a better-typed alternative first. - -## React Query Patterns - -- **Query keys must nest** under established parent key hierarchies. For - example, use `["chats", "costSummary", ...]` not `["chatCostSummary"]`. - Flat keys that break hierarchy prevent - `queryClient.invalidateQueries(parentKey)` from correctly invalidating - related queries. -- When you don't need to `await` a mutation result, use **`mutate()`** - with `onSuccess`/`onError` callbacks — not `mutateAsync()` wrapped in - `try/catch` with an empty catch block. Empty catch blocks silently - swallow errors. `mutate()` automatically surfaces errors through - react-query's error state. - -## Accessibility - -- Every `` / `
` must have an **`aria-label`** or - `
` so screen readers can distinguish between multiple tables - on a page. -- Every element with `tabIndex={0}` must have a semantic **`role`** - attribute (e.g., `role="button"`, `role="row"`) so assistive technology - can communicate what the element is. -- When hiding an interactive element visually (e.g., `opacity-0`, - `pointer-events-none`), you **must also** remove it from the keyboard - tab order and accessibility tree. Add `tabIndex={-1}` and - `aria-hidden="true"`, or better yet, conditionally render the element - so it's not in the DOM at all. `pointer-events: none` only suppresses - mouse/touch — keyboard and screen readers still reach the element. - -## Testing Patterns - -- **Assert observable behavior, not CSS class names.** In Storybook play - functions and tests, use queries like `queryByRole`, `toBeVisible()`, - or `not.toBeVisible()` — not assertions on class names like - `opacity-0`. Asserting class names couples tests to the specific - Tailwind/CSS technique and breaks when the styling mechanism changes - without user-visible regression. -- **Use `data-testid`** for test element lookup when an element has no - semantic role or accessible name (e.g., scroll containers, wrapper - divs). Never use CSS class substring matches like - `querySelector("[class*='flex-col-reverse']")` — these break silently - on class renames or Tailwind output changes. -- **Don't depend on `behavior: "smooth"` scroll** in tests. Smooth - scrolling is async and implementation-defined — in test environments, - `scrollTo` may not produce native scroll events at all. Use - `behavior: "instant"` in test contexts or mock the scroll position - directly. -- When modifying a component's visual appearance or behavior, **update or - add Storybook stories** to capture the change. Stories must stay - current as components evolve — stale stories hide regressions. - -## Robustness - -- When rendering user-facing text from nullable/optional data, always - provide a **visible fallback** (e.g., "Untitled", "N/A", em-dash). - Never render a blank cell or element. -- When converting strings to numbers (e.g., `Number(apiValue)`), **guard - against `NaN`** and non-finite results before formatting. For example, - `Number("abc").toFixed(2)` produces `"NaN"`. -- When using `toLocaleString()`, always pass an **explicit locale** - (e.g., `"en-US"`) for deterministic output across environments. Without - a locale, `1234` formats as `"1.234"` in `de-DE` but `"1,234"` in - `en-US`. +Read [Frontend Patterns](../.claude/docs/FRONTEND_PATTERNS.md) before changing `site/src/`. It is the canonical contract for FE1 through FE10. + +## Frontend contract + +- **FE1:** UI behavior changes ship with Storybook stories whose `play` function exercises the real interaction. Vitest or RTL is for pure logic only. +- **FE2:** No `any`, `as unknown as`, or avoidable casts. Use generated API types from `api/typesGenerated.ts`. +- **FE3:** Search for an existing component or helper before writing one. Keep changes single-purpose. +- **FE4:** Do not add comments that restate identifiers, assertions, or control flow. +- **FE5:** Views handle loading, error, empty, and refetch states without clobbering user state. +- **FE6:** Interactive elements remain keyboard reachable and have correct accessible names. +- **FE7:** Use React Query for server data. Import query key constants instead of retyping string literals. +- **FE8:** Use `useEffect` only to synchronize with external systems. Do not derive state or chain fetches in effects. +- **FE9:** Share entity fixtures as `Mock*` constants. Compose story query wiring inline per story. +- **FE10:** Tests query semantic roles and names. Do not use `querySelector` or class-name assertions. + +## Navigation and commands + +Use the TypeScript language server when available for definitions, references, type information, diagnostics, and renames. + +| Task | Command | +|------------------|---------------------------------------------------------| +| Develop | `pnpm dev` | +| Storybook | `pnpm storybook --no-open` | +| Story tests | `pnpm test:storybook` | +| One story file | `pnpm test:storybook src/path/to/component.stories.tsx` | +| Unit tests | `pnpm test` | +| One unit file | `pnpm test path/to/file.test.ts` | +| Typecheck | `pnpm lint:types` | +| Biome check | `pnpm check` | +| Lint | `pnpm lint` | +| Fix lint | `pnpm lint:fix` | +| Format | `pnpm format` | +| End-to-end tests | `pnpm playwright:test` | + +Some end-to-end tests require a license. The Storybook MCP at `http://localhost:6006/mcp` requires Storybook to be running. + +## Components and styling + +- Use existing shadcn components and Tailwind CSS. MUI and Emotion have been removed; do not reintroduce them. +- Search `site/src/components/` and nearby feature code before creating a component or helper. +- Add shadcn components manually. Do not use the shadcn CLI. +- Keep business-specific components in feature modules. Create shared components only when reuse is established. +- Changes to core components are cross-cutting. Coordinate visual or API expansion with design when needed. +- Keep component files near 500 lines or less. Extract coherent sections when a file becomes difficult to navigate. +- Use semantic theme colors and existing Tailwind tokens. Do not use the `dark:` prefix. + +## TypeScript and data flow + +- Use ES modules and Biome. Prefer `for...of` over `forEach`. +- Access browser globals directly. This is a client-only SPA, so do not guard them with `typeof window` or similar checks. +- Components must not call API functions directly. Use established React Query definitions and key hierarchies. +- Use `mutate()` with callbacks when the result does not need to be awaited. Do not swallow mutation failures in empty catches. +- Prefer generated types, annotations, guards, and upstream type fixes over assertions or non-null assertions. +- Match errors by code or HTTP status, not message text. +- Match patterns in the same file before introducing a new convention. +- Avoid single-use wrappers, aliases, constants, and hooks that add navigation without adding meaning. +- Use JSX shorthand for boolean props whose value is `true`. + +## Accessibility and robustness + +- Every table has an `aria-label` or caption. +- Elements with `tabIndex={0}` have an appropriate semantic role. +- Visually hidden interactive elements must also leave the tab order and accessibility tree. Prefer conditional rendering. +- Render a visible fallback such as `Unknown` or `N/A` for missing user-facing text. +- Guard number conversions against `NaN` and non-finite values. +- Pass an explicit locale to `toLocaleString()` for deterministic output. +- Do not use em dashes, en dashes, or spaced double hyphens as punctuation. + +## Testing + +- Add or update Storybook stories for component and page behavior, visual states, keyboard interaction, focus, and accessibility. +- Assert observable behavior with semantic queries. Do not assert Tailwind classes or implementation details. +- Use `data-testid` only when an element has no suitable role or accessible name. +- Do not depend on smooth scrolling in tests. Use instant behavior or control the scroll position directly. +- Keep stories current when components change. ## Performance -- `src/pages/AgentsPage/` (including `components/ChatElements/`) is opted - into React Compiler via `babel-plugin-react-compiler`. The compiler - automatically memoizes values, callbacks, and JSX at build time. Do - not add `useMemo`, `useCallback`, or `memo()` in these directories - — the compiler handles it. The only exception is `memo()` on - list-item components rendered in a `.map()` (e.g. `ChatMessageItem`, - `Tool`, `ChatTreeNode`, `LazyFileDiff`) because the compiler does - not add `React.memo()` behavior across component boundaries. -- When adding state that changes frequently (scroll position, hover, - animation frame), **extract the state and its dependent UI into a child - component** rather than keeping it in a parent that renders a large - subtree. This prevents React from re-rendering the entire subtree on - every state change. -- **Throttle high-frequency event handlers** (scroll, resize, mousemove) - that call `setState`. Use `requestAnimationFrame` or a throttle - utility. Even when React skips re-renders for identical state, the - handler itself still runs on every frame (60Hz+). - -## Workflow - -- Be sure to typecheck when you're done making a series of code changes -- Prefer running single tests, and not the whole test suite, for performance -- Some e2e tests require a license from the user to execute -- Use pnpm format before creating a PR -- **ALWAYS use TypeScript LSP tools first** when investigating code - don't manually search files - -## Pre-PR Checklist - -1. `pnpm check` - Ensure no TypeScript errors -2. `pnpm lint` - Fix linting issues -3. `pnpm format` - Format code consistently -4. `pnpm test` - Run affected unit tests -5. Visual check in Storybook if component changes -6. If the diff touches `site/src/`, run the `frontend-review` skill - (discovered from `.agents/skills/`; canonical copy at - [.claude/skills/frontend-review](../.claude/skills/frontend-review/SKILL.md)): - audit the diff against FE1 to FE10 and fix every FAIL before creating - the PR - -## React Rules - -### 1. Purity & Immutability - -- **Components and custom Hooks must be pure and idempotent**—same inputs → same output; move side-effects to event handlers or Effects. -- **Never mutate props, state, or values returned by Hooks.** Always create new objects or use the setter from useState. - -### 2. Rules of Hooks - -- **Only call Hooks at the top level** of a function component or another custom Hook—never in loops, conditions, nested functions, or try / catch. -- **Only call Hooks from React functions.** Regular JS functions, classes, event handlers, useMemo, etc. are off-limits. - -### 3. React orchestrates execution - -- **Don't call component functions directly; render them via JSX.** This keeps Hook rules intact and lets React optimize reconciliation. -- **Never pass Hooks around as values or mutate them dynamically.** Keep Hook usage static and local to each component. - -### 4. State Management - -- After calling a setter you'll still read the **previous** state during the same event; updates are queued and batched. -- Use **functional updates** (setX(prev ⇒ …)) whenever next state depends on previous state. -- Pass a function to useState(initialFn) for **lazy initialization**—it runs only on the first render. -- If the next state is Object.is-equal to the current one, React skips the re-render. - -### 5. Effects - -- An Effect takes a **setup** function and optional **cleanup**; React runs setup after commit, cleanup before the next setup or on unmount. -- The **dependency array must list every reactive value** referenced inside the Effect, and its length must stay constant. -- Effects run **only on the client**, never during server rendering. -- Use Effects solely to **synchronize with external systems**; if you're not "escaping React," you probably don't need one. -- **Never use `useEffect` to derive state from props or other state.** If - a value can be computed during render, use `useMemo` or a plain - variable. A `useEffect` that reads state A and calls `setState(B)` on - every change is a code smell — it causes an extra render cycle and adds - unnecessary complexity. - -### 6. Lists & Keys - -- Every sibling element in a list **needs a stable, unique key prop**. Never use array indexes or Math.random(); prefer data-driven IDs. -- Keys aren't passed to children and **must not change between renders**; if you return multiple nodes per item, use `` -- **Never use `key={String(booleanState)}`** to force remounts. When the - boolean flips, React unmounts and remounts the component synchronously, - killing exit animations (e.g., dialog close transitions) and wasting - renders. Use a monotonically increasing counter or avoid `key` for - this pattern entirely. - -### 7. Refs & DOM Access - -- useRef stores a mutable .current **without causing re-renders**. -- **Don't call Hooks (including useRef) inside loops, conditions, or map().** Extract a child component instead. -- **Avoid reading or mutating refs during render;** access them in event handlers or Effects after commit. - -### 8. Element IDs - -- **Use `React.useId()`** to generate unique IDs for form elements, - labels, and ARIA attributes. Never hard-code string IDs — they collide - when a component is rendered multiple times on the same page. +- `src/pages/AgentsPage/`, including `components/ChatElements/`, uses React Compiler. Do not add `useMemo`, `useCallback`, or `memo()` there. +- `memo()` remains valid for list-item components rendered in a map because compiler memoization does not cross component boundaries. +- Isolate frequently changing state in a small child component instead of rerendering a large parent subtree. +- Throttle high-frequency handlers that set state with `requestAnimationFrame` or an established throttle utility. -### 9. Component Testability +## Completion -- When a component depends on a dynamic value like the current time or - date, **accept it as a prop** (or via context) rather than reading it - internally (e.g., `new Date()`, `Date.now()`). This makes the - component deterministic and testable in Storybook without mocking - globals. +- Run targeted story or unit tests during iteration. +- Visually inspect affected component stories before handoff. +- Before handoff, run `pnpm check`, `pnpm lint`, and `pnpm format`, plus affected tests. +- For changes under `site/src/`, run the repository `frontend-review` skill at `.claude/skills/frontend-review/SKILL.md` and fix each applicable FE1 through FE10 failure.