# nerve **Observation engine for autonomous agents** — sense the world, react to changes, run workflows. Nerve is a lightweight daemon that continuously observes external state through **Senses**, reacts via declarative **Reflexes**, and orchestrates multi-step **Workflows**. Built for the [Uncaged](https://github.com/uncaged) agent framework. ## Core Concepts ``` External World → Sense → Signal → Reflex → Workflow → Log ↑ ↑ "what to observe" "what to do" ``` | Concept | Metaphor | Role | |---------|----------|------| | **Sense** | 👁️ Perception | A `compute()` function that samples or derives data. Each sense has its own SQLite database. | | **Reflex** | ⚡ Reaction | Declarative trigger — interval-based, event-driven, or both. Connects senses to actions. | | **Signal** | 📡 Notification | Emitted when a sense returns non-null. Other reflexes can listen for signals. | | **Workflow** | 🔧 Action | Stateful multi-step execution with Roles (actors) and a Moderator (coordinator). | | **Log** | 📝 Record | Immutable audit trail. Queryable by senses, but **cannot** trigger reflexes (prevents feedback loops). | Three extension points, fully orthogonal — a Sense doesn't know when it runs, a Reflex doesn't know what it computes, a Workflow doesn't know why it was triggered. ## Packages | Package | Description | |---------|-------------| | [`@uncaged/nerve-core`](./packages/core) | Shared types and config parser | | [`@uncaged/nerve-daemon`](./packages/daemon) | The observation engine — kernel, sense runtime, reflex scheduler, workflow manager | | [`@uncaged/nerve-cli`](./packages/cli) | CLI tool (`nerve`) — init, start, stop, logs, query | ## Quick Start ```bash # Requirements: Node.js ≥ 22.5, pnpm pnpm add -g @uncaged/nerve-cli # Initialize a workspace mkdir my-agent && cd my-agent nerve init # Write a sense cat > senses/cpu-usage/compute.ts << 'EOF' export async function compute() { const [load] = (await import("node:os")).loadavg(); return load > 2.0 ? { load } : null; // signal only when load is high } EOF # Configure reflexes in nerve.yaml cat > nerve.yaml << 'EOF' senses: cpu-usage: group: system throttle: 10s reflexes: - kind: sense sense: cpu-usage interval: 30s EOF # Run nerve dev # foreground (development) nerve daemon start # background (production) nerve status # check health nerve logs # view logs ``` ## Configuration `nerve.yaml` declares senses, reflexes, and workflows: ```yaml senses: cpu-usage: group: system # senses in the same group share a worker process throttle: 10s # min interval between computes timeout: 30s # max compute duration gracePeriod: 5s # wait before first compute after startup reflexes: - kind: sense sense: cpu-usage interval: 30s # periodic trigger on: [disk-pressure] # also trigger on signals from other senses - kind: workflow workflow: cleanup on: [disk-pressure] # start a workflow when signal fires workflows: cleanup: concurrency: 1 overflow: drop # discard if already running code-review: concurrency: 3 overflow: queue maxQueue: 20 ``` ## Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ Kernel │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Worker │ │ Worker │ │ Worker │ (1 per │ │ │ (group A)│ │ (group B)│ │ (group C)│ group) │ │ │ sense-1 │ │ sense-3 │ │ sense-5 │ │ │ │ sense-2 │ │ sense-4 │ │ │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ └──────────────┼──────────────┘ │ │ ▼ │ │ ┌──────────────┐ │ │ │ Signal Bus │ │ │ └──────┬───────┘ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Reflex Scheduler │ │ │ └────────┬─────────┘ │ │ ▼ │ │ ┌───────────────────┐ │ │ │ Workflow Manager │──→ Log Store (SQLite) │ │ └───────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` - **Worker processes** — one per sense group, forked by the kernel. Isolated compute execution. - **Signal Bus** — in-memory pub/sub for signal distribution. - **Reflex Scheduler** — interval timers + signal subscriptions, with throttle/coalesce. - **Workflow Manager** — concurrency control (drop/queue), thread lifecycle tracking. - **Log Store** — WAL-mode SQLite via `node:sqlite`, with archival and retention policies. ## Tech Stack - **Zero native addons** — uses Node.js built-in `node:sqlite` (DatabaseSync) - **Drizzle ORM** v1.0 for sense databases - **rslib** (rspack) for building - **Biome** for formatting/linting - **Vitest** for testing - **pnpm** workspaces for monorepo management ## Development ```bash git clone https://git.shazhou.work/uncaged/nerve.git cd nerve pnpm install pnpm build pnpm -r test # run all tests ``` ## Design Documents - [RFC-001: Observation Engine](./docs/rfc-001-observation-engine.md) — Sense, Signal, Reflex model - [RFC-002: Workflow Engine](./docs/rfc-002-workflow-engine.md) — Stateful workflow execution - [Coding Conventions](./docs/coding-conventions.md) ## License MIT