- After making any changes, always run
bun run cibefore handing work back. - Keep Biome completely clean: warnings and unused suppression comments are CI failures.
- Run
bun run ciagain immediately before every push, and do not push unless it passes for the exact commit being pushed. While GitHub Actions is unavailable, local CI is the required merge gate; do not wait for a GitHub Actions status check to merge. bun run cimust run the Ultracite-configured Biome checks and Tailwind CSS language-server diagnostics automatically, followed by the unit tests, TypeScript check, and production build.- Prefer behavior-focused tests. Do not assert static copy or CSS classes unless they are dynamic or contract-critical; tests that merely mirror markup add maintenance without protecting behavior.
- Fix all reported issues rather than bypassing or disabling checks unless the project requirements explicitly demand an exception.
- Keep the codebase as DRY as practical: before adding constants, calculations, formatting, parsing, labels, or state-derivation logic, search for an existing domain utility and reuse or extend it. Consolidate meaningful duplication into clearly named domain modules, but do not introduce generic abstractions that hide simple behavior or couple unrelated concepts solely because their implementations look similar.
- Make dashboard numbers as large, high-contrast, and easy to read at a glance as the available layout practically allows. Numeric ride status must be visually dominant over its label; do not use caption-sized values when space exists for prominent dashboard typography.
- Treat motion that communicates live application state or progress as functional, not decorative. Do not disable essential dashboard, connection, loading, route-position, or workout animations solely because Chromium reports
prefers-reduced-motion; instead keep the motion calm and legible, and verify time-based state changes in the tested browser because its automation or accessibility defaults may enable reduced motion unexpectedly. - Keep modal and dialog headers direct: use one clear title and do not add decorative eyebrow, kicker, category, or status text above it (especially small uppercase labels) unless the user explicitly requests that treatment.
- Do not scatter raw string literals for shared domain modes through comparisons or state construction. Define or reuse a named
as constdomain object, derive its union type from those values, centralize validation of persisted or external strings, and reference the named members in application code. Prefer an exhaustiveswitchwhen every variant has distinct behavior. Raw strings remain appropriate for display text, object property names, browser or protocol values, and boundary-focused tests. - Treat TypeScript types as authoritative after data crosses a validated boundary. Do not add scattered inline runtime
typeofchecks for typed domain data; use ordinary presence checks for optional typed fields. Validate JSON, storage, browser, protocol, and other untyped inputs once through named reusable guards insrc/lib/type-guards.tsor a focused domain parser. Runtimetypeofchecks belong inside those guards; type-level queries such astypeof CONSTANTremain appropriate. - Never include AI assistant, product, vendor, or model names (such as
codexoropenai) in branch names, commit messages, pull request titles or descriptions, issue titles or descriptions, tags, release notes, or any other repository-visible metadata or content. - Name branches only after the work being performed, such as
refactor/tanstack-store; do not apply a tool's default branch prefix when that prefix would violate the naming rule above. - When the user says "add, commit", group all existing changes into logical sets, stage and commit each group, and repeat until every change is committed and the working tree is clean.
- Always make changes on a descriptively named task branch, never on
main. At the start of every new work request, check the current Git branch before changing any file; if the current branch ismain, create and switch to the task branch first. - Never push work directly to
main. Ifmainalready contains uncommitted changes or commits that have not been pushed, create the task branch from its current state so all of that work moves forward on the new branch, then continue the normal workflow there. - Treat "release" as exactly equivalent to "add, commit, push, pr, merge" and complete the same full delivery workflow.
- When the user says "add, commit, push, pr, merge" or otherwise confirms that the work is ready, complete the delivery workflow in order: group and commit all changes until the tree is clean, run
bun run cifor the exact commit being delivered, push the task branch, open a pull request targetingmain, and merge the pull request without depending on GitHub Actions while it is unavailable. If local CI fails or the pull request cannot merge, fix the problem on the same task branch and repeat the relevant steps. - Keep React component modules compatible with Vite Fast Refresh: export only React components from component files, and move non-component runtime exports such as constants, helpers, and metadata into separate modules to avoid incompatible-export invalidations.
- Record every new user-facing feature in the README as part of implementing it.