15 KiB
Nexus Agent-first and Performance V2 — implementation and acceptance
Milestone date: 2026-07-30 Final documentation review: 2026-07-30 Scope: local combined working tree; no commit, push, deployment or VPS write Outcome: core architecture implemented locally; production provisioning, live OpenClaw acceptance and measured load gates remain blocked or unproven
Executive verdict
Nexus now has a coherent durable path for owner-approved agent proposals, PostgreSQL-backed workflow events, typed frontend contracts and an efficient Task Board read model. The implementation materially reduces duplicate requests and broad refreshes for the migrated domains.
This is not a production-readiness or performance-budget claim:
- productive OpenClaw writes remain intentionally disabled until a pinned OpenClaw release officially supports an external Nexus or generic operator Client ID;
- no real OpenClaw pairing, agent creation or
Nexus -> OpenClaw -> OpenAI -> Nexuswrite flow was performed; - the controlled Playwright server is synthetic;
- Docker/Testcontainers, Toxiproxy, k6, Promptfoo live evaluation,
EXPLAIN (ANALYZE, BUFFERS)and the browser p95 budget require separate, isolated acceptance runs.
Implemented architecture
One typed API contract
- ASP.NET Core emits OpenAPI 3.1 to
backend/openapi/Nexus.Api.json. openapi-typescriptgeneratesfrontend/src/api/generated/schema.d.ts;openapi-fetchis the typed transport for migrated endpoints.- CI regenerates the schema and rejects a diff.
ProblemDetailsandValidationProblemDetailsare the common HTTP error shape. The server attachestraceId; the frontend uses one error adapter.EntityRefDto,OperationResultDto,DomainEventDtoandTaskBoardPageDtoare explicit public contracts rather than view-model inference.
Server-state migration
TanStack Vue Query owns the migrated server state:
- Task Board;
- projects and project-scoped tasks;
- agent proposals and create options;
- Nexus activity and notifications;
- OpenClaw overview, agents, runs, cron and models;
- agent details and configuration reads; and
- owner-only Memory, Docs, Incidents and Security reads.
The Query-key factory makes multiple consumers share one request. Background refresh keeps previous visible data. Pinia still owns authentication, command and Iris modal state, setup/wizard workflow state, local drafts and shared mutation facades; it does not duplicate canonical runtime collections.
After route and error-state parity checks, the legacy operations/task/
notification/dashboard server-state stores, static agent inventory and
mappers, duplicate liveSync.ts/live-sync.ts modules and the old generic
live-service reader were removed. The backend compatibility endpoints remain
temporarily available, but no active frontend consumer uses them as its
canonical cache.
Memory, Docs and Incidents no longer use host workspace mounts. Their owner-only services read OpenClaw workspace content through confined RPC, return source-agent and workspace-path provenance and expose no arbitrary workspace write path.
PostgreSQL workflow and event backbone
Migration 20260730224500_AddAgentProvisioningAndBoardIndexes adds:
AgentProposals;AgentProvisionRequests;OperationClaims; andOutboxEvents.
For migrated Nexus-owned mutations, domain state and outbox event are stored in
the same EF transaction. The registered OpenClaw mutation claim store also uses
PostgreSQL OperationClaims plus a database transaction and lock; the former
JSONL path is exposed only for discovery of an immutable legacy archive and is
not read or appended. The background worker:
- leases pending work with
FOR UPDATE SKIP LOCKED; - uses a bounded single-process wake-up channel plus database polling for restart recovery;
- publishes content-minimized events to subscriber queues of 64 entries;
- retains at least 24 hours and at least 10,000 global sequences; and
- exposes at most 512 replay deltas per reconnect.
GET /api/v1/events?afterSequence= resumes by global sequence. A missing or
expired range produces resync_required; the browser refreshes affected Query
domains rather than silently accepting a gap. The existing OpenClaw event
projection remains a separate sanitized Runtime adapter during migration.
Authenticated SSE hub
The frontend uses one fetch-based AuthenticatedSseHub with:
- bearer authentication and the existing refresh path;
eventsource-parser;- abort and subscriber lifecycle;
- heartbeat detection;
- jittered reconnect; and
- a 256 KiB maximum parser buffer.
Task events normally reconcile one card through
GET /api/v1/tasks/{id}/board-card. Other events batch small Query-domain
invalidations. The Dashboard legacy SSE path was hardened for cursor
continuation and cancellation but remains a compatibility surface.
Agent proposal and provisioning flow
Shared flow
The manual /agents/new UI and Iris use the same durable service:
local form draft -> awaiting_approval -> provisioning
-> ready | partial | failed | in_doubt
-> rejected
New APIs:
GET /api/v1/openclaw/agents/create-optionsGET|POST /api/v1/openclaw/agent-proposalsGET /api/v1/openclaw/agent-proposals/{proposalId}POST /api/v1/openclaw/agent-proposals/{proposalId}/approvePOST /api/v1/openclaw/agent-proposals/{proposalId}/rejectPOST /api/v1/openclaw/agent-proposals/{proposalId}/retry
Proposal lists use a stable (CreatedAt, Id) keyset cursor, including equal
timestamps. Owner mutations require an Idempotency Key, correlation ID,
optimistic proposal revision and authenticated actor.
Iris boundary
Iris receives only:
nexus_propose_agent; andnexus_get_agent_proposal.
Both MCP tools return structured content and stable state/error information. They cannot approve a proposal or call OpenClaw. Tool annotations describe read-only, destructive, idempotent and open-world behavior but are not used as authorization.
Provisioning safety
After explicit owner approval, Nexus rechecks:
- local
ManagementEnabled; - official external Client-ID support;
- normalized endpoint and TLS trust;
- current capability hash and required advertised methods;
operator.admin;- proposal revision; and
- idempotency claim.
The workspace root is server-controlled and checked against live OpenClaw
configuration. Nexus calls agents.create at most once. After a possible
dispatch timeout it records in_doubt and permits only read-only inventory
reconciliation before another action. A successful create is not ready until
agents.list confirms it. Approved standard files are written through
agents.files.set and read back; a later file failure becomes partial and
does not trigger automatic deletion.
The production button remains disabled because OpenClaw 2026.7.1 does not
register the required external Nexus/generic operator identity. Nexus does not
impersonate CLI, Control UI or gateway-client/backend.
Task Board V2
GET /api/v1/tasks/board?doneLimit=50&doneCursor= returns:
- every non-Done card on the initial page;
- the newest 50 Done cards by default;
- an opaque
(UpdatedAt, Id)keyset cursor for further Done pages; and - a stable board revision.
The repository uses AsNoTracking and direct DTO projection. Child counts and
latest activity are correlated scalar projections rather than N+1 reads. The
initial path uses at most three SQL statements; a Done continuation skips the
active-card query and uses two. The migration adds state, partial Done,
activity, child and agent-workflow indexes.
The Vue client uses useInfiniteQuery, deduplicates Done cards and keeps all
active columns mounted for drag-and-drop. Moves are optimistic and roll back on
failure. Create, update, move and domain events fetch only the affected
board-card; full invalidation is a recovery path. Dashboard, sidebar,
Command Palette and Task Board use the same Query key instead of parallel board
loads.
No claim is made that the p95 budgets are met until the recorded 1,000-task/10,000-activity dataset, k6 run, SQL trace/plans and repeated browser timing run have been executed.
Cross-page result navigation
EntityRefDtocontains type, ID and optional label but no backend-generated URL.- The frontend resolver maps agent, proposal, project, task, run, cron, incident, document, notification and event-stream references to registered routes.
- Iris and proposal mutations can show
OperationResultCardwith primary and affected entities plus operation/trace metadata. - Projects now have a real
/projectsindex andGET /api/v1/projects/{id}/tasks; Project Detail no longer loads unrelated tasks. - Activity and Notifications use typed, authenticated domain queries and navigate to available related entities.
The 2026-07-31 structured operation-results follow-up closed the remaining task, project, notification, cron, config, approval, session and agent-file mutation gap. A global result tray now exposes the typed references and the addressed target surfaces consume their deep-link selection.
Resilience and observability
Microsoft.Extensions.Http.Resilienceprotects safe OpenClaw reads with a 10-second attempt timeout, 30-second total budget, bounded jittered retries and a circuit breaker.- Management mutations and Chat/Run have no automatic retry; Gateway WebSocket reconnect remains inside the connector.
- OpenTelemetry instruments ASP.NET Core, HttpClient, Npgsql, Task Board, Gateway RPC, proposals/provisioning, outbox and SSE-related metrics.
- OTLP export is opt-in through configuration; no extra production container is introduced.
web-vitalsreports an allow-list of metric, value, rating, route name, build version, live mode and correlation ID toPOST /api/v1/telemetry/browser.- Redaction removes URL queries/full URLs, SQL text, exception messages/stacks and content-bearing attributes. Prompts, chat text, Markdown, tool arguments, credentials, headers and entity names are not telemetry.
Dependency decisions
Implemented and pinned:
@tanstack/vue-query5.101.4eventsource-parser3.1.0openapi-fetch0.17.0openapi-typescript7.13.0web-vitals5.3.0- Playwright
1.62.0 - Testcontainers PostgreSQL/Toxiproxy
4.13.0in the test project only - OpenTelemetry
1.17.0 Microsoft.Extensions.Http.Resilience10.0.0
ModelContextProtocol.AspNetCore remains pinned to 1.4.1. The
scripts/qa/test-mcp2-compatibility.ps1 candidate mode copies the project to a
temporary directory and may probe 2.0.0, but it cannot open the upgrade gate
without isolated live OpenClaw negotiation. The local isolated 2.0.0
compile/test probe is green; production deliberately remains on 1.4.1.
Not introduced: Redis, NATS, Kafka, RabbitMQ, Temporal, Hangfire, Quartz, GraphQL, SignalR, RxJS, direct OpenAI Agents/Responses orchestration, OPA, OpenFGA, pgvector or a second production service.
Automated verification
The following non-live checks were completed on 2026-07-30:
| Gate | Result |
|---|---|
.NET 10 / MCP 1.4.1 baseline |
Passed: 360; failed: 0; skipped: 5; total: 365 |
Isolated MCP 2.0.0 candidate copy |
Passed: 360; failed: 0; skipped: 5; compatibility probe only |
| MCP production pin/static markers | Passed; production project remains 1.4.1 |
Promptfoo wrapper -ValidateOnly |
Passed; configuration only, no live evaluation |
| PowerShell AST parse for all QA scripts | Passed |
node --check for k6, QA mock and Promptfoo provider |
Passed |
| Frontend typecheck | Passed; full Vue application and E2E TypeScript projects |
| Frontend unit tests | Passed: 12 files, 28 tests |
| Frontend production build | Passed: 1,984 modules transformed |
| Playwright controlled contract suite | Passed: 24 tests across all 20 core routes and 375/768/1024/1440/1920 px |
| Production dependency audit | Passed; no known vulnerabilities after pinning PostCSS 8.5.18 |
| OpenAPI generation repeatability | Passed; checked-in backend contract and generated TypeScript schema were stable |
The five skips are three explicitly gated PostgreSQL/Testcontainers provisioning tests, one Toxiproxy test and one PostgreSQL operation-claim concurrency test. Docker CLI was available but its daemon was not running. They were not executed and must not be described as passed integration evidence. The Playwright server is a controlled local contract fixture, not a real OpenClaw.
Not executed or not proven
The following acceptance evidence was not produced by this milestone:
- real pairing or scope upgrade against Bao's OpenClaw;
- a live agent create, file write or recovery mutation;
- a complete
Nexus -> OpenClaw -> OpenAI -> Nexusrun; - Docker-backed PostgreSQL/Toxiproxy evidence when the environment gate or Docker daemon is unavailable;
- k6 p95 thresholds on a verified 1,000-task/10,000-activity fixture;
EXPLAIN (ANALYZE, BUFFERS)and independent SQL-statement-count evidence;- repeated browser
navigation -> cards visiblep95 evidence; - live Promptfoo accuracy/injection evaluation against an isolated Nexus and test OpenClaw;
- live MCP 2.0
tools/list, Streamable HTTP and down-level negotiation; and - production OTLP or
pg_stat_statementsactivation.
The repository contains guarded scripts and tests for several of these checks. Static syntax/config validation proves only the artifacts, not their external systems or thresholds.
Residual work and release gates
- Obtain and pin official external Nexus/generic-operator Client-ID support.
- Run read-only pairing and inventory acceptance, then a separately approved disposable management-write sequence.
- Run Docker integration, Toxiproxy, k6, SQL-plan, repeated browser and Promptfoo release gates with archived sanitized evidence.
- Enable
pg_stat_statementsonly through a separately approved PostgreSQL maintenance window because it requires server configuration/restart. - Reconsider virtualization, pgvector/QMD and external policy engines only after measurements or multi-operator/tenant requirements justify them.
Primary code and evidence pointers
backend/openapi/Nexus.Api.jsonbackend/Data/Migrations/20260730224500_AddAgentProvisioningAndBoardIndexes.csbackend/Services/AgentProposalService.csbackend/Services/DomainEventStreamService.csbackend/Repositories/TaskRepository.csfrontend/src/api/queryClient.tsfrontend/src/api/taskBoard.tsfrontend/src/services/sseHub.tsfrontend/src/services/domainEvents.tsfrontend/e2e/agent-proposals.e2e.tsfrontend/e2e/route-smoke.e2e.tsfrontend/e2e/task-board.e2e.ts- QA automation and evidence boundaries
- Agent-first target contract
- OpenClaw Attach & Adopt evidence