Skip to main content

Agent run

A run is one isolated execution of an agent against a task, realized as a Kubernetes Job.

The nine steps

1. Nexus loads agent definition from MongoDB
2. Nexus loads attached skills
3. Nexus searches memory for relevant context
4. Nexus builds runtime prompt/config
5. Nexus creates Kubernetes Job
6. Agent runs in isolated pod
7. Agent reports events back to Nexus
8. Nexus updates internal board
9. Nexus syncs to Taiga

The crucial property: the pod does not need to know all agent types. It receives a config payload.

The run config payload

{
"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"],
"repositories": [
{ "url": "https://github.com/acme/backend.git", "dir": "backend", "branch": "main" },
{ "url": "https://github.com/acme/docs.git", "dir": "docs", "read_only": true }
],
"permissions": {
"can_commit": true,
"can_merge": false
}
}

The same nexus-agent-runner image becomes a planner, implementer, reviewer, tester, or devops agent depending on this payload.

Team routing (which agent gets the task)

The worker leases ready_for_agent tasks to a team of role-specialized agents rather than a single agent:

  • Dependency-aware — a task is held until every task in its depends_on is done, so an architecture task can gate the implementation tasks behind it.
  • Role match — only enabled agents whose SOUL role matches the task's role are considered.
  • Load-balanced — among matching agents, the least-loaded one (fewest queued/running runs) is chosen; agents already at NEXUS_AGENT_MAX_CONCURRENCY (default 3) are skipped. If the whole team is at capacity the task simply waits for the next tick.

This is what lets a goal fan out across a coordinated team of agents working in parallel within their limits.

Inside the runner

The nexus-agent-runner pod:

  1. Loads the run config.
  2. Loads skills and memory.
  3. Clones every configured repository side-by-side into the workspace (git CLI inside the container), then adds a "Repositories" section to the prompt listing each checkout path so the agent knows where each repo lives.
  4. Calls the LLM (via the nexus-llm provider abstraction). For API backends this is a bounded tool-calling loop: the model calls tools and reads results until it emits a final result.
  5. Runs tools (only those granted and passing their gate; the shell.exec tool enforces a hardline command firewall, and platform tools like memory.propose are proxied to Core over NATS where permissions are re-checked). Gated actions raise approvals.
  6. Commits changes / opens a PR if permitted.
  7. Streams logs and structured events back to Nexus.
  8. Returns a structured result.

Events

Runs emit durable events on NATS JetStream:

nexus.agent.run.started
nexus.agent.run.completed
nexus.agent.run.failed

Core consumes these to update agent_runs, the board, and Taiga. Because JetStream is durable, a Core restart replays missed events.

Cancellation and logs

The AgentRuntime trait exposes cancel_run and get_logs/stream_logs. The Kubernetes implementation deletes the Job and streams pod logs.

#[async_trait::async_trait]
pub trait AgentRuntime {
async fn start_run(&self, request: AgentRunRequest) -> anyhow::Result<AgentRunHandle>;
async fn cancel_run(&self, run_id: &str) -> anyhow::Result<()>;
async fn stream_logs(&self, run_id: &str) -> anyhow::Result<()>;
}