# 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)
