swactor/crates/node
Zachery Aaron Shores-Chmielewski ae9ca3bcf3 feat: datastream feature cleaning
Promote pipeline-parallel-inference to a first-class app and consolidate observability on the datastream wire, decoupling the dashboard crate from `distribution`.

- apps/pipeline-parallel-inference: move the example out of `examples/` into `apps/` as its own workspace, rename binaries to `pp-worker`/`pp-orchestrator`, and strip release binaries
- cluster: add `ClusterNode`, a synchronous facade over the actorized distribution protocol (IrohDriver + per-node Runtime hosting Swim/Registry/Metadata/Directory actors with a `MembershipFanout`), replacing ad-hoc `driver.node()`/`tick()` call sites
- fleet: add per-node fleet telemetry that ships identity/resource records as `DatastreamFrame`s over the cluster transport to the orchestrator's `DatastreamSink`, folded into a `FleetView` on a 3s tick
- provision: add best-effort, opt-in SSH boot-phase telemetry (`PP_DEPLOY_KEY`) that streams rented-node boot logs onto the orchestrator's datastream as `proc.boot.<stage>.*`
- dashboard: rewire the crate dependency from `distribution` to `datastream`, drop the standalone `swactor-datastream-dashboard` binary, and rewrite `datastream_source.rs` to demux per-node frames into Overview/Distribution/Fleet views with live-node TTL filtering
- distribution: refresh dist/netmap plugin copy and README from "Kademlia routing" to gossip-directory terminology

Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-06-09 13:29:07 +04:00
..
src feat: datastream feature cleaning 2026-06-09 13:29:07 +04:00
build.rs refactor: consolidate crate functions (#50) 2026-02-24 09:12:28 +00:00
Cargo.toml feat: datastream feature cleaning 2026-06-09 13:29:07 +04:00
README.md refactor: consolidate crate functions (#50) 2026-02-24 09:12:28 +00:00

node

The node crate produces the swactor binary — the batteries-included entry point for running a swactor node. It composes the actor runtime, SWIM-based cluster membership, content-addressed datastore, data streams, an HTTP dashboard, and an optional embedded relay server into a single process.

Run swactor --help for full CLI usage.

What a Default Node Does

Identity

Every node has a persistent Ed25519 keypair stored at ~/.swactor/identity/node.key.json. This is the node's identity across restarts — deleting it makes the node appear as a new peer to the cluster. The keypair's public key doubles as the node ID (used in SWIM, peer auth, and invite codes). A deterministic human-readable name (e.g. swift-falcon) is derived from the key so you can tell nodes apart in logs and the dashboard.

Networking

The default transport is iroh (QUIC over UDP). Nodes find each other via invite codes — base58-encoded public keys exchanged out-of-band. swactor join <code> adds a peer to the allow-list and sets it as the seed node for the next startup.

Once connected, SWIM protocol handles cluster membership: protocol probes every 500ms, 600ms probe timeout (tuned for relay round-trips), 2 indirect probes, 4s suspicion window. All intervals are in ticks where 1 tick = 100ms (the main loop period).

Peer auth operates in two modes: open (no peers_file) or allow-list (peers.json). In allow-list mode, SWIM messages from unknown nodes are dropped at the transport layer. New peers can be added via swactor join or the dashboard UI, both of which hot-update the allow-list.

Relay

Nodes with a public IP auto-promote to embedded relay servers (port 3340). Candidacy is evaluated at startup: the node checks its outbound IP is non-RFC1918 and the relay port is bindable. Relay URLs are announced via SWIM gossip so other nodes discover them automatically. Nodes behind NAT use relays for indirect connectivity — this is why the probe timeout is 600ms instead of the typical 300ms.

Storage

The datastore is a content-addressed, chunked store. Default config persists to ~/.swactor/datastore/. Auth is enabled by default (ACL files in ~/.swactor/auth/). The datastore runs as a group of actors inside the runtime and is driven by the main tick loop — GC runs every 1000 ticks (~100s) and dissemination every 50 ticks (~5s). A StreamManager actor bridges iroh QUIC streams into the datastore for bulk data transfer between nodes.

Disable with --no-datastore. Use --storage-path to change location, or omit it from config for in-memory only.

Observability

An HTTP dashboard serves on port 9090. It exposes runtime stats, cluster membership state, tracing output, and a peer management UI (add/remove peers). The dashboard receives a snapshot of the distribution layer every tick.

State & Lifecycle

All persistent state lives under ~/.swactor/. Deleting this directory fully resets the node (new identity, empty cluster, empty datastore). The node shuts down cleanly on SIGINT (Ctrl+C). swactor install copies the binary to ~/.swactor/bin/swactor and registers it as a system service (systemd user unit, OpenRC/sysvinit init script, or @reboot crontab depending on the host).

Exposed Ports

Port Service Configurable via
9090 HTTP dashboard --dashboard-port
3340 Embedded relay (if eligible) --relay-port

Data Directory (~/.swactor/)

~/.swactor/
├── node.toml          # Node configuration
├── peers.json         # Peer allow-list
├── identity/
│   └── node.key.json  # Persistent Ed25519 keypair
├── datastore/         # Content-addressed chunk storage
├── auth/              # ACL and owner key files
└── bin/
    └── swactor        # Installed binary (after `swactor install`)

Architecture

CLI Args + TOML Config
        │
        ▼
  Config Resolution (CLI > config > defaults)
        │
        ▼
  Identity (Ed25519 Keypair) ──► Node Name
        │
        ▼
  ┌─────────────────────────────────────────────┐
  │              Actor Runtime                   │
  │  (2 threads, StdExtension, stats hook)       │
  │                                              │
  │  ┌──────────────┐  ┌──────────────────────┐  │
  │  │ StreamManager │  │   Datastore Group    │  │
  │  │   (actor)     │◄─┤ (store, gateway,     │  │
  │  │               │  │  bridge actors)      │  │
  │  └──────────────┘  └──────────────────────┘  │
  └──────────────┬──────────────────────────────┘
                 │
                 ▼
  ┌──────────────────────────────────┐
  │   Distribution Driver (iroh)     │
  │  SWIM probes, gossip, relay      │
  └──────────────┬───────────────────┘
                 │
                 ▼
  ┌──────────────────────────────────┐
  │         HTTP Dashboard           │
  │  :9090 — stats, tracing, peers   │
  └──────────────────────────────────┘
                 │
                 ▼
         Main Tick Loop (100ms)
    recv → tick → streams → joins →
    heartbeats → snapshot → datastore