Skip to content

Architecture

On narrow screens, swipe tables horizontally to see every column.

The repository has three runtime components: a Burrow mod server, a settings contribution, and a standalone gateway package. Node Goblin remains an independent mod. Core owns the generic execution-provider contract, agent assignment, host admission, and permission decisions.

Component map

flowchart TB
  subgraph Controller[Burrow controller]
    UI[Host settings renderer] --> UIJS[ui/settings.js]
    UIJS --> API[Mod HTTP routes]
    CORE[Core processExecution contract] --> ADAPT[Process and filesystem adapter]
    API --> SVC[Controller service]
    ADAPT --> SVC
    SVC --> TLS[GatewayControllerListener]
    SVC --> SETTINGS[Mod settings and secrets]
  end
  subgraph Host[Execution host]
    NET[OutboundGatewayTransport] --> DAEMON[GatewayDaemon]
    DAEMON --> PROC[runProcess]
    DAEMON --> FILES[runFilesystem]
    DAEMON --> JOURNAL[OperationJournal]
    NET --> IDENTITY[Identity and trust files]
  end
  NET <-->|TLS JSON lines| TLS

On narrow screens, scroll the diagram horizontally to read all labels.

Manifest and activation

burrow.mod.json declares ID node-goblin, system: true, server/index.mjs, ui/settings.js, the API-target contribution, and the privileged execution-provider-v1 capability. The version appears in the manifest and gateway package/release files.

A system mod uses the same install, update, enable, disable, and uninstall lifecycle as any other mod. system: true is a trust classification: it permits the manifest to request explicitly named privileged Core capabilities that regular mods cannot request. It does not grant every privileged interface, change installation mechanics, imply that the mod is bundled, or make it non-removable. Core exposes only the declared capabilities it supports and rejects undeclared or unsupported requests.

Node Goblin requests only execution-provider-v1. That capability lets it register the controller-side process and native-filesystem execution provider. It does not grant privileged settings, diagnostics, mod-management, database, arbitrary filesystem, or arbitrary process access inside the Burrow controller. Core continues to own target admission, agent assignment, routing, and permission decisions.

activate() creates or accepts a controller service, registers a Core process controller when the declared processExecution.registerController interface exists, and registers the mod's HTTP routes. Its returned close() unregisters the controller and closes the listener.

The adapter exposes executeProcess(request, { abortSignal }) and executeNativeFilesystem(request, { abortSignal }). Core supplies correlated operation IDs and target IDs. The target ID becomes the gateway ID. Process results are translated into the shell_exec result shape; filesystem results preserve their tool result and add remote execution provenance.

The Core process adapter forwards the execution form (command or executable/args), cwd, env, timeoutMs, and supported protected-value/binding inputs. It does not forward the wire protocol's deadlineMs or maxOutputBytes options in this baseline. Direct HTTP process dispatch and direct protocol callers have a different option surface; do not assume every wire option is available through the Core adapter.

Controller service

The service reads listener settings, gateway trust records, pairing identity, and TLS secrets. It generates missing controller pairing keys and, when enabled, missing TLS material. It wraps the TLS listener with persistence and route-facing state.

Pairing approval first stores the trusted public key and gateway record, removes the pending record, and then commits the live approval. Persistence failures attempt rollback. Stored pending requests alone are informational after restart; the live nonce and pairing generation must match. Pending records have no automatic age-based expiry. The live connection has a 60-second authentication timeout by default, including time awaiting approval; a reconnect produces a new challenge and pairing code. A listed pending request therefore does not prove that its challenge is still live.

Connection and execution lifecycle

stateDiagram-v2
  [*] --> Authenticating
  Authenticating --> Pending: New signed node identity
  Pending --> Ready: Operator approval
  Authenticating --> Ready: Known identity proves possession
  Pending --> Closed: Rejected or disconnected
  Ready --> Closed: Socket closes or identity revoked
  Closed --> Authenticating: Host reconnects

On narrow screens, scroll the diagram horizontally to read all labels.

The host transport reconnects with exponential backoff from 100 ms to a maximum 5 seconds. Authentication success resets the attempt counter. A disconnected controller rejects pending dispatch promises with gateway_disconnected; that is uncertainty about execution completion, not a rollback.

The daemon validates a request, checks completed replay and active-operation state, sends accepted, runs the operation, stores terminal evidence in the journal, then sends the final response. A duplicate active ID returns operation_in_progress; a reused ID with a different digest returns operation_id_conflict.

Persistence ownership

Owner Stored data Purpose
Burrow mod settings Controller config, API targets, gateway metadata, pending pairings, TLS metadata, operation correlation Controller-side configuration and correlation
Burrow mod secrets TLS private material, pairing identity, trusted public keys, HMAC secrets Credential/identity storage supplied by the host
Gateway state directory Node identity, controller trust/pins, enrollment-consumed marker, current pairing code, completed operations Durable host identity and bounded replay
Listener memory Active connections, pending requests, bounded activity Current connection/dispatch bookkeeping

Controller operation correlation keeps up to 256 terminal records by default and does not expire unresolved records. It stores digests and terminal references, not a recoverable copy of gateway outcomes; it does not extend the gateway replay window. Listener activity is a separate, bounded in-memory view.

Core storage implementation and encryption guarantees are outside this repository. Back up the Core-owned secrets store with its required keys, not just the mod's visible settings. See configuration for names and paths.

Source references