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
RequestTabletracking 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
[]
= "0.1"
To also build the daemon binary:
[]
= { = "0.1", = ["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 Config;
let 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 ;
use Path;
let token = generate_token; // fresh 64-char hex token
let token = load_or_create_token?; // load or create
dispatch::dispatch_frame
Transport-agnostic frame handler. Returns a DispatchAction that the caller translates into I/O.
use ;
use RequestTable;
// (frame comes from nerve-ipc's codec::decode)
request_table::RequestTable
Per-connection in-flight request tracking with cancellation support.
use RequestTable;
use RequestId;
let mut table = new;
table.insert;
table.cancel;
assert!;
table.remove;
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
On first run:
- Generates a random token and writes it to
~/.anvesha/token(mode0600) - 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
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
RequestTableunit testsread_frameunit testsgenerate_tokenunit 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
[]
= "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_frameshared 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(mode0600,getrandom) - ✅ Oversized payload rejected before allocation
- ⏳ AI daemon integration
- ⏳ Browser extension
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Copyright 2026 Shreyas BK