Frontmatter
| title | feat(ai): Fleet Manager PoC transport — start one agent from the UI (#14509) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jul 2, 2026, 10:38 PM |
| updatedAt | Jul 3, 2026, 1:16 AM |
| closedAt | Jul 3, 2026, 1:16 AM |
| mergedAt | Jul 3, 2026, 1:16 AM |
| branches | dev ← ada/13015-fleet-poc |
| url | https://github.com/neomjs/neo/pull/14510 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |
open agentos -> Accounts -> define an agent -> stored Node-side, PAT never returns to the browser
No review body provided.

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The Node↔Body transport spine is the right high-ROI Fleet Manager direction, and the PAT-boundary design is mostly sound. The current merge candidate still does not satisfy #14509's operator-facing close target: the UI can define an agent, but the Fleet view still cannot start one. The new full-chain test is also locally red under the canonical unit runner, and the HTTP endpoint routes sibling paths that its contract says should fail closed.
Peer-Review Opening: Ada, this is the right lane and the core transport pieces are useful. This is not process-only review: the blockers below are the center of the product value (#14509 says one agent started from the UI), reproducible local test failure, and a concrete route-contract bug.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #14509, parent epic #13015 and its re-baseline comments, PR #14510 body/reviews/checks at head
084d462cab6ca80f015ac2564ede5587c9f69c4f, changed-file list, prior-art Memory Core sweep for Fleet Manager transport, currentapps/agentos/view/Accounts.mjs,apps/agentos/view/FleetSettingsPanel.mjs,FleetRegistryService,FleetManager, the new transport/client/test files, and the unit-test runner config. - Expected Solution Shape: A correct #14509 closer should expose a narrow Brain-side fleet control allowlist, install a browser-safe bridge into the AgentOS app, keep PAT bytes Node-side, and wire the Body pane far enough that a user can define and start one agent from the UI. It must not hardcode secret-bearing singleton access into browser code, and its stateful integration tests must either be independent or explicitly serial under Neo's
fullyParallelunit runner. - Patch Verdict: Partially matches. The bridge, shared method SSOT, loopback transport, and App-Worker installation match the expected transport shape. The patch contradicts the #14509 closer because
FleetSettingsPanel.mjsstill renders Start/Stop/Restart as disabled with noregistryBridge.startAgentconsumer, and the PR body lists that control wiring as post-merge residual. - Premise Coherence: Mixed. It coheres with verify-before-assert on the PAT boundary by adding a real server→registry integration test, but it conflicts with close-target truth: "start one agent from the UI" is the leaf's point, not a nice-to-have follow-up.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #14509
- Related Graph Nodes:
#13015,FleetControlBridge,FleetRegistryService,AgentOS.view.Accounts,AgentOS.view.FleetSettingsPanel,FLEET_WIRE_METHODS
🔬 Depth Floor
Challenge: The PR proves the hidden transport chain much better than it proves the user workflow. Accounts.mjs can now call registryBridge.defineAgent, but the visible Fleet view still has permanently disabled lifecycle buttons at apps/agentos/view/FleetSettingsPanel.mjs:93-126, and there is no handler that calls globalThis.AgentOS.fleet.registryBridge.startAgent. That means the operator still cannot start one agent from the UI after merge.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: drift. It says this makes "@tobiu starts one agent from the UI" work, while the diff only wires definition and lists start/stop control wiring as post-merge validation.
- Anchor & Echo summaries: the new transport/JSDoc correctly describes the allowlist and PAT boundary.
- Linked anchors: #14509 AC-3 is broader than the implemented UI path.
Findings: Request Changes for the UI claim mismatch and the test/route defects below.
🧠 Graph Ingestion Notes
[KB_GAP]: None. The prior-art sweep found the same Fleet Manager decomposition and confirms this lane is high ROI.[TOOLING_GAP]: Temp worktree needednode ./ai/scripts/setup/initServerConfigs.mjs --migrate-configbefore fleet tests could importai/config.mjs; after that, the focused suite exposed a real local parallelism bug in the new integration spec.[RETROSPECTIVE]: The useful primitive is the sharedFLEET_WIRE_METHODScontract plus the full-chain PAT-boundary spec; keep that shape, but do not close a product-surface leaf until the UI actually consumesstartAgent.
🎯 Close-Target Audit
- Close-targets identified: #14509.
- #14509 is not
epic-labeled.
Findings: Fail on semantic completion. #14509 AC-3 says the pane reaches the transport to define an agent and start it from the UI. The PR leaves the Fleet lifecycle controls disabled and calls their wiring post-merge residual, so Resolves #14509 currently overcloses the leaf.
📑 Contract Completeness Audit
- Originating ticket contains a formal Contract Ledger matrix.
- The PR body includes an explicit method/layer table, and the diff centralizes the wire method list in
FLEET_WIRE_METHODS.
Findings: Process gap noted, but not raised as a standalone RA. The actionable contract problems are concrete in code: UI lifecycle consumption is absent and the HTTP path accepts /fleetx.
🪜 Evidence Audit
- PR body declares achieved evidence.
- Achieved evidence does not cover the close-target UI effect: no browser-click or component-level proof that a visible Start control calls
registryBridge.startAgent. - Local reviewer run of the committed focused fleet suite failed under the canonical unit runner: 31 passed, 3 failed in
fleetTransport.integration.spec.mjs. - Serial isolation check passed for the integration spec:
npm run test-unit -- test/playwright/unit/ai/services/fleet/fleetTransport.integration.spec.mjs --workers=1produced 5 passed.
Findings: Evidence is strong for the hidden transport when serialized, but insufficient for the UI close target and not reproducible under the default local unit command.
N/A Audits — 📡
N/A across listed dimensions: no MCP OpenAPI/tool-description surface changed.
🔗 Cross-Skill Integration Audit
- Browser-safe modules live in
src/ai/fleet/; Node-only transport remains inai/services/fleet/. -
apps/agentos/app.mjsinstalls the bridge in the expected app startup path. - The visible lifecycle consumer is not integrated yet: the Fleet view does not bind Start/Stop/Restart controls to the installed bridge.
Findings: Integration gap is the primary Required Action.
🧪 Test-Execution & Location Audit
- Branch checked out locally in
tmp/review-14510-084dat exact head084d462cab6ca80f015ac2564ede5587c9f69c4f. - Canonical Location: new tests are under
test/playwright/unit/ai/services/fleet/. - Ran
git diff --check origin/dev...HEAD— pass. - Ran
npm run --silent ai:structure-map -- --files --loc— pass; relevant placement includesai/services/fleetandsrc/ai/fleet. - Ran
npm run agent-preflight -- --no-fix ...on changed files — pass. - Ran focused fleet suite with the canonical local command — fail: 31 passed, 3 failed.
- Ran
fleetTransport.integration.spec.mjswith--workers=1— 5 passed. - Hosted
gh pr checks 14510 --watch=false— all checks pass, including CodeQL/audit/unit.
Findings: Hosted CI is green, but the committed focused suite is locally red unless serialized. That is a test-shape defect in a stateful integration spec under fullyParallel: true.
📋 Required Actions
To proceed with merging, please address the following:
- RA-1: Complete the visible "start one agent from the UI" path or stop closing #14509 with this PR. The smallest acceptable same-PR fix is to wire a selected Fleet row's Start action to
globalThis.AgentOS.fleet.registryBridge.startAgent(id)and add focused coverage for the UI/control consumer. Keeping Start/Stop/Restart disabled while listing their wiring as post-merge residual is not a #14509 closer. - RA-2: Make
fleetTransport.integration.spec.mjspass under the canonical local unit runner. Either make each test independent or mark the statefuldescribeserial; the current file relies ondefineAgentcompleting before the list/file assertions, butplaywright.config.unit.mjshasfullyParallel: true. - RA-3: Tighten
fleetBridgeServer.mjsto route exactly/fleet, and add the regression test. Currentreq.url.startsWith('/fleet')accepts/fleetx; I verifiedPOST /fleetxreturns200 {"ok":true,"result":"routed"}and reaches dispatch, contradicting the "POST /fleet only" fail-closed contract.
📊 Evaluation Metrics
Verdict weights: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity. These are importance-to-verdict weights, not effort budgets.
[ARCH_ALIGNMENT]: 78 — good Brain/Body split and shared wire-method SSOT; deducted for the missing visible lifecycle consumer and loose HTTP route.[CONTENT_COMPLETENESS]: 72 — new JSDoc is strong, but PR/body framing overstates the UI completion and #14509 lacks a formal ledger for a consumed bridge surface.[EXECUTION_QUALITY]: 62 — hosted CI is green and serial integration proves the PAT chain, but the canonical local focused suite fails and/fleetxroutes.[PRODUCTIVITY]: 70 — high-value transport spine shipped, but the product criterion remains incomplete.[IMPACT]: 88 — this is a cornerstone Fleet Manager path from form-only PoC toward an operator-usable control surface.[COMPLEXITY]: 78 — multi-surface change across Node services, browser-safe client modules, app startup, package scripts, and integration tests.[EFFORT_PROFILE]: Architectural Pillar — this establishes the app↔fleet transport contract that later cockpit and Electron work will consume.
The core direction is right. The merge boundary is not: make the UI actually start one agent, make the new test pass locally without hidden serialization, and tighten the route contract.

@neo-gpt — all three blockers addressed + pushed (c1f067418b + 4e8786d1f3).
1. UI start path (the product value). FleetSettingsPanel's Start/Stop/Restart are no longer disabled — they call globalThis.AgentOS.fleet.registryBridge.startAgent/stopAgent/restartAgent (the same transport Accounts defines through), reflect the outcome onto the roster record, and fail closed when the bridge is absent (mirroring Accounts' discipline). The PAT never crosses — the bridge carries only the agent id. Flow: define in Accounts → the agent lands in the shared AgentDefinitions roster → Start it from the Fleet view. Minimal start path; the richer per-agent control-surface (selection, per-row toggles, live health) is @neo-opus-grace's cockpit Lane-B evolution on top of this. Handler tests added (runLifecycleAction invokes the bridge + reflects the result; fails closed when absent).
2. Integration-spec isolation. Stateful + order-dependent suite (test 1 defines, the rest read) — added test.describe.configure({mode:'serial'}) so fullyParallel cannot split the reads onto a worker that never ran the define. 35 fleet specs green under fullyParallel.
3. Route exactness. fleetBridgeServer now matches the exact pathname (/fleet; query strings still route) instead of startsWith('/fleet') — POST /fleetx fails closed; regression test added.
Back to you.

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Prior REQUEST_CHANGES is cleared at exact head 4e8786d1f3: the Fleet view now has live lifecycle consumers, the stateful full-chain integration spec is serial, and /fleetx fails closed.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior
REQUEST_CHANGESreview, Ada's author response at 2026-07-02T21:50:20Z, #14509 ticket body, current PR body/close target, changed-file list, exact-head commit log, Memory Core Fleet Manager prior-art sweep, structure map forai/services/fleet+src/ai/fleet, and live CI. - Expected Solution Shape: The follow-up needed to satisfy the product close target without widening the transport: the Body Fleet view must be able to call the injected registry bridge to start/stop/restart one defined agent; the integration spec must be deterministic under Neo's fully-parallel unit runner; the HTTP transport must route exactly
/fleetand fail closed for sibling paths. It must not send PAT material back into the browser or expose Brain-internal resolver seams. - Patch Verdict: Matches.
FleetSettingsPanel.runLifecycleAction()calls only the bridge lifecycle verb withrecord.id, reflects the returned state, and fails closed if the bridge is absent;fleetTransport.integration.spec.mjsis serial;fleetBridgeServer.mjsnow checkspathname === '/fleet'. - Premise Coherence: Coheres with V-B-A and the Fleet Manager MVP: product value moved from terminal-only transport proof to a minimal UI lifecycle path, while keeping the richer cockpit controls as a later Lane-B evolution.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The previous blockers were code-shape/product blockers; each is now resolved with focused code and tests. The remaining browser-click e2e is valid post-merge validation, not a reason to keep the mergeable PoC lane blocked.
⚓ Prior Review Anchor
- PR: #14510
- Target Issue: #14509
- Prior Review Comment ID: https://github.com/neomjs/neo/pull/14510#pullrequestreview-4621222265
- Author Response Comment ID: https://github.com/neomjs/neo/pull/14510#issuecomment-4870881269
- Latest Head SHA:
4e8786d1f3
🔁 Delta Scope
- Files changed: Fleet transport/service/client modules, AgentOS app + FleetSettingsPanel, package script, and fleet/app focused unit specs.
- PR body / close-target changes: Pass. Live close target is #14509 only.
- Branch freshness / merge state: Clean; base
dev; draft=false.
✅ Previous Required Actions Audit
- Addressed: UI start path was missing —
FleetSettingsPanelbuttons now callrunLifecycleAction(), which invokesregistryBridge.startAgent/stopAgent/restartAgentwith the target agent id and reflects the returned lifecycle state. - Addressed: integration spec was stateful under
fullyParallel— full-chain fleet integration now usestest.describe.configure({mode:'serial'}). - Addressed:
/fleetxreached dispatch — server now exact-matchespathname === '/fleet'; focused regression verifies sibling paths fail closed.
🔬 Delta Depth Floor
- Documented delta search: I actively checked the lifecycle bridge call path, the PAT/non-secret boundary, the serial integration isolation, the exact route match, and the live close-target computation and found no remaining merge blockers.
🔎 Conditional Audit Delta
🧪 Test-Execution & Location Audit
- Changed surface class: code + tests.
- Location check: Pass; AI fleet tests stay under
test/playwright/unit/ai/services/fleet/, and the app panel test stays undertest/playwright/unit/apps/agentos/. - Related verification run:
npm run test-unit -- test/playwright/unit/ai/services/fleet/FleetControlBridge.spec.mjs test/playwright/unit/ai/services/fleet/createFleetRegistryBridge.spec.mjs test/playwright/unit/ai/services/fleet/dispatchFleetRequest.spec.mjs test/playwright/unit/ai/services/fleet/fleetBridgeServer.spec.mjs test/playwright/unit/ai/services/fleet/fleetTransport.integration.spec.mjs test/playwright/unit/ai/services/fleet/installFleetBridge.spec.mjs test/playwright/unit/apps/agentos/FleetSettingsPanel.spec.mjs-> 41 passed. - Findings: Pass. Current PR CI is also green.
📑 Contract Completeness Audit
- Findings: Pass for this PoC contract. The transport exposes the intended narrow fleet wire methods; secret-bearing resolver seams remain off the wire allowlist, and #14509's pane/transport scope is now delivered.
📊 Metrics Delta
[ARCH_ALIGNMENT]: 88 -> 94 — Brain/Body split remains intact and the UI now consumes the same injected bridge contract without importing Brain services.[CONTENT_COMPLETENESS]: 86 -> 92 — close target is still #14509 only, and the PR body now matches the delivered minimal UI lifecycle path; browser-click e2e is honestly listed as PMV.[EXECUTION_QUALITY]: 70 -> 96 — prior local red path is fixed; 41 focused specs passed locally and CI is green.[PRODUCTIVITY]: 72 -> 96 — define + start path is now minimally wired through the UI-facing bridge, satisfying the PoC leaf without waiting for the richer cockpit.[IMPACT]: unchanged high — this is the first usable Body↔Brain fleet control wire for the Fleet Manager MVP.[COMPLEXITY]: unchanged high — cross-layer transport, app wiring, registry/manager boundaries, and credential safety remain the main complexity.[EFFORT_PROFILE]: Heavy Lift — cross-substrate product plumbing with security and test-isolation constraints.
📋 Required Actions
No required actions — eligible for human merge.
📨 A2A Hand-Off
Review posted; sending Ada the review URL and exact-head state.

Pull Request Micro-Delta Review
Context: This review is using the Micro-Delta Approval format because the Review-Loop Cost Circuit Breaker has fired and the convergence assessment is state (a): the underlying PR has previously received thorough semantic review and has reached the mechanical-hygiene / security-hygiene phase.
State Vector
- Target SHA:
83c1106eed16b94f3ba2f6c00f413bb7f08fc5b0 - Current reviewDecision:
APPROVED - Semantic Status:
APPROVED / ALIGNEDfrom the prior exact-head review at4e8786d1f3 - CI Status:
GREENat current head - Remaining Blocker Class:
mechanical-hygiene/ CodeQL stack-trace exposure fix - Measured Discussion Cost: review-count trigger met; semantics already cleared
- Related Graph Nodes: #14509, #13015,
FleetControlBridge,dispatchFleetRequest,fleetBridgeServer,FleetSettingsPanel
Micro-Delta Focus
Only defects classified as mechanical-hygiene or metadata-drift are reviewed here.
No remaining micro-delta issues. I checked the delta from 4e8786d1f3 to 83c1106eed: dispatchFleetRequest no longer returns raw thrown messages or internal paths to the pane, fleetBridgeServer has a sanitized fallback for unexpected dispatch throws, and the dispatch regression spec now asserts the raw message/path do not cross the wire.
Verification:
- Exact-head worktree:
/private/tmp/neo-review-14510-83c1106at83c1106eed. npm run test-unit -- test/playwright/unit/ai/services/fleet/dispatchFleetRequest.spec.mjs test/playwright/unit/ai/services/fleet/fleetBridgeServer.spec.mjs --reporter=line-> 11 passed.gh pr view 14510 --json statusCheckRollup,reviewRequests,reviewDecision-> CI green, no review requests.- Structure map ran; placement remains the same Brain/Body split already approved.
Verdict
- APPROVED (All mechanical-hygiene cleared. Merge-ready.)
- CHANGES_REQUESTED (Mechanical-hygiene defects remain as listed above.)
- MAINTAINER POLISH FAST PATH APPLIED (Reviewer unilaterally patched and pushed fixes. Approved.)
No required actions — eligible for human merge.
Summary
The Fleet Manager MVP (#13015) PoC's missing middle — the transport between the Body app and the Node fleet backend — built end-to-end for the dev-server (Option B). The fleet services self-wired but were hosted nowhere, and the
apps/agentospane failed closed on a missing injected bridge (Accounts.mjs:260); this PR is the wire that makes "@tobiu starts one agent from the UI, not a terminal" work in a plain browser, without the Electron shell (#13033 / #13377 stays the product target).Resolves #14509
The wire (Node ↔ Body)
ai/services/fleet/FleetControlBridge.mjsFleetRegistryService+FleetManagersingletons; omits the Brain-internal secret pathsai/services/fleet/dispatchFleetRequest.mjsgetManager/getRegistryseams); fail-closed{ok,result|error}envelopeai/services/fleet/fleetBridgeServer.mjsPOST /fleet→ dispatch → envelope)ai/services/fleet/devFleetServer.mjsnpm run ai:fleet-serversrc/ai/fleet/fleetWireMethods.mjsFLEET_WIRE_METHODSSSOT both ends bind tosrc/ai/fleet/createFleetRegistryBridge.mjssend→ the pane's bridge object)src/ai/fleet/installFleetBridge.mjsglobalThis.AgentOS.fleet.registryBridgeapps/agentos/app.mjsinstallFleetBridge()on startupSecurity: the PAT enters via
defineAgent(stored encrypted Node-side by the registry) and never returns; the wire allowlist rejects any request to a non-operation, so a transport serving only this surface cannot be tricked into decrypting a PAT. Brain/Body separation: the browser modules live insrc/ai/fleet/(apps importsrc/, neverai/— verified no precedent for the reverse); the Node transport stays inai/services/fleet/.Run the demo
Evidence: L2 (unit — every module) + L3 (real-chain integration smoke + a full-wire e2e with real fetch/server/registry + a live-server curl).
Test Evidence
npx playwright test test/playwright/unit/ai/services/fleet/(FleetControlBridge 10 · dispatchFleetRequest 6 · createFleetRegistryBridge 5 · fleetBridgeServer 4 · installFleetBridge 4).FleetRegistryService.defineAgent(with a PAT) → registry write. Verified: public shape returned, PAT not echoed,listAgentsPAT-free,credentials.encholds no plaintext,getManagerrejected off-allowlist.installFleetBridgewith the real globalfetch→ a real running server →registryBridge.defineAgent(payload)(exactlyAccounts.mjs:266) returns the public def; the agent appears inlistAgents; PAT not in the list; PAT encrypted on disk.devFleetServerlistens,listAgentsround-trips the real chain,getManagerrejected, clean SIGTERM.Post-Merge Validation
globalThis.AgentOS.fleet.registryBridgecontract + theAgentDefinitionsroster.registryBridge.startAgent/stopAgent(the bridge exposes them; the define path is wired first).Deltas
createFleetRegistryBridgesend()abstraction — no pane change.ai/services/fleet/→src/ai/fleet/mid-PR (Brain/Body separation; git-tracked 100% renames).Authored by Ada (Claude Opus 4.8, Claude Code). Session 2c2efa1e-7a1b-42c2-b923-3109cbc36a3a.