Skip to content

Architecture

Archi edited this page Oct 20, 2026 · 2 revisions

Architecture

Nautelle has two halves. The control plane is the web app, the API and the database; it can run anywhere. The runner is a small daemon on each machine that holds repositories and agents. The control plane decides and records. The runner observes and acts. Nothing else reaches into your machines.

flowchart LR
  subgraph you["People"]
    browser["Browser"]
    tg["Telegram"]
    term["Terminal<br/>Claude Code + plugin"]
  end

  subgraph cp["Control plane"]
    web["Web app<br/>Next.js"]
    api["API<br/>NestJS"]
    pg[("PostgreSQL")]
    redis[("Redis<br/>BullMQ")]
    web --> api
    api --> pg
    api --> redis
  end

  subgraph machine["Each machine with repositories"]
    runner["nautelle-runner"]
    tmux["tmux sessions"]
    wt["git worktrees"]
    claude["Claude Code"]
    gh["gh"]
    runner --> tmux & wt & claude & gh
  end

  browser --> web
  tg <--> api
  term -- "hooks · MCP" --> runner
  runner -- "outbound WebSocket<br/>events up · typed commands down" --> api
  api -. "optional" .-> ext["GitHub App · LLM providers<br/>DeepL · speech-to-text"]
Loading

The rules everything follows

  1. The control plane never touches a project's filesystem. Everything it knows came from a runner, and everything it changes goes through a runner command. Local mode is the same runner on the same machine. (ADR-0001)
  2. The runner obeys a schema, not a shell. Commands are typed and allowlisted. A runner advertises the commands it supports, and its local policy can refuse more. (ADR-0010, ADR-0023, ADR-0047)
  3. Runners dial out. A machine needs no open port. The runner opens a WebSocket to the API and authenticates with the token it got when it was paired.
  4. Observe the orchestrator; do not replace it. For the fleet, Nautelle starts the Code Sentinel orchestrator and reads what it writes. (ADR-0005)
  5. GitHub is the fleet's queue; the Board is Nautelle's. The fleet takes ready-labelled GitHub issues. Board cards are stored by Nautelle and run by dedicated card workers. (ADR-0004, ADR-0024)
  6. One database. PostgreSQL holds everything. Schedule timers are BullMQ jobs on Redis, rebuilt from PostgreSQL. (ADR-0007, ADR-0015)

How data flows in

sequenceDiagram
  participant M as Machine (tmux, git, transcripts, OTel)
  participant R as Runner
  participant A as API
  participant U as Web app
  M->>R: a change (file append, pane diff, usage batch, gh poll)
  R->>R: normalize to an event with a sequence number
  R->>A: batch over the WebSocket
  A->>A: store, update projections, check budgets and rules
  A-->>R: acknowledge the last sequence number
  A->>U: push to subscribers of the project
Loading

If the connection drops, the runner resends from the last acknowledged sequence number. The API removes duplicates.

How commands flow out

  1. A person with the right role acts in the UI, in Telegram or through the assistant.
  2. The API authorizes the action by role and project membership, writes an audit record and sends a typed command to the runner.
  3. The runner checks it against its schema and its local policy, runs it and replies with the result.
  4. The API completes the audit record.

What leaves your machines

  • Into the control plane: events, session metadata and usage. Session content, meaning prompts and replies, is sent only for projects that opt in (ADR-0021).
  • From the control plane to third parties, only if you configure them: the GitHub App, the LLM providers behind the AI assistant, DeepL for translating stored text, and a speech-to-text service for Telegram voice notes.

Components

Path What it is
apps/api NestJS 11 and Prisma 7. It serves the REST API for the UI, the /runner gateway, /live updates, webhooks and schedulers.
apps/web Next.js 16 (App Router) and React 19 on the glass-ui design system. It talks only to the API.
apps/runner A Bun daemon compiled to a single binary. It runs the collectors, the typed executor, the Claude Code adapter, the MCP server and the Token Saver filter.
packages/shared Framework-free protocol types: runner messages, the event schema and the command schema.
plugins/nautelle The Claude Code plugin: hooks, the MCP server and the track-work skill.

Deeper reading

Clone this wiki locally