gh-reloaded

AGENTS.md

The rules for changing this codebase — for people and for coding assistants (Claude Code, Codex, and anything else that reads an AGENTS.md). Every convention lives here exactly once; other files point at this one rather than repeating it.

What this project is

GH Reloaded is a Manifest V3 Chrome extension that injects small, focused UI enhancements into github.com. It’s a collection of independent features, not a single-purpose tool: each one lives in its own folder and can be added, removed, or shipped on its own.

Layout:

manifest.json            MV3 manifest — wires content scripts and the background service worker
background.js            Service worker entry point: opens Settings, routes messages to feature modules
background/<feature>.js  One feature's server-side logic (GitHub calls, computation) + its MESSAGE_TYPE
features/<feature>/      One feature's content-script side: DOM injection, rendering, styling
lib/github-api.js        Shared GitHub REST/GraphQL client (auth, caching) used by every feature
options/                 Settings page (GitHub tokens, quick-create shortcuts, feature toggles)
icons/                   Toolbar/extensions-page icons
screenshots/             SVG mockups illustrating each feature's layout and colors

The shape of a feature

Every feature is two loosely-coupled halves.

features/<name>/ — the content-script side. Runs in the page’s isolated world on whichever github.com pages it targets. Typically:

It’s a self-contained IIFE, not an ES module — content scripts don’t support import. If it needs data from GitHub, it messages the background rather than fetching directly.

background/<name>.js — the feature’s server-side logic, if it has any. An ES module (the service worker runs with "type": "module") that exports:

export const MESSAGE_TYPE = "MY_FEATURE_FETCH_X"; // unique across features
export async function handleMessage(payload) {
  // ... talk to GitHub via lib/github-api.js, compute whatever ...
  return { someKey: result }; // spread into the response the content script gets
}

Import it in background.js and add it to the FEATURES array — the generic message router there takes care of the rest (dispatch by MESSAGE_TYPE, token-presence flag, error shape). A feature with no background logic just skips this half.

lib/github-api.js is shared: auth, request caching, and generic REST/GraphQL helpers. Add a genuinely reusable helper there (not feature-specific parsing) if more than one feature needs it.

manifest.json: add your content script’s files to a content_scripts entry — reuse the existing one if your matches overlap with another feature’s, add a new entry otherwise.

The Chrome Web Store caps the manifest description at 132 characters and the name at 75, and version must be one to four dot-separated integers. Every file the manifest references must also be in the release zip (the zip -r step of release.yml). test/unit/manifest.test.js enforces all of this in npm test.

Design rules

Options / settings UX

The Settings page (options/) is an application settings UI: a compact app shell, not the product’s marketing website and not a clone of GitHub’s own settings.

Keep docs in sync with features

When a feature is added or its behavior changes, in the same pass (not as a follow-up):

Markdown style

Write one paragraph per line: no line break in the middle of a sentence or paragraph. Keep line breaks only between paragraphs, between list items, around headings, and inside code blocks. Long lines are expected — let the editor soft-wrap them rather than hard-wrapping at a column. This keeps diffs to a paragraph readable as a single changed line.

Definition of done

A change is ready to hand off when all of these hold:

Git and pull request conventions

Picking the PR type

The PR title’s type decides the next version, so pick it by what a user notices after updating:

The changelog lists Features, Bug Fixes and Performance. The rules are in release-please-config.json and test/unit/release-please-config.test.js checks them.

The Chrome Web Store accepts versions made of up to four dot-separated integers that always increase, with no pre-release suffix such as -beta.

Local testing

No build step. chrome://extensions → Developer mode → Load unpacked → select the repo folder → reload the extension (and the GitHub page) after each change.

Running the tests

The test harness lives under test/ and is dev-only — it is deliberately outside the paths the release workflow zips (manifest.json, background.js, background, features, icons, lib, options), so package.json, the fixtures, and the tests never ship in the extension. There is no bundler: the extension itself still loads unpacked, exactly as above.

One command runs everything, with no GitHub token:

npm install
npx playwright install --with-deps chromium   # first time only — the e2e browser
npm test

npm test runs two suites, and the same command runs in CI (.github/workflows/ci.yml) on every pull request:

The e2e suite needs the full Chromium build (Playwright’s channel: "chromium") — only it loads extensions headless; the default bundled headless shell can’t.