ADR 0034 already settles this boundary and names one unfiled refinement leaf:
E5 — preload capability contract + credential ingress: the one contextBridge surface + allowlist, sender validation, token custody, and the shell-owned credential surface retiring the transitional Accounts path.
The E8 headed lifecycle witness exposed why E5 is now executable rather than speculative. The native hide/show identity proof and exact-once Brain teardown both pass, but the combined witness remains degraded because the packaged Fleet process is bearer-gated while the Electron shell has neither an authenticated readiness path nor a named renderer capability that can attach the main-owned bearer internally.
Live evidence from npm --prefix harness run witness:lifecycle on 2026-07-18:
sameBrowserWindow: true
sameRenderer: true
sameViewportIdentity: true
hide → zero visible windows → tray restore succeeds
owned Fleet + orchestrator process groups stop cleanly
brainUp: false: awaitFleetReady() times out against the authenticated Fleet endpoint
The latest 20 open issues, targeted searches for Electron preload/Fleet/bearer/credential capability, and team-memory retrieval found no existing E5 leaf.
The Problem
The current source has four pieces that do not yet compose into the packaged security contract:
devFleetServer.mjs requires a per-process bearer and refuses unauthenticated Fleet ingress.
harness/brain.mjs probes POST /fleet without the bearer, so genuine readiness and attach-or-own detection cannot authenticate.
harness/preload.cjs exposes only neoShell.shellVersion; the App Worker therefore has no named private capability through which the Electron main process can attach the bearer without revealing it.
The current Accounts add-agent path still accepts credential bytes in App-Worker state. ADR 0034 §2.3.6 explicitly permits that only as transitional dev-server drift and assigns its packaged-shell retirement to E5.
Fixing only the readiness probe would make one witness green while leaving the product path and credential-ingress contract false. This ticket owns the whole E5 row.
Architectural Reality
ADR 0034 §2.3.4–.6 is upstream authority:
There is exactly one minimal contextBridge surface of named, capability-shaped affordances. Raw ipcRenderer and Node exposure are forbidden.
Every main-process handler validates event.senderFrame against the packaged app:// origin before acting.
The Brain endpoint stays loopback TCP, but loopback is not authentication.
The per-boot Fleet bearer remains main/Brain-side. Its bytes never enter renderer-readable state, App-Worker state, URLs, logs, IPC replies, or persisted config.
The preload/main capability attaches authorization internally; the renderer invokes intent, not a secret.
Packaged credential entry is shell-owned: credential bytes flow preload/main → Brain, while Body/App Worker submits only curated public intent such as {harnessType, id, repo/account facts}.
Direct-browser dev mode remains a distinct supported topology. Its current in-memory installFleetBridge({url, bearerToken}) path must keep working and fail closed when no bearer is supplied.
The existing worker boundary is usable without inventing a second transport: App-Worker code already reaches named main-thread functions through Neo.Main. E5 must publish the private shell capability through that boundary while preserving the current globalThis.AgentOS.fleet.registryBridge consumer contract.
The Fix
Add a named neoShell.fleetRequest(intent) preload capability.
It accepts only the Fleet wire request shape.
It returns only the Fleet response.
It never exposes endpoint or bearer getters.
Add one Electron-main Fleet request owner.
Retain the current per-boot endpoint + bearer in main-owned state.
Attach Authorization internally.
Validate the sender frame and packaged origin.
Apply a named method allowlist at the existing Fleet dispatch choke point rather than creating a divergent allowlist.
Install the packaged App-Worker bridge through the existing Main-worker boundary.
Preserve the current AgentOS.fleet.registryBridge consumer API.
Keep the direct-browser installFleetBridge path separate and unchanged.
Authenticate shell readiness and attach-or-own probes with the same main-owned bearer.
A generic open loopback port is never readiness.
Readiness remains a real Fleet verb/probe response from the process the shell owns or has authenticated for reuse.
Add the shell-owned credential ingress required by §2.3.6.
packaged shell consumes the same registry-bridge API without bearer bytes
real App-Worker request witness
Brain readiness
shell lifecycle owner
authenticated protocol identity, not port occupancy
red/green boot and incumbent-reuse controls
Credential ingress
shell-owned surface
secret bytes bypass Body/App Worker; public intent/readback remains declarative
secret-census + accepted/rejected flow
Multi-window
one app:// origin/partition
cockpit and popup share capability semantics without secret duplication
same-session popup request witness
Direct browser mode
installFleetBridge
current dev/test transport remains distinct and fail-closed
existing transport suite + no-bearer negative
Acceptance Criteria
A packaged/headed Fleet request succeeds through a named preload/main capability while the Fleet bearer is absent from window, globalThis, App-Worker state, URL/search params, logs, IPC replies, and persisted configuration.
Main rejects a forged/off-origin sender frame before dispatch.
Main rejects a disallowed Fleet method and a malformed request before network dispatch.
The capability reuses the canonical Fleet wire-method authority; no second drifting method list is introduced.
The retained cockpit and a same-origin popup both invoke the same main-owned capability; neither receives or duplicates the secret.
probeFleetServing, detectLiveBrain, and awaitFleetReady authenticate the process they inspect. A foreign listener, wrong bearer, mismatched viewer, or generic open port fails closed with a named reason.
Packaged credential entry is shell-owned. PAT bytes never enter App-Worker state; Body submits only curated public intent and receives public readback/status.
Direct-browser dev mode remains working through its existing transport and still rejects missing or URL-carried bearer material locally.
[L3-deferred — healthy macOS host needed] npm --prefix harness run witness:lifecycle becomes fully green with brainUp: true while retaining its same-window, same-renderer, zero-visible, restore, and exact-once teardown receipts.
Unit tests include admitted, wrong-bearer, forged-sender, disallowed-method, malformed-request, popup, secret-census, and readiness red controls.
Cross-family review includes a security-focused seat and verifies ADR 0034 §2.3.4–.6 line by line.
Out of Scope
E8 tray/hide/restore behavior and lifecycle policy (#15531).
Fleet business-method semantics or new Fleet wire verbs.
Changing PAT persistence policy outside the packaged ingress boundary.
External-network or cloud authentication.
Replacing the direct-browser development topology.
Electron ownership of application windows; popups remain Neo/browser-owned and merely materialize as BrowserWindow instances.
Avoided Traps
Exposing getBearer(), bearerToken, endpoint configuration, or raw ipcRenderer through preload.
Smuggling the bearer through a query parameter, init script, DOM/global, response object, or log.
Teaching the App Worker a packaged-shell branch with secret bytes.
Duplicating FLEET_WIRE_METHODS in Electron main.
Treating a TCP listener as Fleet readiness.
Fixing only the E8 probe while leaving packaged product calls or credential ingress false.
Using a renderer-supplied viewer identity, command, args, env, or executable path as authority.
Related
Parent epic: #13377 E8 consumer/witness: #15531 ADR authority: learn/agentos/decisions/0034-electron-shell-architecture.md §2.3.4–.6 and §5 E5 Dev transport: src/ai/fleet/installFleetBridge.mjs Fleet ingress: ai/services/fleet/fleetIngressAuth.mjs
Context
ADR 0034 already settles this boundary and names one unfiled refinement leaf:
The E8 headed lifecycle witness exposed why E5 is now executable rather than speculative. The native hide/show identity proof and exact-once Brain teardown both pass, but the combined witness remains degraded because the packaged Fleet process is bearer-gated while the Electron shell has neither an authenticated readiness path nor a named renderer capability that can attach the main-owned bearer internally.
Live evidence from
npm --prefix harness run witness:lifecycleon 2026-07-18:sameBrowserWindow: truesameRenderer: truesameViewportIdentity: truebrainUp: false:awaitFleetReady()times out against the authenticated Fleet endpointThe latest 20 open issues, targeted searches for Electron preload/Fleet/bearer/credential capability, and team-memory retrieval found no existing E5 leaf.
The Problem
The current source has four pieces that do not yet compose into the packaged security contract:
devFleetServer.mjsrequires a per-process bearer and refuses unauthenticated Fleet ingress.harness/brain.mjsprobesPOST /fleetwithout the bearer, so genuine readiness and attach-or-own detection cannot authenticate.harness/preload.cjsexposes onlyneoShell.shellVersion; the App Worker therefore has no named private capability through which the Electron main process can attach the bearer without revealing it.Fixing only the readiness probe would make one witness green while leaving the product path and credential-ingress contract false. This ticket owns the whole E5 row.
Architectural Reality
ADR 0034 §2.3.4–.6 is upstream authority:
contextBridgesurface of named, capability-shaped affordances. RawipcRendererand Node exposure are forbidden.event.senderFrameagainst the packagedapp://origin before acting.{harnessType, id, repo/account facts}.installFleetBridge({url, bearerToken})path must keep working and fail closed when no bearer is supplied.The existing worker boundary is usable without inventing a second transport: App-Worker code already reaches named main-thread functions through
Neo.Main. E5 must publish the private shell capability through that boundary while preserving the currentglobalThis.AgentOS.fleet.registryBridgeconsumer contract.The Fix
neoShell.fleetRequest(intent)preload capability.Authorizationinternally.AgentOS.fleet.registryBridgeconsumer API.installFleetBridgepath separate and unchanged.Contract Ledger
harness/preload.cjsapp://origin/partitioninstallFleetBridgeAcceptance Criteria
window,globalThis, App-Worker state, URL/search params, logs, IPC replies, and persisted configuration.probeFleetServing,detectLiveBrain, andawaitFleetReadyauthenticate the process they inspect. A foreign listener, wrong bearer, mismatched viewer, or generic open port fails closed with a named reason.npm --prefix harness run witness:lifecyclebecomes fully green withbrainUp: truewhile retaining its same-window, same-renderer, zero-visible, restore, and exact-once teardown receipts.Out of Scope
BrowserWindowinstances.Avoided Traps
getBearer(),bearerToken, endpoint configuration, or rawipcRendererthrough preload.FLEET_WIRE_METHODSin Electron main.Related
Parent epic: #13377
E8 consumer/witness: #15531
ADR authority:
learn/agentos/decisions/0034-electron-shell-architecture.md§2.3.4–.6 and §5 E5Dev transport:
src/ai/fleet/installFleetBridge.mjsFleet ingress:
ai/services/fleet/fleetIngressAuth.mjsOrigin Session ID: ad71d4c3-3e37-4a17-8df7-8415509def84
Retrieval Hint:
Electron E5 private Fleet capability preload main bearer credential ingress App Worker readiness