Rewrites every British spelling found in the codebase to American: neighbour, colour, catalogue, behaviour, honour, flavour, grey, judgement, acknowledgement, licence, defence, organise/optimise/initialise/recognise/ analyse, artefact, cancelled/cancelling, labelled/labelling, modelled/ modelling, and centre/centred/centring all become their American forms — consistently in prose (docs, ADRs, comments) and in identifiers, including the FFI-shared CatalogueSync/Cancelled enum variants and catalogue_* fields that cross the Rust/Kotlin boundary. Left untouched: external API names that only look like a spelling variant (kotlinx.coroutines.CancellationException/NonCancellable, Compose Material3's labelLarge) and the EFF diceware wordlist used for key derivation. Adds a Code Style rule to AGENTS.md/CLAUDE.md requiring American spelling in user-facing copy and documentation going forward, with that same carve-out. Verified: cargo build --workspace, all 1410 Rust tests, Kotlin compile, fmt-rust/fmt-kotlin, lint-kotlin-fast (detekt), and the lint-gui-layout/ lint-sql-params/lint-p2p-admission custom checks all pass clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fHWzCF6oNiCV4ue1bBf1t
Synchronicity browser extension
A companion to a Synchronicity node running on the same machine. It finds the
nodes on this machine and links to them: a node grants this browser a bearer
token — a linkage — and the extension can then send it commands. What it is,
how discovery works, and how pairing is guarded are in
docs/adr/0017-browser-extension-daemon-pairing.md.
Linking
A node will not answer anything but /version without a token, and only hands
one out in exchange for a code shown on the node's own screen. So linking is
two-sided by design:
- On the node: Settings ▸ Linkages ▸ New linkage… in the desktop app, or
syn linkage pairin the CLI. Either prints a six-digit code good for two minutes. - In the popup: Link… on that node's entry, type the code, submit.
The token lands in browser.storage.local, keyed by the node's pubkey — not by
port, which changes every time a node restarts. Unlink revokes it on the
node and then forgets it here; revoking from the node's Settings screen instead
is equally final, and the popup notices the next time it is opened.
Icons
src/icons/ is rendered from assets/synchronicity-icon.png, the same icon
the desktop and Android apps use — committed rather than generated at load
time, since src/ has to stay loadable with no build step. just extension icons re-renders them if the source icon ever changes.
Clipping
Select text on any page, right-click, Save selection to Synchronicity. The
toolbar icon flashes ✓ when the node has it, ! when it hasn't — and the popup
lists the last few clippings under the node they went to, read back from the
node rather than remembered here.
The extension never reads pages. contexts: ["selection"] makes the browser
hand the selected text to the menu handler, so there is no scripting
permission and no host access to the sites you clip from — only to
127.0.0.1, where the node is.
Where a clipping is filed is the node's business: the extension sends the text,
the page URL and the page title, and nothing else (see
docs/adr/0039-clippings-captured-text.md).
Building
There is no build step, on purpose. Everything under src/ is what the
browser loads — plain ES modules, plain CSS, one HTML file, no bundler and no
node_modules. Packaging zips src/ verbatim, so what you debug is
byte-for-byte what ships.
just extension build
That needs the zip binary (the nix devShell supplies it) and nothing else.
The zip lands in dist/.
The recipes live in this directory's own justfile — build, check,
dev-path — reachable from the repo root as just extension <recipe>, or as
plain just <recipe> from inside browser-extension/. just extension check
validates the manifest and checks this side's copy of the loopback port range
against the daemon's, plus deno lint if deno happens to be installed.
Running from source
Load src/ directly rather than the zip, so a reload picks up your edits
without rebuilding — just extension dev-path prints both of these:
- Chrome / Chromium / Edge:
chrome://extensions→ enable Developer mode → Load unpacked → pickbrowser-extension/src. - Firefox:
about:debugging#/runtime/this-firefox→ Load Temporary Add-on → pickbrowser-extension/src/manifest.json. Temporary add-ons are dropped when Firefox restarts; a permanently installable build needs signing, which this doesn't do yet.
Then start a node (just daemon-cli, or open the desktop app) and click the
toolbar button.
On Firefox the popup will first ask you to grant access to 127.0.0.1.
Firefox treats MV3 host_permissions as opt-in and leaves the choice to the
user, where Chrome grants them at install time; the extension checks for the
grant explicitly so a missing permission reads as "can't check" rather than
"no node running".