Add watch/unwatch API to the actor system so actors can monitor each other's liveness. When a watched actor dies (panic or stop), watchers receive an ActorExited notification via on_actor_exit(). - ExitReason enum (Stopped, Panicked, NodeDown) and ActorExited struct - ContextInner::watch()/unwatch() + Ctx typed wrappers - ActorInterface::on_actor_exit() default method (system message fallback) - WatchRegistry in worker with bidirectional tracking - Death notification dispatch as phase 5b in tick_once - Runtime-level watch for external callers - 10 behavioral tests in tests/watch_api.rs - Design documents for OS features in docs/os-design/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7 KiB
Swactor Distributed OS — Design Overview
Vision
Swactor is evolving from a local actor runtime into a distributed operating system for running long-lived daemons across heterogeneous, churning machines.
Primary use case: Wire together personal hardware today; add on-demand spot compute (vast.ai, etc.) tomorrow. Machines pop in and out of the network. The system self-heals.
Design principles:
- Churn is the norm, not the exception. Every subsystem assumes nodes can disappear at any time.
- General and flexible. Minimal assumptions about what a node looks like — feature-gate hardware-specific code.
- Layered. The core runtime stays minimal. OS features are opt-in crates. Supervision is user-space, not kernel.
- Frontend-agnostic. Operational interfaces (commands, inspection) work identically from CLI, TUI, REST, or future transports.
Current Capabilities
| OS Concept | What Swactor Has Today |
|---|---|
| Processes | Actor spawn/stop, lifecycle hooks, restartable with factory + max_restarts |
| Scheduling | Worker threads, fairness budget (64 msgs/tick), load-aware placement |
| IPC | Typed send, request/reply, per-actor VecDeque mailboxes |
| Naming | String-keyed AddressMap — node-local only |
| Fault tolerance | catch_unwind for panics, factory restart, dead actor cleanup |
| Backpressure | Per-actor mailbox capacity, DropNewest/DropOldest overflow |
| Networking | SWIM membership (Lifeguard extensions), TCP transport, bincode wire protocol |
| Directory | Kademlia DHT for ActorAddress -> NodeId resolution |
| Monitoring | WorkerStats/RuntimeStats, TUI dashboard, REST /api/*, investigate REPL |
| Distribution | Multi-node cluster, 5-node Docker test suite |
What's Missing (This Design)
| Feature | Document | Priority |
|---|---|---|
| Actor Watching | 01-actor-watching.md | Foundation for everything |
| Cluster Registry | 02-cluster-registry.md | Actors find each other across nodes |
| Node Capabilities | 03-node-capabilities.md | Heterogeneous placement |
| Command Interface | 04-command-interface.md | Operational control |
| Supervision | 05-supervision.md | Self-healing (user-space) |
Crate Structure (After This Work)
swactor/ # core runtime — no network deps
src/
actor.rs # +watch/unwatch on ContextInner, ExitReason, ActorExited
worker.rs # +WatchRegistry, death notification phase
delivery.rs # (unchanged)
runtime.rs # (unchanged)
...
crates/
capabilities/ # NEW — hardware detection + placement constraints
src/lib.rs # NodeCapabilities, CapValue, PlacementConstraint
command/ # NEW — frontend-agnostic command dispatch
src/lib.rs # CommandRouter, CommandHandler, CommandRequest/Response
src/builtins/ # Built-in command handlers
distribution/ # SWIM + Kademlia + cluster registry
src/
registry.rs # NEW — ClusterRegistry, gossip-propagated naming
node.rs # +register_name, resolve_name, capabilities
messages.rs # +WatchRequest, UnwatchRequest, ActorExitedNotify
...
runtime-dashboard/ # TUI + REST — refactored to use command crate
python/ # PyO3 bindings
simulation/ # Network simulation
wasm/ # WASM bindings
Dependency Graph
┌──────────────┐
│ capabilities │ (standalone — only serde + sysinfo)
└──────┬───────┘
│ optional
┌─────────┐ ┌──────▼────────┐
│ swactor │◄─────│ distribution │
│ (core) │ │ +registry │
└────┬────┘ └──────┬────────┘
│ │
│ ┌──────▼────────┐
└──────────►│ command │
└──────┬────────┘
│
┌──────▼────────────┐
│ runtime-dashboard │
│ (TUI + REST) │
└───────────────────┘
Key constraints:
capabilitieshas zero dependency onswactor— it's a standalone detection library.commanddepends onswactor(needsRuntime, stats types) but NOT ondistribution.distributionoptionally depends oncapabilities(forNodeRecordlabels).runtime-dashboarddepends on bothcommandand optionallydistribution.
Feature Flags
Core swactor
| Flag | Purpose |
|---|---|
getrandom (default) |
Cryptographic RNG for actor addresses |
serde |
Serialization for types |
tracing |
Structured logging |
transport |
Transport-agnostic remote messaging |
watching (new) |
Watch API on ContextInner/Ctx |
swactor-capabilities
| Flag | Purpose |
|---|---|
detect (default) |
Auto-detect CPU, RAM, hostname via sysinfo |
gpu-nvidia |
Detect NVIDIA GPU via nvidia-smi |
gpu-vulkan |
Detect GPU via Vulkan API |
distribution
| Flag | Purpose |
|---|---|
registry (new, default) |
Cluster-wide gossip-propagated naming |
capabilities (new) |
NodeCapabilities on NodeRecord |
Implementation Order
Each feature is one PR, in dependency order:
PR 1: Actor Watching (local only)
└──► PR 2: Command Interface
└──► PR 3: Cluster Registry
└──► PR 4: Node Capabilities
└──► PR 5: Remote Watching (cross-node)
└──► PR 6: Supervisor library
PR 1 — Actor Watching (local)
Adds WatchRegistry, ActorExited, ExitReason to core runtime. Testable without any distribution. Foundation for everything else.
PR 2 — Command Interface
Extracts investigate.rs into crates/command/. Adds write commands (spawn, stop, drain). Immediately useful for operations.
PR 3 — Cluster Registry
Gossip-propagated naming in crates/distribution/src/registry.rs. Actors can find each other by name across nodes.
PR 4 — Node Capabilities
crates/capabilities/ with auto-detection and placement constraints. Integrates with distribution for capability-aware placement.
PR 5 — Remote Watching
Wire protocol for cross-node watches. SWIM Dead triggers ActorExited { reason: NodeDown } for all actors on that node.
PR 6 — Supervisor Library User-space supervisor pattern. Composes watching + registry + capabilities to auto-respawn actors after churn.