Architecture
Nexus is an Agent Operating System: a control plane that turns runtime-defined agent documents into isolated, observable executions. There are five substrates, each with exactly one job.
Nexus UI (React)
create agents · edit skills · manage
memory · view board · approve · logs
│ REST + SSE
▼
┌───────────────────────────────────────────────────────────┐
│ Nexus Core (Rust, axum) │
│ │
│ orchestration engine · scheduler · agent registry · │
│ skill registry · memory service · board sync · auth · │
│ permissions · approvals · Kubernetes job launcher │
└───────┬───────────────┬───────────────┬───────────────┬────┘
│ │ │ │
(state) │ (events)│ (board) │ (isolation)│
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────────────┐
│ MongoDB │ │ NATS │ │ Plane │ │ Kubernetes │
│ │ │ JetStream │ │ (adapter) │ │ │
│ source of │ │ durable │ │ external │ │ one Job per run │
│ truth for │ │ event bus │ │ projection │ │ generic runner │
│ agents, │ │ replay, │ │ of the │ │ image becomes │
│ skills, │ │ crash │ │ internal │ │ any agent from a │
│ memory, │ │ recovery │ │ board │ │ config payload │
│ tasks,runs │ └────────────┘ └────────────┘ └────────┬─────────┘
└────────────┘ │
▼
┌──────────────────────────────┐
│ nexus-agent-runner (pod) │
│ loads skills + memory + │
│ tools, clones repo, calls │
│ the LLM, runs tools, commits,│
│ reports events back to Core │
└──────────────────────────────┘
Substrates and responsibilities
| Substrate | Owns | Notes |
|---|---|---|
| Nexus Core | Orchestration authority | The only component that mutates the source of truth. Everything routes through it. |
| MongoDB | State | Agents, skills, memory, tasks, runs, approvals, board links. Dynamic configuration store. |
| NATS JetStream | Events | Durable, replayable stream messaging. Crash recovery for autonomous agents. |
| Kubernetes | Isolation | Each agent run is an isolated Job. Resource limits, mounted secrets, scoped RBAC. |
| Plane | External projection | The internal board is authoritative; Plane is a synced view. Jira later. |
Components
| Component | Tech | Responsibility |
|---|---|---|
nexus-core | Rust, axum, tokio, tower, MongoDB driver | Admin/agent/board/skill/memory/webhook APIs, auth, approvals, orchestration. |
nexus-worker | Rust, tokio, async-nats, MongoDB | Scheduling, agent dispatch, retries, Plane sync, memory indexing, reconciliation. |
nexus-agent-runner | Rust, reqwest, tokio, duct | Generic container: load config, run skills/tools, report events. One image, many agents. |
nexus-telegram | Rust, teloxide | High-level command gateway: create goals, approve tasks, status, alerts. |
nexus-ui | Next.js 16, React 19, Tailwind v4, TanStack | Admin dashboard (separate repo): agents, skills, memory, board, runs, approvals. |
| Shared crates | Rust | nexus-domain, nexus-db, nexus-events, nexus-board(-plane), nexus-agent-runtime, nexus-ai-runtime, nexus-k8s, nexus-skills, nexus-memory, nexus-llm, nexus-git, nexus-auth, nexus-observability. |
See Repositories for the full per-project library list and Technical overview for the per-component deep dives.
Why agents are data
A traditional design encodes each agent role as a compiled type. Nexus rejects that. An agent is:
agent = MongoDB document (config) + attached skills + memory policy + permissions
When a task is assigned to an agent, Core assembles a run config and hands it to the runtime. The pod does not branch on role. This means:
- You add a new agent from the UI, with no deploy.
- The same
nexus-agent-runnerimage serves every role. - Skills, memory, and permissions are composed at dispatch time.
{
"run_id": "run_123",
"agent_id": "agent_backend_implementer",
"task_id": "task_456",
"system_prompt": "...",
"skills": ["...skill markdown..."],
"memory": ["...relevant memory..."],
"tools": ["git", "shell", "cargo"],
"permissions": { "can_commit": true, "can_merge": false }
}
Trait seams
Nexus uses traits for dynamic providers, not for fixed agent roles:
#[async_trait::async_trait]
pub trait AgentRuntime {
async fn start_run(&self, run: AgentRunRequest) -> anyhow::Result<AgentRunHandle>;
async fn cancel_run(&self, run_id: &str) -> anyhow::Result<()>;
async fn get_logs(&self, run_id: &str) -> anyhow::Result<Vec<String>>;
}
#[async_trait::async_trait]
pub trait BoardProvider {
async fn create_item(&self, item: BoardItemCreate) -> anyhow::Result<BoardItem>;
async fn update_status(&self, item_id: &str, status: BoardStatus) -> anyhow::Result<()>;
async fn add_comment(&self, item_id: &str, comment: &str) -> anyhow::Result<()>;
}
Implementations: KubernetesAgentRuntime; PlaneBoardProvider,
JiraBoardProvider, NexusInternalBoardProvider. Start with Plane — but Plane
is just an adapter.
Deployment shape
| Process | Ports | Hosting |
|---|---|---|
nexus-core | 8080 (REST + SSE), 9100 (Prometheus) | Kubernetes deployment behind ingress. |
nexus-worker | 9100 (Prometheus) | Kubernetes deployment; consumes NATS. |
nexus-telegram | — | Kubernetes deployment; long-polls or webhook. |
nexus-ui | 3000 | Next.js server behind ingress; proxies REST to nexus-core. |
| agent runs | — | Ephemeral Kubernetes Jobs in a dedicated namespace. |
| MongoDB | 27017 | Replica set (3 nodes). |
| NATS JetStream | 4222 | Clustered, with file storage for durability. |
Nexus Core's service account can create Jobs only in the agent namespace, with a tightly scoped RBAC role. See Security & permissions.
Per-component deep dives
- nexus-core — the orchestration API
- nexus-worker — background scheduling and sync
- nexus-agent-runner — the generic runtime
- nexus-telegram — the command gateway
- nexus-ui — the admin dashboard
- crates — the shared Rust crates
The Technical overview is the entry point.