All magic numbers, strings, and tunable values belong in src/shared/constants.js. Never inline them in feature files.
This applies to:
- Timing values (delays, TTLs, timeouts, debounce durations)
- API URLs and version strings
- Token/character limits
- Validation bounds (min/max for inputs)
- Threshold values used in logic
If a value appears in more than one file, it must be a constant. If a value might need tuning, it must be a constant.
ANTHROPIC_API_URL and ANTHROPIC_VERSION are defined once in constants.js. Any file making a direct fetch to the Anthropic API (currently llm.js and the test-key call in Options.jsx) must import these — never re-declare them inline.
Before adding a statistic, counter, or status display to the UI, verify that the backing data is actually written somewhere. The popup's blocked/allowed stats are written in service-worker.js via incrementDailyStat — if you add new stat fields to the popup, add the corresponding write in the service worker first.
All blocking, snapshotting, and relevance-checking logic must be generic — it cannot contain special cases for a specific website (e.g. parsing YouTube video IDs, delaying extra time only on reddit.com, or adjusting selectors for a particular domain). If a site behaves differently, the general heuristics should be improved to handle it rather than adding a per-site branch. This keeps the extension maintainable and ensures every site is treated consistently.
All log calls must use the module-local log() function — never console.log directly. Every call takes exactly two arguments: a dot-namespaced event name string and a plain context object.
log('review.begin', { url, token, readyState: document.readyState });
log('check.fast.error', { tabId, url });Rules:
- Event names use dot-namespace:
category.eventorcategory.subcategory(e.g.spa.proactive_overlay,review.timeout_rescue) - The second argument is always a plain object — never a raw string, array, or additional positional arguments
- Every log call must include the fields most relevant to diagnosing that event (url, tabId, token, reason, etc.)
src/content/content-script.js is bundled by Vite and can import from src/shared/. Use shared constants rather than re-declaring values locally.
When modifying any file, update inline comments, JSDoc, and any .md files an agent might ingest (e.g. CLAUDE.md, README.md, DESIGN.md) if the change affects a rule or architectural decision documented there. This includes:
- Updating comments that describe behaviour you've changed
- Removing comments that describe code you've deleted
- Adding a comment when non-obvious logic is introduced
- Reflecting renamed constants, removed fields, or new features in relevant
.mdfiles
Documentation must be minimal — include only what is necessary to understand a decision or constraint that is not obvious from reading the code. Do not restate what the code already says, do not add historical notes, and do not pad .md files with context that will never be needed. Every sentence should earn its place.