From 004b63f51c91f1e01edee70e0c4a7c320d08e16e Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Mon, 11 May 2026 17:02:48 +0200 Subject: [PATCH 1/3] Add CLAUDE.md with build and architecture guidance Documents the dcat issue workflow rule, bun commands, and the non-obvious invariants future agents need: dist/ is the single source of truth for what ships, the Firefox 142 floor and no-gecko.update_url constraint for AMO-listed distribution, the pinned qrcode-generator SHA and UTF-8 override, and the popup error-path conventions. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b3e3b5b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,58 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Workflow + +- **Read `AGENTS.md` first.** It defines the mandatory `dcat` (dogcat) issue-tracking workflow used here. The hard rule: **before writing any code for a new bug, feature, or change, ask the user whether to create an issue first** — no exceptions for "small" tasks. Run `dcat prime` after compaction, `/clear`, or starting a new session. +- After committing, show a short summary of what was committed and why (per the user's global guidelines). + +## Commands + +```sh +bun run build # bundle popup.js + copy assets into dist/ +bun run lint # build, then web-ext lint (must be 0 errors / 0 warnings) +bun run package # build, then produce a signable .zip in web-ext-artifacts/ +bun run start # build, then launch Firefox with the extension (auto-reload) +``` + +There is no test suite. `bun run lint` is the closest thing to CI — it must pass clean before publishing. The first invocation downloads `web-ext` via `bunx`; subsequent runs are fast. + +Always use `bun` / `bunx` (never `npm`/`npx`/`yarn`). + +## Architecture + +Naiv-QR is a Manifest V3 Firefox extension with no background script and no content script — just a toolbar action that opens a popup. When the user clicks the icon, `popup/popup.js` runs once, reads the active tab's URL via `browser.tabs.query` (allowed by `activeTab` only on user gesture), and renders an SVG QR code locally using the vendored `qrcode-generator` library. There are zero network requests. + +### `dist/` is the only thing that ships + +`scripts/build.mjs` is the **single source of truth** for what the extension contains. It: + +1. Wipes `dist/`. +2. Runs `Bun.build` on `popup/popup.js` (esm, browser target, minified). The `import qrcode from "../vendor/qrcode.js"` line is what causes the vendored library to get inlined — there is no global `qrcode` at runtime. +3. Copies `manifest.json`, `popup/popup.html`, `popup/popup.css`, `icons/`, and `vendor/LICENSE.qrcode-generator` verbatim into `dist/`. + +`web-ext-config.cjs` points `web-ext` at `dist/` only, so lint/package/run all operate on the build output. **Adding a file to the repo does not put it in the extension** — if a new asset (icon, locale, script) needs to ship, update `scripts/build.mjs` to copy it. + +### Compatibility & distribution constraints + +- `manifest.json` sets `strict_min_version: 142.0`. This floor exists because `browser_specific_settings.gecko.data_collection_permissions` was introduced in Firefox 140 desktop / 142 Android. Don't lower it without also removing that field. +- Target distribution is **AMO-listed**. The manifest must **not** declare `gecko.update_url` — AMO handles auto-updates for listed extensions, and adding an update URL breaks the listed-channel review. +- Permissions are deliberately minimal: `activeTab` (read current tab on click) and `clipboardWrite` (Copy URL button). Adding a new permission needs explicit justification — it's user-visible at install/upgrade and surfaces during AMO review. +- `data_collection_permissions` declares `"none"`. If any code is ever added that does collect data (telemetry, error reporting, etc.), that field must be updated honestly — it's surfaced to users during AMO review and at install time. + +### Vendored QR library + +`vendor/qrcode.js` is [kazuhikoarase/qrcode-generator](https://github.com/kazuhikoarase/qrcode-generator), pinned to commit `83b7e8fe3fddd3b0368dbafd6ce56995bd25e3c8`. AMO source-code review requires we point reviewers at this pinned upstream. If the vendored file is updated, update the pinned SHA in `README.md` and `vendor/LICENSE.qrcode-generator` if needed. + +`popup.js` sets `qrcode.stringToBytes = qrcode.stringToBytesFuncs["UTF-8"]` because the library defaults to SJIS — without this, non-ASCII URLs would be misencoded. + +### Popup error paths + +`popup.js` has three "can't render" branches that all route through `showMessage()`: + +- `browser.tabs.query` throws → "Could not read the active tab." +- URL protocol is in `PRIVILEGED_PROTOCOLS` (`about:`, `moz-extension:`, `chrome:`, `view-source:`, `resource:`, `javascript:`, `data:`) → "This page can't be shared." +- `qrcode-generator` throws because the URL exceeds the largest QR version (~2,953 bytes for EC level L; we use M ≈ ~2,331) → "URL is too long to encode." + +When adding new error states, keep them on this same `showMessage()` path so the popup never ends up in an inconsistent half-rendered state. From 3fef3d85a8136a2074eca6e6beb2d31d67214469 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Mon, 11 May 2026 17:14:00 +0200 Subject: [PATCH 2/3] Forbid TodoWrite in CLAUDE.md; point at dcat workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the rule we already have in ønskenytt.no/CLAUDE.md so fresh agents don't reach for the built-in task tools when this repo manages work via dcat. Also switches the prime invocation to the recommended `dcat prime --opinionated` form. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index b3e3b5b..4096d9a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Workflow -- **Read `AGENTS.md` first.** It defines the mandatory `dcat` (dogcat) issue-tracking workflow used here. The hard rule: **before writing any code for a new bug, feature, or change, ask the user whether to create an issue first** — no exceptions for "small" tasks. Run `dcat prime` after compaction, `/clear`, or starting a new session. +- **Read `AGENTS.md` first.** It defines the mandatory `dcat` (dogcat) issue-tracking workflow used here. The hard rule: **before writing any code for a new bug, feature, or change, ask the user whether to create an issue first** — no exceptions for "small" tasks. Run `dcat prime --opinionated` after compaction, `/clear`, or starting a new session. +- **Do NOT use the `TodoWrite` / task tools in this project.** Issue tracking and progress is managed with `dcat` as specified in `AGENTS.md` — see that file for the full workflow (`dcat prime --opinionated`, `dcat list --agent-only`, status transitions, closing rules, etc.). - After committing, show a short summary of what was committed and why (per the user's global guidelines). ## Commands From 31ffddfcf452c1ce8f3ba5655942962b7a7364d2 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Mon, 11 May 2026 17:14:41 +0200 Subject: [PATCH 3/3] Use `dcat prime --opinionated` in AGENTS.md Aligns with CLAUDE.md (commit 3fef3d8) so both files agree on the recommended prime invocation. Co-Authored-By: Claude Opus 4.7 (1M context) --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2949866..6e4d794 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ DOGCAT WORKFLOW GUIDE ## Rules - Run `dcat prime` after compaction, clear, or new session + Run `dcat prime --opinionated` after compaction, clear, or new session BEFORE writing any code for a new bug, feature, or change: ask the user if you should create an issue first. No exceptions for 'small' tasks — the rule exists for traceability, not