Connect vs Chrome
How the connect.* platform maps to — and deliberately diverges from — the chrome.* extension API.
What you can build on the
connect.*API today, how it maps tochrome.*, and what's next. Companion to the extension dev guide (the full API reference) and the design spec.Native-first, not parity-chasing. Chrome's surface is a design checklist, not a spec to clone. Connect+ reimplements the useful capabilities natively and sometimes diverges deliberately (narrower where safer, richer where it helps). Roughly ~65–70% of Chrome's breadth is covered, weighted toward what real extensions actually use.
1. Capabilities (what a user grants)
Extensions request these in the manifest; the user grants a scoped, revocable, audited subset (default-deny). Full taxonomy + host/channel scoping in dev guide §4.
| Capability | Unlocks |
|---|---|
tabs.read | See tabs/windows + their change events; webNavigation events. |
tabs.write | Open/close/reload/navigate/activate tabs; window focus/state. |
storage | The extension's own private per-profile store (local + session). |
scripting | Programmatic script/CSS injection (+ a host grant for the target). |
net.observe / net.block | Read adblock state / block+redirect + declarative rules. |
history.read / history.write | Read / modify browsing history. |
bookmarks.read / bookmarks.write | Read / modify bookmarks. |
cookies | Read/write cookies for permitted sites (+ a host grant). |
downloads | Start + observe the extension's own downloads. |
notifications | System notifications. |
contextMenus | Items in the page right-click menu. |
alarms | Timer tasks that survive background suspension. |
idle | active / idle / locked state. |
sidePanel / action / options / newTab | Own the side panel / toolbar button / options surface / the new-tab page. |
profile.read | Read Connect+ profile + device rules (Connect+-only). |
proxy | Control the profile proxy (Connect+-only). |
{ host: <pattern> } | Per-site access (content scripts, cookies, injection scope). |
{ channel: <name> } | Talk to other extensions on a named channel (Connect+-only). |
Extensions can check what they got at runtime:
connect.capabilities.list(), capabilities.contains(cap) → boolean,
capabilities.request([...]).
2. chrome.* → connect.* coverage
Legend: ✅ covered · 🟡 partial / narrower · 🔴 not yet · ⛔ intentionally not.
| Chrome API | Connect+ | Status | Notes |
|---|---|---|---|
chrome.tabs | connect.tabs | ✅ | query/get/create/close/reload/navigate/activate/move/duplicate/captureVisibleTab (host-gated), sendMessage, onActivated/onUpdated/onCreated/onRemoved. Tab groups: deliberately not implemented (deferred — §4). |
chrome.windows | connect.windows | 🟡 | Single-window shell: get*/create/update(focus,state)/onFocusChanged/onCreated/onRemoved. Bounds are read-only. |
chrome.storage | connect.storage | ✅ | local + session + sync (v1 device-local), object API, onChanged w/ areas. Missing: managed. |
chrome.runtime | connect.runtime | 🟡 | getManifest, sendMessage/onMessage, connect/onConnect (long-lived Ports) — from extension surfaces and content scripts (a CS is the opener; disconnects on navigate/close), onInstalled, onSuspend/onResume, onGrantsChanged (extra). Ports don't wake a suspended background. tabs.connect (surface→CS) works — the CS accepts via runtime.onConnect. |
chrome.scripting | connect.scripting | ✅ | executeScript(code/files/func+args)/insertCSS/removeCSS + register/update/unregister/getRegisteredContentScripts, isolated + main worlds. |
chrome.declarativeNetRequest | connect.net | ✅ | DNR-subset rules (block/allow/redirect) plus adblock master + per-site tiers. |
chrome.webRequest (blocking) | connect.net rules | ⛔ | No blocking webRequest / header rewriting; use declarative rules. |
chrome.webNavigation | connect.webNavigation | ✅ | onCommitted/onCompleted/onHistoryStateUpdated, all frames (frameId; 0 = main). |
chrome.cookies | connect.cookies | ✅ | getAll/get/set/remove/onChanged, host-scoped (events too — you only hear granted origins). |
chrome.bookmarks | connect.bookmarks | ✅ | list/add/remove + folder tree (getTree/getChildren/createFolder/move/removeById) + onChanged. Favorites are a tree: an entry is a link (has a url) or a folder. list stays a flat list of links. Ordering within a folder is by creation (no explicit index yet). |
chrome.history | connect.history | 🟡 | list/search/delete. |
chrome.downloads | connect.downloads | 🟡 | Start-your-own + observe-your-own only (no surveillance of the user's downloads — by design). |
chrome.notifications | connect.notifications | ✅ | create (≤2 buttons)/clear/onClicked/onButtonClicked; buttons render where the OS notifier supports actions. |
chrome.contextMenus | connect.ui.menus | ✅ | create/update/remove/removeAll/onClicked. |
chrome.action | connect.action + ui.setPopupSize | ✅ | setBadgeText/BadgeBackgroundColor/getBadgeText/getBadgeBackgroundColor/setIcon/setTitle/getTitle/enable/disable/isEnabled/openPopup/onClicked + live popup sizing. (Per-tab badge/title scoping is per-instance here.) |
chrome.sidePanel | connect.ui.sidePanel | ✅ | open/close a docked panel surface. |
chrome.alarms | connect.alarms | ✅ | create/get/getAll/clear/clearAll/onAlarm (survive suspension). |
chrome.idle | connect.idle | ✅ | queryState/setDetectionInterval/onStateChanged. |
chrome.permissions | connect.capabilities | ✅ | list / contains / request. |
chrome.i18n | connect.i18n | ✅ | getMessage (placeholders + locale fallback) + getUILanguage + getAcceptLanguages + detectLanguage + _locales/default_locale. Detection is a trigram model rather than Chrome's CLD (backed by @connect/lang-detect, our in-repo franc-min fork with no runtime deps) and reports isReliable. |
chrome.proxy | connect.proxy | 🟡 | Connect+ proxy arbiter (simpler get/set). |
chrome.devtools.* | — | 🔴 | No devtools panels/inspected-window API. |
chrome.commands | connect.commands | ✅ | Declarative keyboard shortcuts: manifest commands, onCommand, getAll (effective shortcut), _execute_action. Fires while a page or the shell chrome is focused. Users re-bind/disable from Extensions → Shortcuts… |
chrome_url_overrides | ui.newTab / ui.historyPage / ui.bookmarksPage + caps newTab / historyPage / bookmarksPage | ✅ | Page overrides declared as surfaces (like ui.action/ui.options) and capability-gated, so a declaration alone never takes over: the user's consent does, and revoking hands the view back. History/bookmarks live as popups in Connect+, so those overrides replace the popup's content. |
chrome.omnibox / tts / nativeMessaging | — | ⛔ | Out of scope. |
| externally_connectable / cross-ext | connect.channel | ✅* | Capability-gated named-channel pub/sub (different model, not runtime.connect). |
| — | connect.profile | ✅ | Connect+-only: read profile + device rules. No Chrome analog. |
3. What you can build today
Great fit (ship it now):
- Ad / content blockers —
connect.netdeclarative rules + the native adblock tiers (often better than Chrome's DNR: integrated engine + per-site tiers). (Reference: Shield.) - Themes / dark mode / page restyling — content scripts with Chrome-exact timing, per-host prefs, first-paint injection. (Reference: Midnight.)
- Tab & session managers —
tabs.*+storage, live events, bookmark-all. (Reference: Session.) - Privacy tools — host-scoped
cookies,netrules,proxy, history control. - Page tools — annotators, readers, summarizers, form helpers (content
scripts ↔ background messaging +
storage). - Toolbar utilities & side-panel apps — popup/side-panel UIs, badges, runtime icons, context-menu actions, alarms, notifications.
- Cross-extension suites — coordinate multiple extensions over
connect.channel(capability-gated).
Possible with limits:
- Password managers / autofill — content scripts + storage work; there's no dedicated autofill/credentials API.
- Request-level privacy — declarative block/allow/redirect only; no per-header
rewriting (no blocking
webRequest).
Now possible (new):
- Keyboard shortcuts —
connect.commands(manifestcommands+onCommand, and_execute_actionto open your popup). - Localized extensions —
connect.i18n+_locales(getMessage, getUILanguage, getAcceptLanguages). - Cookie-reactive tools —
cookies.onChanged(host-scoped) for session/consent watchers, plustabs.move/duplicatefor tab organizers. - Streaming / stateful UIs — long-lived Ports (
runtime.connect) between a popup/side panel or a content script and the background, withonDisconnectso the background stops work the moment its UI closes (or the tab navigates away). - Screenshot / capture tools —
tabs.captureVisibleTab(host-gated). - New-tab dashboards —
ui.newTab(capnewTab) replaces the new-tab page with your own surface, running in the extension's own partition. - Bookmark managers — the favorites folder tree (
getTree/createFolder/move) plusonChanged, which also fires when the user stars a page.
Not yet possible:
- DevTools panels, history/bookmarks page overrides, omnibox (extension keyword API), TTS, native messaging.
4. What's next (roadmap toward a fuller API)
Ordered roughly by demand. None block the platform being a real product today.
Ports for content scripts✅ shipped —runtime.connectfrom a content script (per-isolated-world routing in the tab preload; disconnects on navigate/close).tabs.connect(surface→CS) shipped too — the CS accepts viaruntime.onConnect; ports are fully bidirectional now.- Tab groups — ⏸ deferred by decision (2026-07-22): not implemented in v1;
revisit in a future version if author demand shows up.
tabs.group/tabGroups.*calls are simply absent (an extension can feature-detect with'group' in connect.tabs). Everything else intabsshipped. ✅ shipped — Extensions → Shortcuts… re-binds or disables any command; overrides are global, win over the manifest suggestion, andcommandsre-binding UIgetAllreports the effective shortcut.✅ shipped —url_overridesfor history/bookmarks pagesui.historyPage/ui.bookmarksPage(capshistoryPage/bookmarksPage) replace the History / Favorites popups, same consent model asui.newTab.worker_threads substrate✅ shipped —background.substrate: "worker"runs a first-party background in aworker_threadscompute host (no DOM;call/onEvent+ runtime/storage/alarms sugar; lifecycle parity incl. suspend/wake). Community access is planned behind a double security-consent gate — see docs/community-worker-substrate-plan.md.- DevTools panels — if author demand warrants it.
- Conformance suite (P7) — 🟢 layers 1+2 shipped:
pnpm conformance(apps/desktop,tests/conformance/) runs 31 pure-unit + consistency tests in ~120ms — commands/overrides, all three storage areas, theme validation, the worker-bootstrap protocol (event names checked against the realconnectEvent), the manifest schema contract (every grantable capability is declarable), and code↔schema↔docs agreement (capability-info === schema enum, §4 taxonomy coverage, preload namespaces ⊆ §20 matrix, §20 methods exist in the preloads, schema ui surfaces === types). The headless-app integration layer comes later. The Chrome→Connect converter (P6) stays parked — the store hosts native Connect+ extensions.
When any of these lands, add it to the dev guide (namespace section + §20 matrix) and flip its row here — same change.