swactor/docs/os-design
Developer 473999d1df feat: actor watching — local death notifications
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>
2026-02-13 07:25:27 +00:00
..
01-actor-watching.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00
02-cluster-registry.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00
03-node-capabilities.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00
04-command-interface.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00
05-supervision.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00
README.md feat: actor watching — local death notifications 2026-02-13 07:25:27 +00:00

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:

  • capabilities has zero dependency on swactor — it's a standalone detection library.
  • command depends on swactor (needs Runtime, stats types) but NOT on distribution.
  • distribution optionally depends on capabilities (for NodeRecord labels).
  • runtime-dashboard depends on both command and optionally distribution.

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.