cd8c78d165
CI - Build & Test / Backend (.NET) (push) Successful in 45s
CI - Build & Test / Backend integration (PostgreSQL/Toxiproxy) (push) Failing after 1m0s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m49s
CI - Build & Test / Security Check (push) Successful in 7s
CI - Build & Test / Deploy Nexus (push) Has been skipped
727 lines
38 KiB
Markdown
727 lines
38 KiB
Markdown
# Nexus
|
|
|
|
Nexus is the operations platform for the Noveria ecosystem. OpenClaw is the
|
|
mandatory agent runtime and gateway behind the Nexus control plane; it remains
|
|
isolated from the frontend and the Nexus domain model.
|
|
|
|
> **Project audit (2026-07-26, commit `3bc7622`):**
|
|
> [analysis](docs/PROJECT_ANALYSIS_2026-07-26.md),
|
|
> [all-page audit](docs/audits/2026-07-26/PAGE_AUDIT.md),
|
|
> [security spot check](docs/SECURITY_SPOT_CHECK_2026-07-26.md), and
|
|
> [evaluation](docs/PROJECT_EVALUATION_2026-07-26.md).
|
|
|
|
> **Agent-first evaluation (2026-07-27):**
|
|
> [all-page and capability evaluation](docs/audits/2026-07-27/agent-first-evaluation/PAGE_AND_CAPABILITY_EVALUATION.md),
|
|
> [mission-control target contract](docs/AGENT_FIRST_MISSION_CONTROL.md), and
|
|
> [canonical roadmap](docs/MISSION_CONTROL_ROADMAP.md).
|
|
|
|
> **OpenClaw core integration checkpoint (2026-07-28):**
|
|
> [implementation evidence](docs/audits/2026-07-28/openclaw-core-integration/IMPLEMENTATION_EVIDENCE.md),
|
|
> [route evaluation](docs/audits/2026-07-28/openclaw-core-integration/ROUTE_EVALUATION.md),
|
|
> and [design QA](docs/audits/2026-07-28/openclaw-core-integration/design-qa.md).
|
|
|
|
> **OpenClaw agent-first hardening checkpoint (2026-07-30):**
|
|
> [acceptance evidence](docs/audits/2026-07-30/openclaw-agent-first-hardening/ACCEPTANCE_EVIDENCE.md),
|
|
> [route and agent-first evaluation](docs/audits/2026-07-30/openclaw-agent-first-hardening/ROUTE_AND_AGENT_FIRST_EVALUATION.md),
|
|
> [Gateway connection contract](docs/OPENCLAW_GATEWAY_CONNECTION.md), and
|
|
> [agent-first target contract](docs/AGENT_FIRST_MISSION_CONTROL.md).
|
|
>
|
|
> **OpenClaw Attach & Adopt checkpoint (2026-07-30):**
|
|
> [implementation and acceptance](docs/audits/2026-07-30/openclaw-attach-adopt/IMPLEMENTATION_AND_ACCEPTANCE.md)
|
|
> and
|
|
> [structural proof preflight](docs/audits/2026-07-30/openclaw-attach-adopt/STRUCTURAL_PROOF_PREFLIGHT.md).
|
|
>
|
|
> **Agent-first and Performance V2 checkpoint (2026-07-30):**
|
|
> [implementation and acceptance](docs/audits/2026-07-30/agent-first-performance-v2/IMPLEMENTATION_AND_ACCEPTANCE.md),
|
|
> [agent-first target contract](docs/AGENT_FIRST_MISSION_CONTROL.md), and
|
|
> [QA automation boundaries](docs/QA_AUTOMATION.md).
|
|
>
|
|
> **Structured operation results checkpoint (2026-07-31):**
|
|
> [implementation and acceptance](docs/audits/2026-07-31/operation-results-deep-links/IMPLEMENTATION_AND_ACCEPTANCE.md).
|
|
>
|
|
> **Production release v0.2.59 (2026-07-31):**
|
|
> [production validation, route matrix and next plan](docs/audits/2026-07-31/production-release-v0.2.59/PRODUCTION_VALIDATION_AND_NEXT_PLAN.md).
|
|
> Gitea run 362 deployed commit `144edf58fe5928a3e04816f4435ea574d64211a1`;
|
|
> PostgreSQL and the OpenClaw HTTP runtime are healthy. Productive Protocol-v4
|
|
> management remains intentionally blocked by the external Client-ID gate.
|
|
>
|
|
> **Stability and recovery v0.2.60 candidate (2026-07-31):**
|
|
> [implementation and acceptance](docs/audits/2026-07-31/stability-v0.2.60/IMPLEMENTATION_AND_ACCEPTANCE.md).
|
|
> Readiness, browser-origin protection, generated ProblemDetails metadata,
|
|
> shared UI recovery states, version provenance and mandatory container-backed
|
|
> CI are implemented. The audit separates locally proven behavior from the
|
|
> Linux/Docker, deployment, credentialed-production and OpenClaw-write gates.
|
|
|
|
> 📋 **Architektur-Review** (2026-06-22): Board-first Orchestrierung, sichere
|
|
> Backend-Brücke und Gateway-Integration geprüft. Siehe
|
|
> [`docs/architecture-board-first-orchestration.md`](docs/architecture-board-first-orchestration.md)
|
|
|
|
> CI runs automatically on every push. CD runs **inside the green CI run**
|
|
> on main or can be triggered **manually** (workflow_dispatch). Deploy reads
|
|
> `VERSION` but does not mutate Git or create tags. Rollback and database backup
|
|
> are separate manual workflows.
|
|
> See [phases/deployment.md](phases/deployment.md) for full CD documentation.
|
|
|
|
## Current foundation
|
|
|
|
- Vue 3, TypeScript, Pinia, Vue Router and Tailwind CSS
|
|
- ASP.NET Core 10 REST API (Minimal API pattern)
|
|
- Entity Framework Core and PostgreSQL
|
|
- generated OpenAPI 3.1 contracts with `openapi-typescript` and `openapi-fetch`
|
|
- TanStack Vue Query for migrated server-state domains
|
|
- PostgreSQL transactional outbox and a sequenced domain-event stream
|
|
- OpenTelemetry instrumentation and allow-listed browser Web Vitals
|
|
- JWT owner authentication with rotating refresh sessions
|
|
- `IAgentRuntime` abstraction with OpenClaw as the currently registered runtime
|
|
- protocol-v4 `IGatewayConnector` and browser-safe `IOpenClawControlService`
|
|
- owner-only OpenClaw Attach & Adopt setup with one persisted `primary` profile
|
|
- live OpenClaw agent files, schema-based config and cron management through RPC
|
|
- owner-approved agent proposals with durable provisioning recovery
|
|
- keyset-paginated Task Board with targeted live card reconciliation
|
|
- structured mutation results with entity references, trace metadata and
|
|
cross-page frontend deep links
|
|
- one generated `ProblemDetails` contract and shared loading, empty, error,
|
|
offline, stale and partial presentation across all authenticated views
|
|
- separate process liveness, database-backed readiness and full runtime
|
|
diagnostics used consistently by deploy and rollback
|
|
- Responsive dark-mode operations dashboard
|
|
- Traefik reverse-proxy with Let's Encrypt TLS on `nexus.noveria.net`
|
|
|
|
## Product target
|
|
|
|
Nexus is the primary daily control plane for agents, tasks, runs, approvals,
|
|
tools, schedules, knowledge and operational recovery. All agent and model
|
|
execution travels through OpenClaw; OpenAI is the intended primary provider
|
|
configured inside OpenClaw. Nexus does not call OpenAI directly. The browser
|
|
and Nexus domain model stay independent of gateway and provider internals.
|
|
|
|
The binding product and architecture direction is documented in
|
|
[Agent-First Mission Control](docs/AGENT_FIRST_MISSION_CONTROL.md); the ordered
|
|
feature plan is the [Mission Control Roadmap](docs/MISSION_CONTROL_ROADMAP.md).
|
|
|
|
## Local/container start
|
|
|
|
```bash
|
|
cp .env.template .env
|
|
# Replace every placeholder, especially POSTGRES_PASSWORD, JWT_KEY,
|
|
# BOOTSTRAP_OWNER_EMAIL, BOOTSTRAP_OWNER_PASSWORD and the OpenClaw credential.
|
|
# Pin OPENCLAW_REQUIRED_VERSION for a production deployment.
|
|
docker compose up --build -d
|
|
curl http://127.0.0.1:18880/health/live
|
|
curl http://127.0.0.1:18880/health/ready
|
|
curl http://127.0.0.1:18880/health
|
|
```
|
|
|
|
On an empty database the API creates exactly one owner from `BOOTSTRAP_OWNER_EMAIL`,
|
|
derives the initial display name from that email, and hashes the explicitly configured
|
|
`BOOTSTRAP_OWNER_PASSWORD`. Bootstrap credentials are never written to application logs.
|
|
After first seed the password lives only in PostgreSQL. Existing databases are
|
|
never overwritten by the bootstrap process.
|
|
|
|
The API is exposed via Traefik reverse-proxy with automatic Let's Encrypt TLS.
|
|
Health checks, rate limiting, and security headers are active.
|
|
|
|
## OpenClaw runtime data
|
|
|
|
OpenClaw remains authoritative for its agents, bootstrap files, arbitrary
|
|
workspace files, configuration and cron jobs. Nexus does not copy this state
|
|
into a competing configuration:
|
|
|
|
- agent inventory comes from `agents.list`;
|
|
- supported bootstrap files are read and written through
|
|
`agents.files.list/get/set`;
|
|
- additional workspace files are browsed read-only through
|
|
`agents.workspace.list/get`; and
|
|
- OpenClaw configuration is read and patched through
|
|
`config.schema.lookup`, `config.get` and `config.patch`.
|
|
|
|
Agent inventory and configuration therefore do not depend on a
|
|
`/mnt/workspace-{agentId}` naming convention. The owner-only Nexus
|
|
Memory/Docs/Incidents read surfaces also resolve their live content through
|
|
OpenClaw RPC. Their DTOs retain the source agent and safe workspace path so the
|
|
UI can show provenance without mounting or inferring a host workspace.
|
|
|
|
## Frontend architecture
|
|
|
|
### Server-state and API boundary
|
|
|
|
- `backend/openapi/Nexus.Api.json` is the checked-in OpenAPI 3.1 contract.
|
|
`pnpm openapi:generate` produces
|
|
`frontend/src/api/generated/schema.d.ts`; CI rejects generated drift.
|
|
- `frontend/src/api/` owns generated DTO use, typed requests, Query keys and
|
|
the common `ProblemDetails` adapter. Views must not reimplement transport
|
|
contracts.
|
|
- TanStack Vue Query owns canonical reads for the Task Board, projects,
|
|
proposals, activity, notifications and the OpenClaw agent, overview, run,
|
|
cron, model, content and security domains. Shared Query keys deduplicate
|
|
consumers and preserve visible data during background refresh.
|
|
- Pinia remains only for authentication, navigation/modals, local drafts,
|
|
setup/wizard workflow state and shared command facades. It is not a second
|
|
cache for canonical runtime collections.
|
|
- A single authenticated fetch-based SSE hub parses domain events with a
|
|
bounded buffer, token refresh, abort, heartbeat and jittered reconnect.
|
|
Content-minimized deltas patch or invalidate only affected Query domains.
|
|
- The old operations/task/notification/dashboard server-state stores, static
|
|
agent sources, duplicate live-sync modules and per-view SSE readers have
|
|
been removed after route and error-state parity checks.
|
|
|
|
### App.vue route rendering
|
|
|
|
`/dashboard` uses `NexusLayout`; `/login` renders directly. Routes with
|
|
`meta.standalone` render their registered view inside the shared legacy shell.
|
|
Projects, Models and Activity are dedicated typed views. Iris chat is a
|
|
global, on-demand modal on authenticated routes and has no separate `/chat`
|
|
route.
|
|
|
|
### Live orchestration dashboard
|
|
|
|
The dashboard prioritizes the live agent topology:
|
|
|
|
- **AlertBar** — compact active/planning/idle, usage and blocker status.
|
|
- **FlowCanvas** — agent topology, selection, layout reset and model controls.
|
|
- **TaskStrip** — compact focus tasks linked to the task workflow.
|
|
- **IrisChat** — hidden by default and opened from the topbar as a modal.
|
|
- **AgentDetailModal** — live summary, activity and model selection.
|
|
|
|
### Global agent-first controls
|
|
|
|
- `Ctrl/Cmd+K` opens a real command palette on every authenticated route.
|
|
- The palette navigates to core surfaces and loaded projects, tasks, agents and
|
|
sessions. From a task, project or agent it can prefill a correlated durable
|
|
run.
|
|
- “Ask Iris” sends only bounded route, surface, object-type and object-id
|
|
context. The backend labels this caller-provided context as untrusted
|
|
metadata before placing it ahead of the user's message.
|
|
- Command and Iris dialogs are mutually exclusive and support keyboard
|
|
selection, dismissal and focus restoration.
|
|
- Mission-control mutations publish one shared result tray with status,
|
|
revision, trace metadata and links to their primary and affected entities.
|
|
Task, OpenClaw runtime, cron, approval, config, agent-file, project,
|
|
notification and activity links select the addressed result on the target
|
|
surface instead of only opening its index route.
|
|
|
|
### Authentication
|
|
|
|
- Passwords use versioned PBKDF2-SHA256 hashes with random salts and 210,000 iterations.
|
|
- Access tokens expire after 15 minutes and are held only in browser memory.
|
|
- Refresh tokens are random, stored only as SHA-256 hashes in PostgreSQL, rotated on use and checked for reuse.
|
|
- The browser receives the refresh token only as a `HttpOnly`, `Secure`, `SameSite=Strict` cookie.
|
|
- Cookie-backed refresh and logout reject explicit cross-site browser requests
|
|
through `Origin` and `Sec-Fetch-Site` validation. Non-browser API clients
|
|
without provenance headers still require a valid refresh cookie and the
|
|
normal rate limit.
|
|
- Login and refresh endpoints are rate-limited per forwarded client IP (5 attempts/minute).
|
|
- The API uses an authenticated-by-default fallback policy; only the login and
|
|
recovery flow plus the explicit liveness/Gateway-health probes are anonymous.
|
|
- Swagger is enabled only in the Development environment.
|
|
- The unused antiforgery-token endpoint was removed. Nexus does not advertise a
|
|
token that no mutation validates; strict cookies plus the refresh/logout
|
|
origin guard form the browser boundary for those anonymous cookie calls.
|
|
|
|
### Security
|
|
|
|
- Never commit `.env`.
|
|
- Generate `JWT_KEY` from at least 32 random bytes.
|
|
- Rotate any credential that has appeared in chat before using it.
|
|
- Do not expose PostgreSQL or the API container directly.
|
|
- Keep OpenClaw behind the `IAgentRuntime` contract.
|
|
- Keep the API reachable only through the bundled web proxy or another trusted reverse proxy.
|
|
|
|
## Frontend routes (SPA)
|
|
|
|
The SPA uses history-mode routes. Registered standalone views:
|
|
|
|
| Route | View | Description |
|
|
|---|---|---|
|
|
| `/login` | LoginView | Owner login |
|
|
| `/dashboard` | FlowBoard | Live orchestration, compact task focus and Iris modal |
|
|
| `/memory` | MemoryView | Memory file browser with search |
|
|
| `/docs` | DocsView | Documentation file browser |
|
|
| `/agents` | AgentsIndexView | Agent inventory |
|
|
| `/agents/new` | AgentCreateView | Owner-only agent proposal form |
|
|
| `/agents/proposals/:proposalId` | AgentProposalDetailView | Proposal approval, provisioning and recovery state |
|
|
| `/agents/:id` | AgentDetailView | Agent detail, live bootstrap files, read-only workspace and Standing Orders |
|
|
| `/security` | SecurityView | Security status center |
|
|
| `/incidents` | IncidentsView | Incident diary |
|
|
| `/calendar` | CalendarView | OpenClaw cron lifecycle, detail and run history |
|
|
| `/projects` | ProjectsIndexView | Project portfolio and creation |
|
|
| `/projects/:id` | ProjectDetailView | Project detail with scoped tasks |
|
|
| `/tasks` | TaskBoardView | Active task board and keyset-paginated Done history |
|
|
| `/tasks/:id` | TaskDetailView | Task detail, subtasks and activity |
|
|
| `/notifications` | NotificationsView | Notification inbox |
|
|
| `/settings` | SettingsView | Profile, owner setup center, OpenClaw config and user management |
|
|
| `/runs` | RunControlView | OpenClaw tasks, sessions, approvals, cron and events |
|
|
| `/runs/:id` | RunDetailView | Durable run state, history, correlations and recovery actions |
|
|
| `/models` | ModelsView | Live OpenClaw model catalog and sanitized auth status |
|
|
| `/activity` | ActivityView | Nexus and OpenClaw event feed |
|
|
|
|
## API endpoints
|
|
|
|
### MCP Agent Data Plane
|
|
|
|
Nexus exposes an MCP endpoint at `/mcp` for agent-facing board operations.
|
|
It uses the official `ModelContextProtocol.AspNetCore` SDK with stateless
|
|
streamable HTTP transport. Tools are a thin facade over `ITaskBridgeService`;
|
|
they must not duplicate board business logic. Two additional proposal tools
|
|
use the same durable proposal service as the owner UI and cannot approve or
|
|
provision an agent.
|
|
|
|
The bridge requires a verified JWT or `X-Nexus-Api-Key`. `X-Agent-Id` is
|
|
accepted only for a service or privileged user principal as an allow-listed
|
|
actor hint; the header is not an authentication credential.
|
|
Secrets stay in server-side runtime configuration and are never embedded in
|
|
frontend code.
|
|
|
|
Registered tools:
|
|
|
|
| Tool | Purpose |
|
|
|---|---|
|
|
| `nexus_get_board` | Full task board |
|
|
| `nexus_agent_overview` | Waiting/stale workflow overview |
|
|
| `nexus_get_task` | Single task |
|
|
| `nexus_get_children` | Child tasks for a parent |
|
|
| `nexus_get_activity` | Task activity history |
|
|
| `nexus_create_task` | Create parent/standalone task |
|
|
| `nexus_create_child_task` | Create visible delegation child task |
|
|
| `nexus_update_status` | Update status using the canonical enum only |
|
|
| `nexus_append_activity` | Append checkpoint/activity |
|
|
| `nexus_handoff` | Handoff to a known agent |
|
|
| `nexus_propose_agent` | Create an approval-required proposal; never mutate OpenClaw |
|
|
| `nexus_get_agent_proposal` | Read one durable proposal and provisioning state |
|
|
|
|
The compatible `/api/bridge` HTTP facade remains available for internal
|
|
diagnostics and transition clients. New agent integrations should use MCP;
|
|
`/api/dashboard` is UI/admin surface, not an agent contract.
|
|
|
|
### Mission Control Gateway Plane
|
|
|
|
Nexus keeps the Browser -> Nexus -> OpenClaw boundary: the frontend never talks
|
|
to OpenClaw directly. Read-only Gateway status is exposed through
|
|
`GET /api/dashboard/gateway`; it reports reachability, discovered Gateway
|
|
version and the fail-fast `Integrations:OpenClaw:RequiredVersion` pin. Nexus
|
|
defaults to the verified stable `2026.7.1` contract; upgrades are an explicit
|
|
deployment decision.
|
|
|
|
The primary browser contract is the authenticated, typed
|
|
`/api/v1/openclaw/*` facade. It uses the Gateway protocol-v4 WebSocket connector,
|
|
reports missing methods separately from missing scopes, and returns explicit
|
|
recovery state instead of converting failures to plausible empty data.
|
|
|
|
| Method | Path | Purpose |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/openclaw/setup` | Owner-only state of the single persisted `primary` connection profile |
|
|
| `POST` | `/api/v1/openclaw/setup/discover` | Discover only bounded, known Gateway candidates |
|
|
| `POST` | `/api/v1/openclaw/setup/probe` | Validate endpoint, transport, version and client compatibility |
|
|
| `POST` | `/api/v1/openclaw/setup/attach` | Start a read-only attachment with an in-memory bootstrap credential |
|
|
| `POST` | `/api/v1/openclaw/setup/verify` | Re-check pairing, scopes and capability state |
|
|
| `POST` | `/api/v1/openclaw/setup/adopt` | Capture live inventory and persist adoption/capability metadata without copying runtime data |
|
|
| `POST` | `/api/v1/openclaw/setup/management` | Deliberately request the required management scope upgrade |
|
|
| `DELETE` | `/api/v1/openclaw/setup/connection` | Confirmed detach of profile, bound device token and active socket |
|
|
| `POST/GET` | `/api/v1/openclaw/setup/wizard/*` | Render the official OpenClaw `wizard.*` setup flow after management authorization |
|
|
| `GET` | `/api/v1/openclaw/overview` | Connection, capabilities and all core runtime collections |
|
|
| `GET` | `/api/v1/openclaw/tasks` | Runtime task ledger |
|
|
| `POST` | `/api/v1/openclaw/tasks/{id}/cancel` | Owner-only task cancellation |
|
|
| `GET` | `/api/v1/openclaw/sessions` | Runtime sessions |
|
|
| `POST` | `/api/v1/openclaw/sessions/abort` | Owner-only session abort |
|
|
| `POST` | `/api/v1/openclaw/sessions/model` | Owner-only session model patch |
|
|
| `GET/POST` | `/api/v1/openclaw/cron` | Paginated runtime schedules and owner-only creation |
|
|
| `GET/PATCH/DELETE` | `/api/v1/openclaw/cron/{id}` | Owner-only detail and hash-guarded mutation |
|
|
| `GET` | `/api/v1/openclaw/cron/{id}/runs` | Paginated authoritative OpenClaw run history |
|
|
| `POST` | `/api/v1/openclaw/cron/{id}/run` | Queue an owner-only force run and correlate its returned run id |
|
|
| `GET` | `/api/v1/openclaw/approvals` | Pending runtime approvals |
|
|
| `POST` | `/api/v1/openclaw/approvals/{id}/resolve` | Owner-only approval decision |
|
|
| `GET` | `/api/v1/openclaw/activity` | Normalized Gateway event buffer |
|
|
| `GET` | `/api/v1/openclaw/models` | Provider-safe live model catalog |
|
|
| `GET` | `/api/v1/openclaw/models/auth-status` | Sanitized `models.authStatus` projection |
|
|
| `GET` | `/api/v1/openclaw/agents` | Runtime agents |
|
|
| `GET` | `/api/v1/openclaw/agents/create-options` | Server-derived workspace, model and production-gate options |
|
|
| `GET/POST` | `/api/v1/openclaw/agent-proposals` | Owner proposal list and manual proposal creation |
|
|
| `GET` | `/api/v1/openclaw/agent-proposals/{id}` | Proposal, approval and provisioning state |
|
|
| `POST` | `/api/v1/openclaw/agent-proposals/{id}/approve` | Owner approval and durable provisioning queue |
|
|
| `POST` | `/api/v1/openclaw/agent-proposals/{id}/reject` | Owner rejection with optimistic revision |
|
|
| `POST` | `/api/v1/openclaw/agent-proposals/{id}/retry` | Explicit recovery after failed or uncertain provisioning |
|
|
| `GET/PUT` | `/api/v1/openclaw/agents/{id}/files/*` | Live bootstrap-file list, read and hash-guarded write |
|
|
| `GET` | `/api/v1/openclaw/agents/{id}/workspace*` | Read-only arbitrary workspace browsing |
|
|
| `GET/PATCH` | `/api/v1/openclaw/config*` | Schema lookup, redacted snapshot and hash-guarded patch |
|
|
| `GET` | `/api/v1/openclaw/events` | Authenticated SSE projection with cursor replay and gap signals |
|
|
| `GET` | `/api/v1/openclaw/runs` | Durable run collection and correlation filters |
|
|
| `POST` | `/api/v1/openclaw/runs` | Owner-only durable dispatch |
|
|
| `GET` | `/api/v1/openclaw/runs/{id}` | Durable run state |
|
|
| `GET` | `/api/v1/openclaw/runs/{id}/history` | Nexus transition history plus redacted Gateway history when available |
|
|
| `POST` | `/api/v1/openclaw/runs/{id}/stop` | Owner-only exact-run stop |
|
|
| `POST` | `/api/v1/openclaw/runs/{id}/retry` | Owner-only correlated retry as a new run |
|
|
| `POST` | `/api/v1/openclaw/runs/{id}/resume` | Explicitly reports unsupported until OpenClaw exposes a same-run resume contract |
|
|
|
|
The compatibility OpenClaw event stream projects connection, run, session,
|
|
tool, approval, artifact and other Gateway events from the bounded connector
|
|
buffer. It accepts `Last-Event-ID`, emits heartbeat and replay-gap events and
|
|
redacts projected payloads. It remains a backend adapter during migration; the
|
|
frontend does not consume raw or projected OpenClaw payloads directly.
|
|
|
|
The OpenClaw stream above remains the sanitized Runtime projection. Nexus-owned
|
|
workflow changes additionally use `GET /api/v1/events?afterSequence=`. This
|
|
authenticated stream replays the PostgreSQL outbox by global sequence and
|
|
emits content-minimized task, project, proposal, run, activity and notification
|
|
deltas. A cursor older than the retained range returns `resync_required`;
|
|
clients then refresh only affected Query domains. The frontend never consumes
|
|
raw OpenClaw event payloads.
|
|
|
|
### Agent proposal and provisioning boundary
|
|
|
|
Manual creation and Iris both create the same durable proposal:
|
|
|
|
```text
|
|
local form draft -> awaiting_approval -> provisioning
|
|
-> ready | partial | failed | in_doubt
|
|
-> rejected
|
|
```
|
|
|
|
Iris has only `nexus_propose_agent` and `nexus_get_agent_proposal`; neither can
|
|
approve or mutate OpenClaw. After explicit owner approval, the worker rechecks
|
|
local management consent, the official external Client ID, endpoint/TLS trust,
|
|
advertised capability, `operator.admin`, proposal revision and idempotency. It
|
|
derives the workspace from server-side OpenClaw configuration, calls
|
|
`agents.create` at most once, reads the inventory back and only then writes and
|
|
verifies approved standard files. A timeout after possible dispatch becomes
|
|
`in_doubt`; a later retry first reconciles `agents.list`. Post-create file
|
|
failure becomes `partial` and never triggers an automatic agent deletion.
|
|
|
|
Production provisioning remains disabled while the pinned OpenClaw version
|
|
lacks an officially supported external Nexus or generic operator identity.
|
|
|
|
Durable runs are stored in PostgreSQL before dispatch together with their
|
|
transition history. They correlate OpenClaw run/session ids with optional
|
|
Nexus task and project ids, actor, correlation id and trace context. Start,
|
|
stop and retry are implemented. Same-run resume is deliberately disabled
|
|
because the pinned Gateway contract does not currently advertise such an RPC.
|
|
|
|
Nexus does not impersonate OpenClaw's reserved `gateway-client/backend`
|
|
identity. Production attachment remains blocked until the pinned OpenClaw
|
|
release officially supports the external `nexus` client id or another approved
|
|
generic external-operator identity. Once that contract exists, remote or
|
|
container-to-host operation uses Nexus' persisted Ed25519 identity and signed
|
|
challenge response. The exact `PAIRING_REQUIRED` request id is surfaced to the
|
|
owner; a resulting device token stays bound server-side to the normalized
|
|
endpoint, TLS fingerprint and role. The Compose volume
|
|
`nexus-openclaw-device` keeps identity state stable across API restarts and
|
|
must be protected as credential material.
|
|
See [OpenClaw Gateway connection](docs/OPENCLAW_GATEWAY_CONNECTION.md).
|
|
|
|
Every typed OpenClaw mutation carries a Nexus invocation context with actor,
|
|
correlation id, W3C `traceparent`, and idempotency key. The PostgreSQL claim
|
|
store keeps only metadata and hashed idempotency keys. Because the current
|
|
OpenClaw schemas for `tasks.cancel`, `sessions.abort`, `sessions.patch`,
|
|
`cron.run`, and `approval.resolve` are closed and do not declare an
|
|
`idempotencyKey`, Nexus deduplicates these calls locally instead of sending an
|
|
undocumented field. Schema-confirmed methods such as `chat.send` can opt in to
|
|
wire-level `idempotencyKey` propagation. Active claims and terminal outcomes
|
|
are stored transactionally in PostgreSQL `OperationClaims`; any existing JSONL
|
|
file is treated as an immutable legacy archive and is neither read nor
|
|
appended by the registered store.
|
|
|
|
Agent activity shown as "Thinking" is redacted before display. Lines containing
|
|
token, password, bearer, authorization, API key or secret markers are replaced
|
|
with a redaction marker. Persisted audit-worthy events should be written as
|
|
short Activity entries, not raw session transcripts.
|
|
|
|
Dashboard and agent telemetry no longer invent progress, elapsed time, next
|
|
steps, cost or synthetic “Thinking” items. Progress is shown only when a Nexus
|
|
task reports it, token totals only when a Gateway session reports them, and
|
|
unreported values are rendered as unknown. Cost remains unknown until the
|
|
runtime supplies authoritative cost data.
|
|
|
|
Nexus activity changes arrive as content-minimized domain events and invalidate
|
|
only the affected Query keys. Gateway session history remains read-only
|
|
fallback data: it is fetched on demand, redacted before display and not
|
|
persisted as a long-term raw transcript. Agent "Now" and "Today" summaries are
|
|
deterministic derivations from redacted Nexus activity plus redacted Gateway
|
|
history; Nexus does not call an LLM to summarize this feed.
|
|
|
|
Config writes and approval actions are owner-only. Agent bootstrap-file writes
|
|
require `expectedHash` and `Idempotency-Key`, re-read before the write, use
|
|
OpenClaw's `agents.files.set`, and verify the stored result afterward. Nexus
|
|
reports only “saved and read back”; it does not claim an unconfirmed runtime
|
|
hot reload. Arbitrary workspace files remain read-only. OpenClaw configuration
|
|
patches use the live schema, `baseHash`, a visible diff and explicit
|
|
`replacePaths`; secret values are never projected to the browser.
|
|
|
|
### Backend Bridge (Agent-zu-Backend, NICHT Frontend)
|
|
|
|
Der `/api/bridge/` Pfad ist ein strukturierter MCP-artiger Kommando-Adapter für die
|
|
Agent-zu-Backend-Kommunikation. Kein Frontend-Code ruft diese Endpunkte auf.
|
|
|
|
Auth: verifiziertes JWT oder `X-Nexus-Api-Key`, rate-limited (30/min).
|
|
`X-Agent-Id` ist für Service- oder privilegierte User-Principals nur ein
|
|
allow-gelisteter Actor-Hinweis und niemals selbst ein Credential.
|
|
|
|
| Methode | Pfad | Kommando | Beschreibung |
|
|
|---|---|---|---|
|
|
| `GET` | `/api/bridge/health` | — | Bridge-Health-Check |
|
|
| `POST` | `/api/bridge/tasks` | `create_task` | Neue Top-Level-Task erstellen |
|
|
| `POST` | `/api/bridge/tasks/{id}/children` | `create_child_task` | Child-Task unter Parent erstellen |
|
|
| `PATCH` | `/api/bridge/tasks/{id}/status` | `update_status` | Task-Status ändern |
|
|
| `POST` | `/api/bridge/tasks/{id}/activity` | `append_activity` | Aktivitätseintrag anhängen |
|
|
| `POST` | `/api/bridge/tasks/{id}/handoff` | `handoff` | Task an anderen Agent übergeben |
|
|
| `GET` | `/api/bridge/board` | `get_board` | Vollständiges Task-Board |
|
|
| `GET` | `/api/bridge/tasks/{id}` | `get_task` | Einzelne Task abrufen |
|
|
| `GET` | `/api/bridge/tasks/{id}/children` | `get_children` | Child-Tasks abrufen |
|
|
| `GET` | `/api/bridge/tasks/{id}/activity` | `get_activity` | Task-Aktivität abrufen |
|
|
| `GET` | `/api/bridge/agent-overview` | `get_agent_overview` | Agent-Workflow-Übersicht |
|
|
|
|
Response-Format (TaskBridgeCommandResponse<T>):
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"command": "create_task",
|
|
"data": { ... },
|
|
"error": null,
|
|
"timestamp": "2026-06-22T15:30:00.000Z"
|
|
}
|
|
```
|
|
|
|
### Health & Auth (public or rate-limited)
|
|
|
|
| Method | Path | Auth | Description |
|
|
|---|---|---|---|
|
|
| `GET` | `/health/live` | No | Process liveness only; no dependency probe |
|
|
| `GET` | `/health/ready` | No | `200` only when Nexus can serve through PostgreSQL; otherwise `503` |
|
|
| `GET` | `/health` | No | Full diagnostic projection for PostgreSQL and OpenClaw runtime; may return `Degraded` with HTTP 200 so the UI remains available for recovery |
|
|
| `POST` | `/api/v1/auth/login` | No (rate-limited) | Login with email/password |
|
|
| `POST` | `/api/v1/auth/refresh` | No (rate-limited) | Refresh access token |
|
|
| `POST` | `/api/v1/auth/logout` | No | Clear refresh token |
|
|
| `GET` | `/api/v1/auth/me` | Yes | Current user info |
|
|
| `PATCH` | `/api/v1/auth/profile` | Yes | Update display name |
|
|
| `POST` | `/api/v1/auth/change-password` | Yes | Change password (min 10 chars) |
|
|
|
|
Ordinary API failures use `application/problem+json` with a stable `code`, HTTP
|
|
`status`, `title`, `detail` and `traceId`. Conflict revisions, operation IDs and
|
|
retry delays are included only when applicable. The generated OpenAPI contract
|
|
is the frontend source for these fields; mutations are never automatically
|
|
retried. Durable operation endpoints retain their typed operation envelope for
|
|
states such as `partial`, `failed` and `in_doubt`; those states must remain
|
|
inspectable and are not collapsed into a transient HTTP exception.
|
|
|
|
### Operations
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/operations/snapshot` | Transitional aggregate snapshot for compatibility views |
|
|
|
|
New views must use the typed domain endpoints and shared Query keys instead of
|
|
expanding the operations snapshot. The endpoint remains a backend
|
|
compatibility surface, but the old frontend operations/task stores and
|
|
duplicate live-sync files have been removed.
|
|
|
|
### Parent/Child task flow
|
|
|
|
The Task Board now models OpenClaw delegation as a visible parent/child flow:
|
|
- Iris keeps the parent task `In progress` while delegated work is running.
|
|
- Delegated agent work is represented as visible child tasks linked via `parentTaskId`.
|
|
- Child tasks use the normal visible states (`Backlog`, `In progress`, `Review`, `Blocked`, `Done`) instead of a separate hidden delegation lane.
|
|
- Agent progress hints on parent tasks derive from recent activity and child-task status summaries.
|
|
- Full workflow documentation: [`docs/openclaw-task-board-flow.md`](docs/openclaw-task-board-flow.md)
|
|
|
|
The initial board request projects every non-Done task and the newest 50 Done
|
|
tasks without entity tracking. Child counts and latest activity are correlated
|
|
inside the projected SQL; the initial path uses at most three statements.
|
|
Further Done pages use an opaque `(UpdatedAt, Id)` keyset cursor and omit the
|
|
active-task query. Task mutations and outbox events reconcile only
|
|
`/api/v1/tasks/{id}/board-card`; a full board reload is reserved for failed
|
|
delta recovery or an explicit stream resync. The supporting PostgreSQL indexes
|
|
are created by
|
|
`20260730224500_AddAgentProvisioningAndBoardIndexes`.
|
|
|
|
These structural properties do not prove the release performance budgets.
|
|
The 1,000-task/10,000-activity k6 result, SQL plans, statement-count trace and
|
|
browser navigation-to-visible p95 remain separate acceptance evidence; see
|
|
[QA automation](docs/QA_AUTOMATION.md).
|
|
|
|
### Projects
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/projects` | List all projects |
|
|
| `POST` | `/api/v1/projects` | Create project |
|
|
| `GET` | `/api/v1/projects/{id}` | Get project detail |
|
|
| `GET` | `/api/v1/projects/{id}/tasks` | Get only tasks scoped to the project |
|
|
| `PATCH` | `/api/v1/projects/{id}` | Update project (name, description, status) |
|
|
| `DELETE` | `/api/v1/projects/{id}` | Delete or archive project (archives if has tasks) |
|
|
|
|
### Tasks
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/tasks` | List all tasks |
|
|
| `GET` | `/api/v1/tasks/board` | All active cards plus keyset-paginated Done cards |
|
|
| `GET` | `/api/v1/tasks/{id}/board-card` | One compact card for live delta reconciliation |
|
|
| `POST` | `/api/v1/tasks` | Create task |
|
|
| `GET` | `/api/v1/tasks/pending-approval` | Owner-only pending approvals |
|
|
| `PATCH` | `/api/v1/tasks/{id}` | Update task (title, priority, projectId) |
|
|
| `PATCH` | `/api/v1/tasks/{id}/state` | Update task state |
|
|
| `POST` | `/api/v1/tasks/{id}/approve` | Owner-only approve task (in-progress -> done) |
|
|
| `POST` | `/api/v1/tasks/{id}/reject` | Owner-only reject task (in-progress -> backlog) |
|
|
| `DELETE` | `/api/v1/tasks/{id}` | Delete task (only done/backlog states) |
|
|
|
|
### Agents
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/agents` | List all agents |
|
|
| `GET` | `/api/v1/agents/{id}` | Agent detail (with sub-agents, identity) |
|
|
| `GET` | `/api/v1/agents/{id}/activity` | Agent-specific activity (last 50) |
|
|
| `GET` | `/api/v1/agents/{id}/summary` | Redacted deterministic Now/Today summary |
|
|
| `POST` | `/api/v1/agents/{id}/command` | Send command to agent |
|
|
| `GET` | `/api/v1/agents/{id}/config` | Transitional owner-only adapter to the live OpenClaw file list |
|
|
| `GET` | `/api/v1/agents/{id}/config/{fileName}` | Transitional owner-only adapter to live file content |
|
|
| `PUT` | `/api/v1/agents/{id}/config/{fileName}` | Transitional owner-only adapter to verified OpenClaw file writes |
|
|
|
|
New clients use the `/api/v1/openclaw/agents/{id}/files` and
|
|
`/api/v1/openclaw/agents/{id}/workspace` contracts documented above.
|
|
|
|
### Memory & Docs
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/memory` | List memory files (daily + MEMORY.md) |
|
|
| `GET` | `/api/v1/memory/search?q=` | Full-text search in memory files |
|
|
| `GET` | `/api/v1/memory/{name}` | Get memory file content |
|
|
| `GET` | `/api/v1/docs` | List documentation files by category |
|
|
| `GET` | `/api/v1/docs/{**path}` | Get doc file content (catch-all) |
|
|
|
|
### Activity & Team
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/activity` | Paginated activity feed (supports `type`, `sort`, `page`, `pageSize`) |
|
|
| `GET` | `/api/v1/routing` | Model routing status |
|
|
| `GET` | `/api/v1/team` | Team org map with identity excerpts |
|
|
| `GET` | `/api/v1/incidents` | List incident diary entries |
|
|
| `GET` | `/api/v1/incidents/{name}` | Get incident detail |
|
|
| `GET` | `/api/v1/security/status` | Security configuration status |
|
|
|
|
### Calendar (Scheduler)
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/calendar` | Transitional calendar projection |
|
|
| `GET` | `/api/v1/calendar/upcoming` | Transitional upcoming-job projection |
|
|
|
|
Create, edit, enable/disable, delete, immediate run and paginated history use
|
|
the typed `/api/v1/openclaw/cron` contracts. OpenClaw remains the only cron
|
|
data authority.
|
|
|
|
### Chat
|
|
|
|
| Method | Path | Auth | Description |
|
|
|---|---|---|---|
|
|
| `POST` | `/api/v1/chat` | Yes (rate-limited) | Route message through Protocol-v4 OpenClaw chat service |
|
|
|
|
### Domain events and browser telemetry
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| `GET` | `/api/v1/events?afterSequence=` | Authenticated replayable PostgreSQL domain stream |
|
|
| `POST` | `/api/v1/telemetry/browser` | Allow-listed Web Vital or browser performance metric |
|
|
|
|
`OutboxEvents` is the durable Nexus event source for migrated domains. A background worker claims
|
|
unpublished rows with a lease and `FOR UPDATE SKIP LOCKED`, publishes them to
|
|
bounded in-process subscribers, and retains at least 24 hours and 10,000
|
|
sequences. Reconnect replay is capped at 512 deltas.
|
|
|
|
Browser telemetry accepts only metric name, value, rating, route name, build
|
|
version, live mode and correlation ID. OpenTelemetry processors remove URL
|
|
queries, SQL text, exception messages/stacks and other content-bearing
|
|
attributes. Prompts, chat text, Markdown, tool arguments, secrets and
|
|
credentials are never valid telemetry.
|
|
|
|
Project and task mutations create activity records. The API applies committed EF
|
|
Core migrations after PostgreSQL becomes healthy. No destructive endpoints are
|
|
implemented on the data layer.
|
|
|
|
## State machine (tasks)
|
|
|
|
Tasks follow a simple state machine:
|
|
|
|
```
|
|
Backlog → In progress → Done
|
|
Backlog → Blocked → In progress / Done
|
|
```
|
|
|
|
- Only `In progress` or `Blocked` tasks can be approved (→ Done) or rejected (→ Backlog).
|
|
- Only `Done` or `Backlog` tasks can be deleted.
|
|
|
|
## Runtime chat and model routing
|
|
|
|
`POST /api/v1/chat` routes authenticated messages through
|
|
`IOpenClawChatService` and Protocol-v4 `chat.send`. The older parallel
|
|
OpenAI-compatible `/v1/chat/completions` path is not a Nexus runtime path.
|
|
The browser never receives a Gateway password or model-provider key.
|
|
Conversation IDs are stable per browser and Iris is the default agent target.
|
|
|
|
The configured model-routing policy routes through the OpenClaw Gateway only.
|
|
Nexus no longer defines a static active-model table. `/models`, routing status
|
|
and agent model choices are projections of the catalog and active sessions
|
|
reported by OpenClaw. OpenAI is the intended primary provider and must be
|
|
configured and proven inside OpenClaw; Nexus stores no OpenAI credential.
|
|
|
|
The Settings module reports runtime and provider state without exposing
|
|
credentials.
|
|
|
|
## CI/CD
|
|
|
|
### CI — Automatic
|
|
|
|
Every push to `main` triggers `.gitea/workflows/ci.yaml`:
|
|
- **Backend**: .NET restore → build → checked-in OpenAPI drift check → test
|
|
- **Frontend**: pnpm install → type-check → generated client drift check →
|
|
unit test → build → Playwright Chromium E2E
|
|
- **Optional integration**: environment-gated Testcontainers PostgreSQL and
|
|
Toxiproxy tests
|
|
- **Security**: Scan for hardcoded secrets in source code
|
|
|
|
CI must never break. If it does, Reviewer fixes.
|
|
|
|
### CD — Auto + Manual (CD v4)
|
|
|
|
Deployment can happen automatically or manually:
|
|
|
|
#### Auto-Deploy (after successful CI jobs on main)
|
|
|
|
- Runs as the final `Deploy Nexus` job in `.gitea/workflows/ci.yaml`
|
|
- Starts only after backend, frontend, and security jobs succeed on `main`
|
|
- Deploys the current `main` version after CI succeeds.
|
|
- This replaces `workflow_run`, which did not create deploy runs in this Gitea 1.26.3 installation.
|
|
- The deploy script reads `VERSION`; it does not mutate Git, bump versions, or create tags
|
|
|
|
#### Manual Deploy (`workflow_dispatch`)
|
|
|
|
1. DevOps triggers `Deploy Nexus Manual` in Gitea Actions
|
|
2. Workflow validates `VERSION`, builds and deploys `main`
|
|
3. Health check + smoke test verify the deployment
|
|
|
|
#### Rollback (`workflow_dispatch`)
|
|
|
|
1. DevOps triggers `Rollback to Previous Version` in Gitea Actions
|
|
2. Enters target git tag (e.g. `v0.2.49`) + confirmation `ROLLBACK`
|
|
3. Workflow checks out the tag, rebuilds with `--no-cache`, redeploys
|
|
4. Health check + smoke test verify the rollback
|
|
|
|
#### Database Backup (`workflow_dispatch`)
|
|
|
|
1. DevOps triggers `Database Backup` in Gitea Actions
|
|
2. Optionally also copies backup to a host path (`/home/projekte_bao/backups`)
|
|
3. Workflow dumps PostgreSQL via `pg_dumpall`, gzips, and uploads as a Gitea artifact
|
|
4. Artifacts are retained for 90 days (configurable)
|
|
5. Optional nightly schedule (uncomment the cron trigger in `backup.yaml`)
|
|
|
|
#### Failure Handling
|
|
|
|
When deploy or rollback fails:
|
|
- **DevOps (Architekt)** analyses the error
|
|
- **Reviewer (Code-Fixer)** fixes the problem
|
|
- **DevOps** re-deploys to verify the fix
|
|
|
|
The workflow outputs a formatted handoff message with the job URL.
|
|
|
|
Full CD documentation: [phases/deployment.md](phases/deployment.md)
|