diff --git a/RFC/RFC-0910-FIRST-CLASS-MESSAGING.md b/RFC/RFC-0910-FIRST-CLASS-MESSAGING.md index 6e280ad..b203c24 100644 --- a/RFC/RFC-0910-FIRST-CLASS-MESSAGING.md +++ b/RFC/RFC-0910-FIRST-CLASS-MESSAGING.md @@ -2,7 +2,7 @@ ## The Submarine's Nervous System -**Version:** 0.1.0 +**Version:** 0.2.0 **Status:** DRAFT **Layer:** L0-L1 (Transport — Internal Process Communication) **Class:** ARCHITECTURAL @@ -13,209 +13,214 @@ ## 0. ABSTRACT -This document specifies the **First-Class Messaging System** for internal process communication within Libertaria nodes. It introduces a dual-plane architecture using **Zenoh** for the data plane (content-routed pub/sub) and **NNG (nanomsg-next-generation)** for the control plane (pattern-oriented messaging). +This document specifies the **First-Class Messaging System** for internal process communication within Libertaria nodes. After architectural review, we converge on **Zenoh-only** (via zenoh-pico) as the unified messaging layer. **Key Principles:** - **No-broker sovereignty:** No Kafka, no RabbitMQ, no central daemon -- **Kenya compliance:** ~50-200KB footprint per library -- **Layered encryption:** LWF encryption (RFC-0000) overlays both transports -- **Pattern + Content:** Structural patterns (NNG) + namespace routing (Zenoh) +- **Kenya compliance:** ~50KB footprint (zenoh-pico) +- **Unified semantics:** Everything is a key-space query +- **Pattern unification:** PUB/SUB, REQ/REP, SURVEY all map to `z_get()` with different key patterns +- **Single library:** One mental model, one failure mode, one update cycle + +**Correction from v0.1.0:** Dual-plane (Zenoh + NNG) was rejected. For solo development, two libraries = two failure modes = too much complexity. Zenoh's key-space query unifies all messaging patterns. --- ## 1. MOTIVATION ### 1.1 The Gap -Libertaria L0 (UTCP, LWF) handles *inter-node* communication. But *intra-node* communication—chatter between Membrane Agent, Feed processor, Sensor Oracle, and cognitive streams—lacks a first-class solution. +Libertaria L0 (UTCP, LWF) handles *inter-node* communication. But *intra-node* communication—between Membrane Agent, Feed processor, Sensor Oracle, and cognitive streams—lacks a first-class solution. WebSockets are inappropriate (HTTP upgrade semantics where HTTP has no business). Raw TCP is too low-level. We need: - **Brokerless operation** (sovereignty requirement) -- **Pattern expressiveness** (REQ/REP, PUB/SUB, PIPELINE) +- **Unified patterns** (PUB/SUB, REQ/REP, SURVEY as one semantic) - **Content-based routing** (subscribe to `sensor/berlin/pm25/**`) - **Kenya compliance** (embedded-friendly footprint) -### 1.2 The Dual-Plane Insight -No single library satisfies all constraints. The solution is architectural: +### 1.2 The Zenoh-Only Insight +After evaluating dual-plane (Zenoh + NNG), we reject it. **Two libraries = two failure modes = too much complexity for solo development.** -| Plane | Library | Use Case | Pattern | -|-------|---------|----------|---------| -| **Data** | Zenoh | Sensor readings, Feed posts, economic signals | Content-routed pub/sub | -| **Control** | NNG | Agent negotiation, membrane stages, health checks | Pattern-oriented messaging | +The key realization: **Zenoh's key-space query unifies all messaging patterns.** -> **Law: Zenoh is the data plane. NNG is the control plane. The submarine controls its own hull.** +| Pattern | Zenoh Equivalent | +|---------|------------------| +| PUB/SUB | `z_subscribe("sensor/berlin/pm25/*")` | +| REQ/REP | `z_get("query/qvl/trust/did:xxx")` (specific key) | +| SURVEY | `z_get("health/**")` with timeout (wildcard + aggregation) | + +> **Law: Everything is a key-space query. The pattern is in the key, not the library.** + +### 1.3 Why Not NNG? +NNG's PIPELINE pattern seems attractive for Membrane processing stages, but: +- **The Pipeline is not a network problem.** It's sequential function calls within a process. +- **Stages run synchronously** in the same address space. You need `fn process_frame()`, not a socket. +- **Adding NNG adds complexity** without solving a real problem. + +> **Principle: Don't use message passing where function calls suffice.** --- -## 2. ZENOH: THE DATA PLANE +## 2. ZENOH: THE UNIFIED MESSAGING LAYER ### 2.1 What is Zenoh? -Zero-overhead pub/sub with query semantics. Rust core, Eclipse Foundation lineage. Successor to DDS ecosystem. +Zero-overhead pub/sub with query semantics. Rust core, Eclipse Foundation lineage. -### 2.2 Why Zenoh for Data? -- **Key-expression routing:** `sensor/berlin/pm25/**` is first-class -- **Query + Pub/Sub unified:** `get("sensor/berlin/pm25/latest")` AND `subscribe("sensor/berlin/pm25/*")` +### 2.2 Why Zenoh-Only? +- **Single mental model:** Everything is a key-space query +- **Pattern unification:** PUB/SUB, REQ/REP, SURVEY all via `z_get()` with different key patterns - **Peer-to-peer AND routed:** Brokerless by default, routers for scale - **Wire efficiency:** 4-8 bytes overhead per message (binary protocol) - **Storage alignment:** Built-in persistence backends (RocksDB, memory) -- **Zenoh-Pico:** C library, ~50KB footprint (Kenya-compliant) +- **zenoh-pico:** C library, ~50KB footprint (Kenya-compliant) -### 2.3 Zenoh Namespace Design -``` -libertaria/ -├── sensor/ -│ └── {geohash}/ -│ └── {metric_type}/ -│ └── {reading} → sensor/9f4w/pm25/42.3 -├── chapter/ -│ └── {chapter_id}/ -│ ├── feed/ -│ │ └── {channel}/ -│ │ └── {post_id} → chapter/berlin/feed/world/post-123 -│ └── state/ -│ └── {key} → chapter/berlin/state/governance -├── economy/ -│ └── {token}/ -│ └── {metric} → economy/scrap/velocity -└── agent/ - └── {agent_id}/ - └── {stream} → agent/janus-7/stream-2 +### 2.3 Pattern Mapping: Zenoh Replaces All + +#### PUB/SUB → `z_subscribe()` +```zig +// Subscribe to all PM2.5 sensors +var sub = try session.declare_subscriber("sensor/+/pm25", .{ + .callback = onSensorReading, +}); + +// Publisher +var pub = try session.declare_publisher("sensor/berlin/pm25"); +try pub.put("42.3"); ``` -### 2.4 Zenoh Integration Points -| Component | Subscription | Publication | -|-----------|-------------|-------------| -| Membrane Agent | `sensor/+/pm25`, `chapter/+/feed/**` | Filtered feed items | +#### REQ/REP → `z_get()` on specific key +```zig +// Requester: Query specific trust distance +var reply = try session.get("query/qvl/trust/did:libertaria:abc123"); +const trust_score = reply.payload; // "0.87" + +// Replier: Declare queryable +var queryable = try session.declare_queryable("query/qvl/trust/*", .{ + .callback = onTrustQuery, +}); +``` + +#### SURVEY → `z_get()` with wildcards + timeout +```zig +// Surveyor: Ask all health modules, aggregate responses +var replies = try session.get("health/**", .{.timeout_ms = 500}); +while (replies.next()) |reply| { + std.log.info("{s}: {s}", .{reply.key, reply.payload}); +} +// Automatically aggregates all matching responses within deadline +``` + +### 2.4 Namespace Design (LWF Service-Type Registry) +The Zenoh key-space **IS** the LWF Service-Type Registry, only readable. + +``` +$MEMBRANE/ ← L0/L1 Signals + defcon/current ← Current defense level + defcon/history ← Level history (queryable) + pattern/alert/* ← Pattern detection events + stats/throughput ← Real-time metrics + +$AGENT/ ← L1 Agent Communication + {did}/caps ← Agent capabilities + {did}/negotiate ← Negotiation channel + {did}/status ← Online/Offline/Occupied + +$SENSOR/ ← RFC-0295 Sensor Oracle + {geohash}/{metric} ← sensor/u33dc0/pm25 + {geohash}/{metric}/history ← Queryable storage + +$FEED/ ← RFC-0830 Feed Protocol + {chapter}/world/{post_id} ← World posts + {chapter}/channel/{chan_id} ← Channel posts + {chapter}/group/{group_id} ← Group messages + {chapter}/dm/{thread_id} ← E2E encrypted DMs + +$QUERY/ ← REQ/REP Replacement + qvl/trust/{did} ← Trust graph query + economy/scrap/velocity ← Economic metrics + health/{module} ← Health check responses +``` + +### 2.5 Integration Points +| Component | Subscription | Publication/Query | +|-----------|-------------|-------------------| +| Membrane Agent | `sensor/+/pm25`, `$MEMBRANE/defcon` | Filtered items to `$FEED/` | | Sensor Oracle | `sensor/+/+` (all sensors) | Normalized readings | -| Feed Relay | `chapter/+/feed/channel/*` | Relayed posts | +| Feed Relay | `$FEED/{chapter}/+` | Relayed posts | | Economic Engine | `economy/scrap/**` | Velocity updates | -| Archive Negotiator | `chapter/+/feed/**` (selective) | ANP responses | +| Health Monitor | `health/**` (SURVEY mode) | Aggregated status | --- -## 3. NNG: THE CONTROL PLANE +## 3. ARCHITECTURE -### 3.1 What is NNG? -Brokerless messaging library (nanomsg-next-generation). Pure C. Pattern-oriented. - -### 3.2 Why NNG for Control? -- **Pattern elegance:** Declare *intent* (REQ/REP, PUB/SUB, PIPELINE), not plumbing -- **Zig interop:** Native C ABI, `@cImport` trivial -- **Transport agnostic:** `ipc://`, `tcp://`, `inproc://` (zero-copy same-process) -- **Zero broker:** The pattern *is* the infrastructure -- **Lightweight:** ~200KB shared library (Kenya-compliant) -- **SURVEY pattern:** Perfect for "ask all sensors, collect within deadline" - -### 3.3 NNG Patterns Used - -#### PUB/SUB — Status Broadcasts -``` -PUBLISHER (Health Monitor) - └── PUB socket → "ipc:///tmp/libertaria/health.pub" - -SUBSCRIBERS - ├── Membrane Agent (subscribe: "membrane.") - ├── Feed Processor (subscribe: "feed.") - └── Chapter Governor (subscribe: "governor.") -``` - -#### REQ/REP — Agent Negotiation -``` -REQUESTER (Membrane Agent) - └── REQ socket → "ipc:///tmp/libertaria/governor.rep" - └── "AUTHORIZE: post-123" - -REPLIER (Chapter Governor) - └── REP socket ← "ipc:///tmp/libertaria/governor.rep" - └── "PERMIT: entropy=valid,qvl=trusted" -``` - -#### PIPELINE — Membrane Processing Stages -``` -PUSH (Entropy Checker) - └── PUSH socket → "inproc:///membrane/stage1" - -PULL → PUSH (Graph Checker) - └── PULL ← "inproc:///membrane/stage1" - └── PUSH → "inproc:///membrane/stage2" - -PULL → PUSH (Periscope AI) - └── PULL ← "inproc:///membrane/stage2" - └── PUSH → "inproc:///membrane/stage3" - -PULL (Accept/Reject) - └── PULL ← "inproc:///membrane/stage3" -``` - -#### SURVEY — Sensor Aggregation -``` -SURVEYOR (Sensor Oracle) - └── SURVEY socket → "tcp://*:7890" - └── "QUERY: pm25_24h_max" - └── Deadline: 500ms - -RESPONDENTS (Sensor Nodes) - └── RESPONDENT socket ← "tcp://sensor-oracle:7890" - └── Reply with local reading -``` - ---- - -## 4. DUAL-PLANE ARCHITECTURE - -### 4.1 Node Interior Layout +### 3.1 Node Interior Layout ``` ┌─────────────────────────────────────────────────────────┐ -│ LIBERTARIA NODE │ +│ LIBERTARIA NODE — Zenoh-Only Architecture │ │ │ -│ CONTROL PLANE (NNG) DATA PLANE (Zenoh) │ -│ ┌──────────────────┐ ┌──────────────────────┐ │ -│ │ REQ/REP │ │ sensor/berlin/pm25/* │ │ -│ │ Agent negotiation│◄──────►│ chapter/+/feed/** │ │ -│ └──────────────────┘ │ economy/scrap/** │ │ -│ └──────────────────────┘ │ -│ ┌──────────────────┐ │ -│ │ PIPELINE │ ┌──────────────────┐ │ -│ │ Membrane stages │ │ Membrane Agent │ │ -│ │ (inproc://) │ │ (subscribes to │ │ -│ └──────────────────┘ │ sensor/+/pm25) │ │ -│ └──────────────────┘ │ -│ ┌──────────────────┐ ┌──────────────────┐ │ -│ │ SURVEY │ │ Feed Processor │ │ -│ │ Health checks │ │ (subscribes to │ │ -│ └──────────────────┘ │ chapter/+/feed) │ │ -│ └──────────────────┘ │ +│ ZENOH KEY-SPACE (Unified Messaging) │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ $MEMBRANE/ │ │ +│ │ defcon/current │ │ +│ │ pattern/alert/* │ │ +│ ├──────────────────────────────────────────────────┤ │ +│ │ $SENSOR/ │ │ +│ │ {geohash}/{metric} │ │ +│ │ {geohash}/{metric}/history (queryable) │ │ +│ ├──────────────────────────────────────────────────┤ │ +│ │ $FEED/ │ │ +│ │ {chapter}/world/{post_id} │ │ +│ │ {chapter}/channel/{chan_id} │ │ +│ ├──────────────────────────────────────────────────┤ │ +│ │ $QUERY/ │ │ +│ │ qvl/trust/{did} (REQ/REP pattern) │ │ +│ │ health/** (SURVEY pattern with timeout) │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +│ COMPONENTS │ +│ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Membrane Agent │ │ Sensor Oracle │ │ +│ │ (sub+pub) │ │ (sub+pub) │ │ +│ └─────────────────┘ └─────────────────┘ │ +│ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Feed Processor │ │ Health Monitor │ │ +│ │ (sub+pub) │ │ (SURVEY queries)│ │ +│ └─────────────────┘ └─────────────────┘ │ +│ │ +│ NOTE: Membrane Pipeline = Function calls, not sockets │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ fn process_frame() │ │ +│ │ Stage 0: Triage (validate) │ │ +│ │ Stage 1: Context (build_context) │ │ +│ │ Stage 2: Decide (policy_engine) │ │ +│ │ Stage 3: Commit (state_manager) │ │ +│ └──────────────────────────────────────────────────┘ │ │ │ -│ ENCRYPTION: LWF (RFC-0000) overlays both planes │ -│ ┌────────────────────────────────────────────────────┐ │ -│ │ Zenoh payload: XChaCha20-Poly1305 encrypted │ │ -│ │ NNG payload: XChaCha20-Poly1305 encrypted │ │ -│ └────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` -### 4.2 Transport Selection Decision Tree +### 3.2 Transport Selection Decision Tree ``` Is the communication: ├── Content-defined? (sensor/berlin/pm25) │ └── Use ZENOH (key-expression routing) -├── Pattern-defined? (REQ/REP negotiation) -│ └── Use NNG (pattern semantics) ├── High-frequency + small payload? -│ ├── >10k msgs/sec → ZENOH (lower overhead) -│ └── <10k msgs/sec → Either +│ └── ZENOH (4-8 byte overhead) ├── Must survive intermittent connectivity? │ └── ZENOH (designed for this) -└── Must guarantee delivery ordering? - └── NNG PIPELINE or REQ/REP +├── Must guarantee delivery ordering? +│ └── ZENOH with reliability QoS +└── Is it internal pipeline stages? + └── Function calls, NOT message passing ``` --- -## 5. SECURITY: LWF ENCRYPTION OVERLAY +## 4. SECURITY: LWF ENCRYPTION OVERLAY -Neither Zenoh nor NNG provides native encryption that satisfies Libertaria's sovereignty requirements. Both use **LWF encryption overlay** (RFC-0000). +Zenoh does not provide native encryption satisfying Libertaria's sovereignty requirements. Use **LWF encryption overlay** (RFC-0000). -### 5.1 Zenoh + LWF +### 4.1 Zenoh + LWF ``` Zenoh payload structure: ┌─────────────────────────────────────────────────────┐ @@ -231,25 +236,13 @@ Zenoh payload structure: └─────────────────────────────────────────────────────┘ ``` -### 5.2 NNG + LWF -``` -NNG message structure: -┌─────────────────────────────────────────────────────┐ -│ NNG Protocol Header (minimal) │ -├─────────────────────────────────────────────────────┤ -│ LWF Encrypted Body │ -│ └── XChaCha20-Poly1305(SoulKey-derived nonce) │ -│ └── Contains: Application message │ -└─────────────────────────────────────────────────────┘ -``` - **Key Derivation:** Per-session keys from X3DH handshake (RFC-0140), rotated per RFC-0010 epoch. --- -## 6. IMPLEMENTATION +## 5. IMPLEMENTATION -### 6.1 Dependencies +### 5.1 Dependencies ```zig // build.zig const zenoh_pico = b.dependency("zenoh-pico", .{ @@ -257,127 +250,122 @@ const zenoh_pico = b.dependency("zenoh-pico", .{ .optimize = optimize, }); -const nng = b.dependency("nng", .{ - .target = target, - .optimize = optimize, -}); - exe.addModule("zenoh", zenoh_pico.module("zenoh")); -exe.linkLibrary(nng.artifact("nng")); ``` -### 6.2 Zig API Example: Zenoh +### 5.2 Zig API Example ```zig const zenoh = @import("zenoh"); -// Publisher -var pub = try zenoh.open(b.allocator, .{.mode = .peer}); -var publisher = try pub.declare_publisher("sensor/berlin/pm25"); -try publisher.put("42.3"); +// Initialize session +var session = try zenoh.open(allocator, .{.mode = .peer}); -// Subscriber -var sub = try zenoh.open(b.allocator, .{.mode = .peer}); -var subscriber = try sub.declare_subscriber("sensor/+/pm25", .{ +// PUB/SUB: Subscribe to sensors +var sub = try session.declare_subscriber("sensor/+/pm25", .{ .callback = onSensorReading, }); fn onSensorReading(sample: zenoh.Sample) void { - const reading = sample.payload; // "42.3" - const key = sample.key; // "sensor/berlin/pm25" - std.log.info("{s}: {s}", .{key, reading}); + std.log.info("{s}: {s}", .{sample.key, sample.payload}); } -``` -### 6.3 Zig API Example: NNG -```zig -const nng = @cImport({ - @cInclude("nng/nng.h"); -}); +// PUB/SUB: Publish reading +var pub = try session.declare_publisher("sensor/berlin/pm25"); +try pub.put("42.3"); -// REQ socket -var req: nng.nng_socket = undefined; -_ = nng.nng_req0_open(&req); -_ = nng.nng_dial(req, "ipc:///tmp/libertaria/governor.rep"); +// REQ/REP: Query trust distance +var reply = try session.get("query/qvl/trust/did:libertaria:abc123"); +std.log.info("Trust: {s}", .{reply.payload}); -const msg = "AUTHORIZE: post-123"; -_ = nng.nng_send(req, msg.ptr, msg.len, 0); - -var reply: ?*anyopaque = null; -var reply_len: usize = 0; -_ = nng.nng_recv(req, &reply, &reply_len, nng.NNG_FLAG_ALLOC); -std.log.info("Reply: {s}", .{@ptrCast([*]u8, reply)[0..reply_len]}); +// SURVEY: Health check all modules +var replies = try session.get("health/**", .{.timeout_ms = 500}); +var healthy: usize = 0; +while (replies.next()) |r| { + if (std.mem.eql(u8, r.payload, "OK")) healthy += 1; +} +std.log.info("{d}/{d} modules healthy", .{healthy, replies.total}); ``` --- -## 7. KENYA COMPLIANCE +## 6. KENYA COMPLIANCE -| Library | Footprint | Kenya Status | -|---------|-----------|--------------| -| Zenoh-Pico | ~50KB | ✅ Compliant | -| NNG | ~200KB | ✅ Compliant | -| **Total** | **~250KB** | **✅ Compliant** | - -Both libraries: -- No mandatory broker (survives network partition) -- Low memory footprint (no JVM, no heavy runtime) -- C ABI (Zig interop without FFI complexity) -- Static linkable (single binary deployment) +| Metric | Value | Status | +|--------|-------|--------| +| **Footprint** | ~50KB (zenoh-pico) | ✅ Compliant | +| **No broker** | Peer-to-peer by default | ✅ Compliant | +| **Offline tolerance** | Designed for intermittent | ✅ Compliant | +| **C ABI** | Native `@cImport` | ✅ Compliant | --- -## 8. MIGRATION PATH +## 7. MIGRATION PATH -### Phase 1: Zenoh for Sensors (Week 1) -- Deploy Zenoh-Pico on sensor nodes -- Membrane Agent subscribes to `sensor/+/pm25` -- Verify: 4-8 byte overhead per message +### Phase 1 (v0.5.0; ~15h): Zenoh-Pico Binding + First Channel +- Build zenoh-pico Zig binding +- Implement `$MEMBRANE/defcon` as first live channel +- Proof: Membrane Agent publishes defcon changes -### Phase 2: NNG for Membrane (Week 2) -- Implement PIPELINE for processing stages -- Replace ad-hoc channel communication -- Verify: Zero-copy `inproc://` where possible +### Phase 2 (v0.6.0; ~15h): Sensor + Query Namespace +- `$SENSOR/` namespace for Sensor Oracle +- `$QUERY/qvl/trust/{did}` for trust graph queries +- Pattern Detection (RFC-0115) publishes to `$MEMBRANE/pattern/alert/*` -### Phase 3: Unified Health (Week 3) -- NNG SURVEY for node health aggregation -- Zenoh pub for status broadcasts -- Unified dashboard +### Phase 3 (v0.7.0; ~10h): Feed Integration +- `$FEED/` namespace for Feed Social Protocol (RFC-0830) +- Gossip-Relay via Zenoh-Router -### Phase 4: LWF Overlay (Week 4) -- Add XChaCha20-Poly1305 encryption to both transports +### Phase 4 (v0.8.0; ~10h): LWF Encryption Overlay +- Add XChaCha20-Poly1305 encryption to Zenoh payloads - Key rotation per RFC-0010 epochs - Security audit --- -## 9. CONCLUSION +## 8. CONCLUSION -> **Zenoh is the data plane. NNG is the control plane.** +> **Zenoh-only is the right knife.** -This dual-plane architecture respects Libertaria's core constraints: -- **Sovereignty:** No broker, no external dependency -- **Kenya:** 50-200KB footprint -- **Security:** LWF encryption overlays both -- **Expressiveness:** Content routing (Zenoh) + Pattern semantics (NNG) +The dual-plane approach (Zenoh + NNG) was architecturally valid but practically wrong for solo development. Two libraries = two failure modes = too much complexity. + +The insight: **Zenoh's key-space IS the LWF Service-Type Registry, only readable.** + +| Pattern | Old Approach | Zenoh-Only | +|---------|--------------|------------| +| PUB/SUB | `z_subscribe()` | `z_subscribe()` ✓ | +| REQ/REP | NNG REQ/REP | `z_get(specific_key)` ✓ | +| SURVEY | NNG SURVEY | `z_get(wildcard, timeout)` ✓ | +| PIPELINE | NNG PIPELINE | Function calls ✓ | + +One library. One namespace. One mental model. The submarine does not merely transport messages. It *thinks* through them. --- +## APPENDIX: COMPARISON WITH v0.1.0 + +| Aspect | v0.1.0 (Dual-Plane) | v0.2.0 (Zenoh-Only) | +|--------|---------------------|---------------------| +| Libraries | 2 (Zenoh + NNG) | 1 (Zenoh) | +| Mental Models | 2 | 1 | +| Failure Modes | 2 | 1 | +| Update Cycles | 2 | 1 | +| Pipeline | NNG PIPELINE | Function calls | +| Complexity | Higher | Lower | +| Solo-Dev Fit | Poor | Excellent | + +--- + ## APPENDIX: DEPENDENCIES ### Zenoh-Pico - **URL:** https://github.com/eclipse-zenoh/zenoh-pico - **License:** EPL-2.0 OR Apache-2.0 - **Zig binding:** Direct C API via `@cImport` - -### NNG (nanomsg-next-generation) -- **URL:** https://github.com/nanomsg/nng -- **License:** MIT -- **Zig binding:** Direct C API via `@cImport` +- **Footprint:** ~50KB --- -**End of RFC-0910 v0.1.0** - -*The submarine's nervous system is waking up.* 🜏 +**End of RFC-0910 v0.2.0** +*The submarine's nervous system is unified.* 🜏