Cell Declarations
Compiler vs Runtime Boundary
Rs is a compiler. It defines the shape of a cell and enforces structural correctness at compile time. The runtime consumes cell declarations and provides lifecycle management.
Rs enforces (compile time):
- State and step_state structs are well-formed
- Migration implementations type-check against previous version
- Step state resets are generated correctly
- Public interface is introspectable via
CellMetadata - Bounded async deadlines are present on async methods
Rs declares (consumed by runtime):
budget— resource limit per cell; the runtime enforces itheartbeat— liveness interval; the runtime monitors ithealth_check()— the runtime calls it; the cell implements it- Channel connections — the runtime wires them at initialization
- Hot-swap protocol — the runtime drives step boundaries and triggers migration
Rs validates that these declarations are syntactically and type-correct. The runtime decides what to do with them.
Problem
Operating system modules need: a private state, a public interface, a resource budget, health monitoring, hot-swap capability, and state migration between versions. Rust has none of these as a first-class concept. Crates provide modularity but not lifecycle management.
Solution
The cell! macro declares a self-contained, hot-swappable OS module.
Syntax
cell!
Generated Code
The cell! macro generates:
// 1. State struct
// 2. Step state struct (with auto-reset)
// 3. Cell struct wrapping both
// 4. Cell trait implementation
// 5. Migration from v2
// 6. Public interface methods (impl block)
// 7. Metadata for introspection
Migration State Schema
The migrate from vN block generates MigrateFrom<XxxStateVN> impl. The previous version's state struct must be in scope at compile time. Convention: keep old state definitions in versioned modules alongside the cell.
// Previous version state — kept for migration
// Current cell uses v2::ConsensusState as the migration source
cell!
The old binding has the type of the previous state struct (v2::ConsensusState). The macro resolves vN to {CellName}StateVN (e.g. ConsensusStateV2) by convention. If a different type name is needed, use the full path: migrate from my_module::OldState { ... }.
Hot-Swap Protocol
cyb os is a living system. Living systems replace their components continuously without stopping — biological cells divide, differentiate, and die while the organism keeps running. cyb os cells follow the same principle: the system never reboots, modules update in place, and state migrates forward version by version.
The hot-swap protocol is a mechanical process. The spec defines how cells swap, not who or what triggers the swap. The trigger is external to the protocol — it could be a local operator, a governance decision, an automated upgrade pipeline, or the cell itself detecting that a new version is available. The protocol is the same regardless.
Step N Step N+1 Step N+2
┌──────┐ ┌──────────┐ ┌──────┐
│Cell │ drain │Cell v2 │ │Cell │
│v1 │───────>│loading + │────>│v2 │
│active│ │migration │ │active│
└──────┘ └──────────┘ └──────┘
state transfer
via MigrateFrom
- New cell version is loaded (trigger is external to the protocol)
- Current step completes normally
- At step boundary: old cell's state is serialized via
CanonicalSerialize - Serialized bytes are deserialized into the previous version's state struct (
XxxStateVN) MigrateFrom::migrate()transforms the old state struct to the new version- New cell is initialized with migrated state
- New cell starts processing next step
- Old cell binary is unloaded
Total downtime: zero. Migration happens in the gap between steps. The system never stops.
Error Types
The cell! macro generates a cell-specific error enum from the error variants used in the cell's methods. Error variants are referenced as Error::VariantName in the cell body. The macro collects all referenced variants and generates:
Inside the cell body, Error::GraphFull resolves to ConsensusError::GraphFull. The Result type inside cell methods is Result<T, ConsensusError>.
Cell-to-Cell Communication
Cells communicate through two mechanisms:
- Bounded channels — the
cell!macro can declare typed input/output channels:
cell!
Channels are wait-free (try_send/try_recv). The cell runtime connects channels between cells at initialization.
- Read-only state references — a cell can declare a dependency on another cell's public interface. The runtime provides a read-only reference at initialization. The dependent cell calls methods on this reference but cannot mutate the other cell's state.
Implementation: proc-macro, ~2000 lines.