nerve-ipc-core 0.1.1

Core IPC layer for the NERVE protocol: authentication, request lifecycle, transport-agnostic dispatch, Unix Domain Socket server, and WebSocket server.
Documentation

nerve-ipc-core

Core IPC layer for the NERVE protocol.

What is NERVE?

NERVE is a binary framing protocol for local AI daemon communication. It defines the wire format, message types, codec, and request semantics used between a browser extension, local tools, and an AI daemon.

What does nerve-ipc-core provide?

nerve-ipc-core is the runtime/core layer of NERVE. It provides:

  • Authentication — per-install token generation and persistence (~/.anvesha/token)
  • Transport servers — Unix Domain Socket (UDS) server for local tool integrations; WebSocket server for browser extension connections
  • Transport-agnostic dispatch — a single dispatch_frame() function shared by both transports, performing no I/O
  • Request lifecycle and cancellation — per-connection RequestTable tracking active and cancelled requests
  • WebSocket handshake authentication — Origin check and per-install token verification at the HTTP upgrade step

nerve-ipc-core has no knowledge of search relevance, AI reasoning, or crawling. That belongs to the layers above.

Relationship to nerve-ipc

Crate Role
nerve-ipc Wire format, codec, frame types, message schema, protocol constants
nerve-ipc-core (this crate) Authentication, request lifecycle, dispatch, UDS server, WebSocket server

nerve-ipc-core depends on nerve-ipc for all protocol types. It does not redefine any wire-format types.

Installation

[dependencies]
nerve-ipc-core = "0.1"

To also build the daemon binary:

[dependencies]
nerve-ipc-core = { version = "0.1", features = ["daemon"] }

Architecture

Browser Extension
      │
      │  NERVE frames over WebSocket (ws://127.0.0.1:9001)
      │  Sec-WebSocket-Protocol: anvesha-v1.<token>
      │  Origin: chrome-extension://<extension_id>
      ▼
┌─────────────────────────────────────────┐
│             nerve-ipc-core              │
│                                         │
│  ws_server          server              │
│  (WebSocket)        (UDS)               │
│       │               │                 │
│       └───────┬───────┘                 │
│               ▼                         │
│          dispatch_frame()               │  ← transport-agnostic
│               │                         │  ← Ping handled inline
│               │                         │  ← Cancel marks request
│               ▼                         │  ← SearchQuery → AI boundary
│         RequestTable                    │  ← per-connection, isolated
│                                         │
└─────────────────────────────────────────┘
      │
      │  (future)
      ▼
  AI Daemon
  ├── query understanding
  ├── search client (HTTPS → hosted API)
  ├── context builder
  └── inference / token streaming

Each accepted connection runs in its own OS thread with an independent RequestTable. A misbehaving client cannot affect other connections.

API Overview

config::Config

Runtime configuration: bind address, WebSocket port, extension ID for origin checking, token path, UDS socket path.

use nerve_ipc_core::config::Config;

let config = Config::default(); // 127.0.0.1:9001, ~/.anvesha/token

auth

Token generation and persistence. The token is 32 bytes of OS randomness stored as 64 hex characters.

use nerve_ipc_core::auth::{generate_token, load_or_create_token};
use std::path::Path;

let token = generate_token(); // fresh 64-char hex token
let token = load_or_create_token(Path::new("/path/to/token"))?; // load or create

dispatch::dispatch_frame

Transport-agnostic frame handler. Returns a DispatchAction that the caller translates into I/O.

use nerve_ipc_core::dispatch::{dispatch_frame, DispatchAction};
use nerve_ipc_core::request_table::RequestTable;
// (frame comes from nerve-ipc's codec::decode)

request_table::RequestTable

Per-connection in-flight request tracking with cancellation support.

use nerve_ipc_core::request_table::RequestTable;
use nerve_protocol::types::RequestId;

let mut table = RequestTable::new();
table.insert(RequestId(1));
table.cancel(RequestId(1));
assert!(table.is_cancelled(RequestId(1)));
table.remove(RequestId(1));

server::run / server::handle_connection

UDS server: binds to a path, accepts connections, spawns threads.

ws_server::run_ws / ws_server::run_ws_on_listener

WebSocket server: binds to 127.0.0.1:<port>, performs auth handshake, dispatches frames.

Protocol / Frame Concepts

One WebSocket binary message = one NERVE frame. The 20-byte NERVE frame header contains magic, version, message type, flags, request ID, and payload length. Payload is arbitrary bytes (typically JSON for message types that carry structured data).

Frame types handled by nerve-ipc-core:

Message Behaviour
Ping Echo reply with FINAL flag, same request_id
SearchQuery Registered in RequestTable → ForwardToAiDaemon (AI daemon: future)
Cancel Marks the request cancelled in RequestTable
AgentTaskStart Registers request
AgentTaskEvent No-op (future: forwarded to AI daemon)
AgentTaskDone Removes request from table
Unknown types Ignored safely

Security

nerve-ipc-core is only accessible to the browser extension and local tools:

Control Detail
Bind address Always 127.0.0.1, never 0.0.0.0
Origin check Origin: chrome-extension://<ANVESHA_EXTENSION_ID>
Token auth Per-install secret at ~/.anvesha/token (mode 0600); passed via Sec-WebSocket-Protocol: anvesha-v1.<token> — never in the URL
Payload limit payload_length validated before allocation; oversized frames rejected before any bytes are read
Error responses 403 on auth failure — does not reveal which check failed

Design Goals

  • Protocol correctness first
  • Deterministic, non-blocking dispatch
  • Connection isolation: one bad client does not crash the daemon
  • Real IPC in tests — no mocks, no fake transports
  • Clean boundary between transport and AI daemon
  • Minimal surface area

Non-Goals

  • AI reasoning, search ranking, or crawler logic
  • Async runtime
  • TLS (localhost-only)
  • Browser-specific code

Running the Daemon Binary

cargo run --features daemon

On first run:

  • Generates a random token and writes it to ~/.anvesha/token (mode 0600)
  • Starts the WebSocket server on 127.0.0.1:9001
  • Starts the UDS server on /tmp/nerve.sock

On subsequent runs the existing token is reloaded and validated.

Testing

cargo test --all-features

65 tests. No mocks — every test exercises real server code over real sockets.

WebSocket tests (25 tests)

File Coverage
ws_basic.rs Server startup, valid token auth, Origin auth, Ping roundtrip, sequential pings
ws_security.rs Wrong token → 403, missing token → 403, wrong origin → 403, missing origin → 403, correct origin wrong token → 403, oversized payload header rejected, bad magic rejected, truncated header rejected, bind addr is 127.0.0.1, oversized WebSocket message rejected
ws_connections.rs 2 concurrent clients, 3 concurrent clients, bad frame closes one connection only, Cancel isolation between connections, disconnect/reconnect
ws_protocol.rs request_id echo, FINAL/STREAM flags on Ping reply, SearchQuery connection stays open, Cancel connection stays open, AgentTask lifecycle, multiple pings with distinct IDs

UDS and unit tests (40 tests)

  • Ping round-trip (single and multiple)
  • Concurrent connections (2 and 6+ simultaneous clients)
  • Connection isolation (malformed client does not affect concurrent good client)
  • Cancel semantics (unknown, duplicate, cross-connection)
  • SearchQuery dispatch to AI boundary
  • Interleaved SearchQuery and Ping on same connection
  • Cancel of pending SearchQuery
  • Request lifecycle and cleanup
  • Malformed frames, partial frames, rapid connect/disconnect
  • RequestTable unit tests
  • read_frame unit tests
  • generate_token unit tests

Repository Structure

nerve-core/
├── src/
│   ├── main.rs           # daemon entry point — starts WS + UDS servers
│   ├── lib.rs
│   ├── config.rs         # Config struct; bind address, ports, token path
│   ├── auth.rs           # per-install token generation and persistence
│   ├── server.rs         # UDS accept loop, thread-per-connection, read_frame
│   ├── ws_server.rs      # WebSocket accept loop + auth handshake
│   ├── dispatch.rs       # transport-agnostic dispatch, AI daemon boundary
│   └── request_table.rs  # per-connection request lifecycle and cancellation
│
└── tests/
    ├── helpers/mod.rs    # shared WebSocket test helpers
    ├── ws_basic.rs       # WebSocket: startup, auth, ping
    ├── ws_security.rs    # WebSocket: auth rejection, malformed frames
    ├── ws_connections.rs # WebSocket: concurrent clients, isolation
    ├── ws_protocol.rs    # WebSocket: NERVE semantics
    ├── ping.rs / ping_roundtrip.rs
    ├── cancel.rs / cancel_edge_cases.rs / cancel_marks_requests.rs
    ├── concurrent_connections.rs
    ├── lifecycle.rs
    ├── search_roundtrip.rs / search_streaming.rs / search_cancel_mid_stream.rs
    ├── search_worker_routing.rs
    ├── agent_task_lifecycle.rs
    ├── error_handling.rs
    ├── request_table.rs
    └── socket_read_frame.rs

Dependencies

[dependencies]
nerve-ipc-core = "0.1"

# nerve-ipc provides wire format, codec, and protocol types
# (pulled in transitively via nerve-ipc-core)

Direct dependencies of nerve-ipc-core:

Dependency Purpose
nerve-ipc Wire format, codec, frame types, protocol constants
tracing Structured logging facade
tungstenite WebSocket implementation (blocking, thread-per-connection)
getrandom Cryptographically secure token generation
tracing-subscriber Log subscriber — daemon binary only (features = ["daemon"])

Status

v0.1.0 — WebSocket transport complete.

  • ✅ Multiple simultaneous connections (UDS + WebSocket)
  • ✅ Connection isolation (per-connection RequestTable)
  • ✅ Request lifecycle and cancellation
  • ✅ Clean AI daemon boundary (ForwardToAiDaemon)
  • ✅ Transport-agnostic dispatch (dispatch_frame shared by UDS and WebSocket)
  • ✅ WebSocket server on 127.0.0.1:9001
  • ✅ Origin + token authentication at the WebSocket handshake
  • ✅ Per-install token at ~/.anvesha/token (mode 0600, getrandom)
  • ✅ Oversized payload rejected before allocation
  • ⏳ AI daemon integration
  • ⏳ Browser extension

License

Licensed under either of:

at your option.

Copyright 2026 Shreyas BK