- The release workflow renders `docs/tools.json` and `docs/clients.json`
right after it bumps the package version and commits them with the
release: both files carry the version and the suite asserts the files on
disk are the current rendering, so the first 10.11.0 run failed its own
bump.
- The Safari automation hint names the setting the way the engine does: Safari > Settings > Developer > "Allow remote automation", with the Develop menu item on older Safari.
- `extension_dev` carries the control channel by default: `allowControl` defaults to true, so `extension_storage`, `extension_reload`, `extension_open` and `extension_dom_snapshot` work on a plain dev session and a later "reload it" costs no restart; pass `allowControl: false` for a read-only session. `allowEval` stays off until asked and still implies control. The descriptions, the hints, the docs gates, the README and the shipped rules say control is on unless asked off.
- `extension_wait` now says when it is needed (a session started with `wait: false`, a dev answer whose `ready.status` was not ready, a build-only session); `extension_dev`'s answer and the shipped rules say a ready answer ends the run recipe.
- `extension_docs_search`'s description is the trigger: any WebExtension API, manifest key, permission or browser-difference question is answered from the docs first, memory only when nothing matches.
- `extension_build` hands the reading of the output to `extension_analyze` in its hint, and `extension_create` says the scaffold needs no build to verify and names `extension_dev` as the next step.
- The `extension_logs` hint for a Safari session with no log file, the
README, the rules and the `/extension debug` command name 4.1.21 as the
Extension.js floor for Safari log streaming in place of 4.1.28, which no
engine change backed (that number is the `navigate` verb's canary). The
engine first streamed Safari background and content lines through the
bridge in v4.1.20 (#533, the webkit background patch that stops Safari
from skipping the MV3 worker), and v4.1.21 (#566) gave the dev-injected
background of a project with no background of its own the same shape,
so 4.1.21 is the first release where every project streams.
- `extension_build` always answers `outputPath`, the folder it checked the
manifest in: the engine's reported path when the summary carries one, else
`dist/<browser>` under the package root. On an engine older than the
summaries contract the field used to be missing and an agent guessed the
folder. `zipPath` stays beside it when a zip was asked for.
- `extension_create` answers `scripts`: every package.json script the
scaffolder wrote that runs the engine, with the command, the browser it
targets and the folder it writes (`npm run build` is flagless, so chromium
into `dist/chromium`; `build:chrome` into `dist/chrome`; a monorepo
script's folder is resolved under the package the engine builds). The
`defaultsApplied.browser` sentence points at that list instead of
restating it, and the description says to read the folder from there.
- `extension_project_create` defaults the build command to
`npm run build -- --browser <browser>`, the browser's name per enabled
browser, in place of `npm run build`: the platform runs the stored command
as it is and reads `dist/<browser>` afterwards, and a flagless
`extension build` writes `dist/chromium`, so a default-created project
produced an empty artifact. `<browser>` in a command of your own is
replaced the same way `outputDirectory` already did. The description and
the `buildCommand` input say what the platform does with the command.
- The rules, the `/extension build` command and the `extension_build`,
`extension_create` and `extension_project_create` descriptions now say
what the engine does: `extension build` with no `--browser` targets
chromium and writes `dist/chromium/`, so a scaffolded `npm run build`
lands there, while `--browser=chrome` and `extension_build` (chrome by
default) write `dist/chrome/`. The build rule tells the agent to read the
folder from the build's answer (`outputPath`) instead of assuming
`dist/chrome/`, which an agent did on 2026-10-08 and got `ls: exit 1`.
- The README and the `extension_create` description now say that a
successful scaffold sends one `draft_seeded` event to PostHog, what it
carries, and that `EXTENSION_DEV_NO_TELEMETRY=1` or `DO_NOT_TRACK=1` turns
it off. Nothing about what is sent changed; a test fails if either text
stops naming the event or the two variables.
- The Live Preview carrier copy that `extension_dev {carrier: true}` places
no longer admits `http://localhost/*` or `http://127.0.0.1/*` in its
`externally_connectable`: on a stranger's machine those ports belong to
whatever runs there. `EXTENSION_DEV_CARRIER_LOOPBACK=1` on the server
keeps them for the extension.dev apps' own dev servers; the `carrier`
description names the permissions the carrier holds and the switch.
- `extension_inspect` no longer sleeps 1.5 s after navigating or 0.5 s when
it did not navigate: the CDP navigate already waits for the page's load
event, so both waits read nothing.
- A CDP event listener that throws is reported on stderr with the event
name instead of being discarded with unparseable frames, and the
recorded console is kept.
- `extension_list_extensions` connects once to the port the ready contract
stamped instead of retrying three times 800 ms apart: the port is read
from a live session's contract, so a refused connection is the answer.
- One JSON frame reader (`src/lib/frame-json.ts`) replaces the two private
copies in `extension_open` and `extension_eval`.
- The server starts with the local group alone: the 23 of its 32 tools that
work on this machine. The 9 platform tools (account, share, release and
store) come on with `--features=local,platform` or
`EXTENSION_DEV_FEATURES=local,platform` while the platform is in private
alpha. The Connect recipes name both groups for the two reaches that need
the platform. The README moves signing in, sharing and the store lane
under one Platform heading.
- `scripts/live-lane.mjs` drives the real server and the real pinned engine
per browser, headless, through create, build, dev, wait, logs, list,
open, dom snapshot, eval, storage, reload, assert and stop, and writes a
verdict table. On 2026-10-07 it passed on Chrome, Edge, Firefox, Brave,
Opera, Vivaldi, Yandex, Waterfox, Zen and Floorp. LibreWolf refuses to
launch until its overrides file turns remote debugging on, so it is no
longer listed as a dev browser (the `browser` enum still accepts it).
- The build test fixtures feed the engine's own `--output json` envelope on
stdout and its narration on stderr instead of prose the engine never
prints; the Safari webdriver seed names the 4.1.32 writer it copies; the
Gecko assert cells run the real list-tabs reader on the engine's tab
rows; `extension_reload` has its own test.
- The package lints with the console's rules: eslint-config-auditor's
recommended and typescript presets, the house style plugin (blank lines
between statements, curly, banner-aware header rules, no JSDoc prose),
consistent type imports and the migration warnings, with the React and
Tailwind layers left out. Every source file was reformatted by the fixer;
no behaviour changed.
- `extension_reload` of the background waits, bounded, for the engine's
`ready.json` to stamp the executor detached and attached again, and
reports `reattachedMs`, `detachedAt` and `attachedTs`; when the new
background has not connected within the budget it answers `reloading`
with a warning instead of `reloaded`. Before this the engine answered
`reloading` 50 ms before the old background died, and a read landing in
the detach-to-reattach gap (measured 11 to 129 ms on Zen and Floorp) got
"the control channel did not answer". `extension_assert` names that gap
when its Gecko read lands in it. Zen and Floorp pass the live lane 5 of 5.
- `@modelcontextprotocol/sdk` moves to 1.32.1, past GHSA-6qxp-vccf-f47h
(the OAuth client paths it fixes are not used here). Its stdio reader now
refuses a single client message over 10 MiB.
- Housekeeping: the July comment inventory left the repository, local
audit folders and the package's own `.mcp.json` are ignored, and the
template sync workflow commits with a plain sentence. The published
tarball was checked file by file: only `dist`, `bin`, `claude`,
`extensions`, the plugin manifests, `server.json` and the three top-level
documents ship. The Extension.js pins already match npm's latest 4.1.32.
- Measured on this machine without a window: `extension_build` for Safari
validates the manifest, generates the Xcode project and builds the app
(31 s, bundle id derived from the app name). A Safari dev session and
its surface reads still need Allow Remote Automation on and the
extension enabled in Safari > Settings > Extensions, which are attended
steps, so the live lane does not run Safari on its own.
- Measured on Extension.js 4.1.32: a Firefox MV3 event page answers
`extension_eval` in `background` like an MV2 page does. The CSP refusal
rewrite applies to a declared content_security_policy, never to MV3 as
such.
- The envelope contract copied under the tests is the one Extension.js
4.1.32 ships (it had stayed at the 4.0.17 bytes, so the byte comparison
against the installed engine only warned), and the comparison now fails
on any engine at or above the pinned release instead of only on an exact
match. A new cell checks the build and doctor fixture builders key for
key against the engine's golden frames.
- Test-only exports left the public surface: `reviewDist` (callers use
`reviewDistReport`), `loginProjectRef`, `resolvedEngineVersion`
(`resolvedEngineFacts` carries the version), the
`HOLD_STILL_WORKS_SENTENCE` alias and the carrier registry's
`rememberedCarriers`. A test-audit pass also removed cells that restated
constants, pinned source spellings, or passed for a reason other than
the one in their title, and fed the remaining hand-written frames from
the engine's builders.
- No comments remain in the package beyond the file banner and tool-read
directives. Every former invariant block is carried by a name, a cell
title, or a `*-rules.test.ts` cell that fails when the rule is broken;
each fixture builder names the engine or platform writer it copies, and
a cell checks the engine markers against the installed engine. The 40
browser, engine-internal and platform-server facts no code or cell can
hold left the repository for the maintainers' notes.
- The invariant comments are cut to their rule: 509 blocks become 386 and
3,744 lines become 2,814, with every ledger citation, date, commit, run
id, first name and machine reference gone, the 120 that only restated a
tested rule deleted, and five that no longer matched the code corrected
(the build is an rslib bundle, the engine stamps the profile path, the
Safari bundle id pattern is the engine's).
- The six inline `<workspace>/<project>` checks on login, project create
and the create list now go through `isProjectRef`, so a ref with a space
is refused where it enters instead of by the platform one call later. The
login list keeps its own check because its exact-slug rule two lines down
owns the message.
- Dead code out: `isManagedCarrier`, `credentialProjectRef`, `mirrorActionsUrlFromRunUrl`,
`browserExitStamp`, `hasSourceMaps`, `REGISTRY_BASE_DEFAULT`,
`SAFARI_MCP_ADD_COMMAND`, `BrowserType`, `ASSERT_RETIRED_IDS`, two unused
`vi` imports and the live lane's unused `GECKO` set.
- The lint migration warnings no longer re-enable core `no-unused-vars`
after typescript-eslint turned it off; `@typescript-eslint/no-unused-vars`
stays. The same line left the monorepo's shared config.
- Nine test files write `ready.json` through the engine contract builder
instead of by hand; the stop-hints cells name the dead server pid they
cut in.
- Sleeps go through `node:timers/promises`; one JSON object reader serves
login config and the approval gate; `consoleBase` and `consoleProjectUrl`
moved to `src/lib/console-urls.ts`, which ends the login-flow, registry,
registry-access import cycle; four shadowed names renamed; the
platform-hold header read lost a catch nothing could reach.
- Five exports that existed only for tests are gone: `getSession`,
`resetEngineVersionCache`, `resetSessionIdentityForTests`,
`resetBatchCreateSessions` and `uninstallCarrierExitCleanup`. The cells
that used them now read the in-memory registry through `listSessions`,
or start a fresh module graph per cell, which is what "a new process"
meant in those cells all along.
- The eval envelope has fixture builders in both shapes, and the golden
frame cell now compares nine of the engine's twelve golden files key for
key and names the three without a counterpart. The detect sentences are
a pure function, so the not-found cell no longer runs a 20 s scan; the
tool description rules are five tables instead of 160 cells.
- The manifest is trimmed: the 20 `pnpm.overrides` floors from the
September advisory sweep are gone (the tree resolves past every one of
them now, and the audit reads the same with or without them),
`browser-extension-manifest-fields`, `vite`, `@eslint/js` and
`typescript-eslint` leave the dependencies (nothing imported them), and
the `clean`, `watch`, `start`, `build` and npm hook scripts leave
(nothing called them; the release lane publishes with scripts ignored).
- Thirteen test cells that hand-wrote the CLI eval or target-not-found
envelope now feed the fixture builders; one cell pinned `E_NO_SESSION`,
a code the engine never sends, and now asserts the engine's
`E_SESSION_NOT_FOUND`. The engine's own `golden.eval.ok.json` wraps the
value as `{ result, context }` while its executor and CLI answer the bare
value; the eval builder follows the engine and a cell names the
disagreement until upstream settles it.
- The Live Preview carrier leaves the package: the bundled extension under
`extensions/`, the `carrier` input on `extension_dev` and the loopback
switch are gone. The carrier only ever reached a machine through this
package, and with the platform in private alpha there is no public
delivery for it, so the public package no longer ships a companion that
holds `<all_urls>`, cookies, history, bookmarks and scripting. A copy an
earlier server placed is still taken back on `extension_stop`,
`extension_start` and `extension_build`, and a build that packs one is
still refused.