Context
Focused split from #13521 (Accounts keeper-view enhancements), mirroring the AC1→#13525 split: per the agent PR-body lint's 1-PR-per-ticket model, each remaining AC on #13521 gets its own ticket when picked up. This is AC2 — the basic NL-MCP external-harness entry reachable from the Accounts surface. AC1 (provider-login via the AiConfig SSOT) shipped via #13525 / PR #13526; the Accounts keeper-view extraction shipped via #13491 / PR #13516.
The Problem
The extracted Accounts keeper-view (apps/agentos/view/Accounts.mjs) lets an operator define an agent identity (GitHub username + harness type + PAT) and submit it through a future-injected Brain-side Fleet Registry bridge, failing closed when no bridge is present. But it exposes no path for an external harness to register/connect via the Neural Link MCP — the manage_connection entry an external harness uses to start its bridge session. The App-Worker side has zero reference to that entry today (verified: ConnectionService / manage_connection appear nowhere under apps/).
The Architectural Reality
- The connect entry already exists Brain-side:
ConnectionService.manageConnection({action}) (ai/services/neural-link/ConnectionService.mjs:639), registered as the manage_connection NL-MCP tool (ai/mcp/server/neural-link/toolService.mjs:52). It starts/stops the bridge session.
- The Accounts view reaches Brain-side capability through a fail-closed injected bridge, never a direct import:
submitToFleetRegistryBridge() (apps/agentos/view/Accounts.mjs:236) calls globalThis.AgentOS?.fleet?.registryBridge.defineAgent(payload) and throws "bridge unavailable" when the shell hasn't injected one (its JSDoc, lines 228–235: "the current dev-server app has no Brain-side bridge object, so the view fails closed instead of inventing browser persistence"). The capability-security boundary (App Worker emits JSON intent only; PAT never persists browser-side) is upheld by this seam.
- The action toolbar (
Accounts.mjs:127–139) and the bridge-status feedback component (:141–145) are the existing affordance + feedback pattern to mirror.
The Fix
Add a basic NL-MCP connect entry to the Accounts keeper-view, mirroring the established fail-closed injected-bridge pattern:
- A new action-toolbar button (e.g. "Connect harness (NL-MCP)") in
Accounts.mjs:127–139.
- A handler
onConnectExternalHarnessClick() (parallel to onSubmitAgentClick() at :189) that invokes a future-injected NL-MCP connection bridge — shape globalThis.AgentOS?.neuralLink?.connectionBridge?.manageConnection({action:'start'}) — and fails closed with a bridge-status message when absent (no browser-side connection state invented).
- The connect path carries no credential (the PAT stays the identity-form's concern); the capability boundary is preserved.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
globalThis.AgentOS.neuralLink.connectionBridge.manageConnection({action}) — NEW view→shell injected-runtime contract |
ConnectionService.manageConnection({action}) (ai/services/neural-link/ConnectionService.mjs:639); ADR 0020 |
View invokes {action:'start'}; on success updates bridge-status to live |
Fail closed: status message only; no App-Worker connection state |
JSDoc on the new handler (mirrors submitToFleetRegistryBridge) |
Accounts.mjs:236 fail-closed pattern; toolService.mjs:52 tool binding |
The manage_connection NL-MCP tool itself is unchanged — no tool/transport/error-code change. This row covers only the NEW view→shell injected-bridge contract.
Decision Record impact
aligned-with ADR 0019 (AiConfig reactive provider SSOT — from AC1) + aligned-with ADR 0020 (agent-harness concept — the external-harness entry mode). No ADR challenged or superseded.
Acceptance Criteria
Out of Scope
- The future Agent OS shell's actual
connectionBridge implementation (the injecting side) — this ticket adds the view-side consumer + the contract only.
- Extended multi-agent NL coordination (
#13056, H3).
- Lifecycle controls beyond a basic connect entry (stop / restart / status-polling UI).
- AC3 (v14
IdentityState slot, gated on #13444) and AC4 (credential-boundary invariant) of #13521.
Avoided Traps
- Direct
ConnectionService import from the view. ConnectionService is a Brain-side (Node) singleton; importing it into the App-Worker view would breach the worker/thread + capability boundary. The view MUST reach it through the injected bridge seam, exactly as defineAgent does — never a direct cross-boundary call.
- Inventing browser-side connection state when no bridge is present. Mirror the fail-closed discipline; do not fabricate a "connected" status the Brain has not confirmed.
Related
- Parent: #13521 (AC2 of the Accounts enhancements). Sibling precedent: #13525 (AC1 split) / PR #13526.
- Epic: #13448 (v13.1 fleet cockpit) — #13521 is linked under it via
SUB_ISSUE.
- Forward-compat: #13444 (v14
IdentityState, AC3). Fences: #13056 (extended NL coordination).
- Extraction: #13491 / PR #13516.
Release classification: v13.1 harness cockpit (not v13-release-blocking) — boardless.
Origin Session ID: d1903453-9b2d-4f5d-bb5a-cf51ac2f7538
Retrieval Hint: query_raw_memories "NL-MCP connect entry Accounts keeper-view fail-closed injected bridge"; Accounts.mjs:236 submitToFleetRegistryBridge pattern.
Authored by Claude Opus 4.8 (Claude Code), @neo-opus-vega (Vega).
Context
Focused split from #13521 (Accounts keeper-view enhancements), mirroring the AC1→#13525 split: per the agent PR-body lint's 1-PR-per-ticket model, each remaining AC on #13521 gets its own ticket when picked up. This is AC2 — the basic NL-MCP external-harness entry reachable from the Accounts surface. AC1 (provider-login via the AiConfig SSOT) shipped via #13525 / PR #13526; the Accounts keeper-view extraction shipped via #13491 / PR #13516.
The Problem
The extracted Accounts keeper-view (
apps/agentos/view/Accounts.mjs) lets an operator define an agent identity (GitHub username + harness type + PAT) and submit it through a future-injected Brain-side Fleet Registry bridge, failing closed when no bridge is present. But it exposes no path for an external harness to register/connect via the Neural Link MCP — themanage_connectionentry an external harness uses to start its bridge session. The App-Worker side has zero reference to that entry today (verified:ConnectionService/manage_connectionappear nowhere underapps/).The Architectural Reality
ConnectionService.manageConnection({action})(ai/services/neural-link/ConnectionService.mjs:639), registered as themanage_connectionNL-MCP tool (ai/mcp/server/neural-link/toolService.mjs:52). It starts/stops the bridge session.submitToFleetRegistryBridge()(apps/agentos/view/Accounts.mjs:236) callsglobalThis.AgentOS?.fleet?.registryBridge.defineAgent(payload)and throws "bridge unavailable" when the shell hasn't injected one (its JSDoc, lines 228–235: "the current dev-server app has no Brain-side bridge object, so the view fails closed instead of inventing browser persistence"). The capability-security boundary (App Worker emits JSON intent only; PAT never persists browser-side) is upheld by this seam.Accounts.mjs:127–139) and thebridge-statusfeedback component (:141–145) are the existing affordance + feedback pattern to mirror.The Fix
Add a basic NL-MCP connect entry to the Accounts keeper-view, mirroring the established fail-closed injected-bridge pattern:
Accounts.mjs:127–139.onConnectExternalHarnessClick()(parallel toonSubmitAgentClick()at:189) that invokes a future-injected NL-MCP connection bridge — shapeglobalThis.AgentOS?.neuralLink?.connectionBridge?.manageConnection({action:'start'})— and fails closed with abridge-statusmessage when absent (no browser-side connection state invented).Contract Ledger Matrix
globalThis.AgentOS.neuralLink.connectionBridge.manageConnection({action})— NEW view→shell injected-runtime contractConnectionService.manageConnection({action})(ai/services/neural-link/ConnectionService.mjs:639); ADR 0020{action:'start'}; on success updatesbridge-statusto livesubmitToFleetRegistryBridge)Accounts.mjs:236fail-closed pattern;toolService.mjs:52tool bindingThe
manage_connectionNL-MCP tool itself is unchanged — no tool/transport/error-code change. This row covers only the NEW view→shell injected-bridge contract.Decision Record impact
aligned-with ADR 0019(AiConfig reactive provider SSOT — from AC1) +aligned-with ADR 0020(agent-harness concept — the external-harness entry mode). No ADR challenged or superseded.Acceptance Criteria
manageConnection({action:'start'})seam.submitToFleetRegistryBridge.#13056/ H3) is NOT pulled forward — basic connect entry only.is-livestatus; absent-bridge →is-errorfail-closed.Out of Scope
connectionBridgeimplementation (the injecting side) — this ticket adds the view-side consumer + the contract only.#13056, H3).IdentityStateslot, gated on #13444) and AC4 (credential-boundary invariant) of #13521.Avoided Traps
ConnectionServiceimport from the view.ConnectionServiceis a Brain-side (Node) singleton; importing it into the App-Worker view would breach the worker/thread + capability boundary. The view MUST reach it through the injected bridge seam, exactly asdefineAgentdoes — never a direct cross-boundary call.Related
SUB_ISSUE.IdentityState, AC3). Fences:#13056(extended NL coordination).Release classification: v13.1 harness cockpit (not v13-release-blocking) — boardless.
Origin Session ID: d1903453-9b2d-4f5d-bb5a-cf51ac2f7538
Retrieval Hint: query_raw_memories "NL-MCP connect entry Accounts keeper-view fail-closed injected bridge";
Accounts.mjs:236submitToFleetRegistryBridgepattern.Authored by Claude Opus 4.8 (Claude Code), @neo-opus-vega (Vega).