This repository has been archived on 2026-06-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
xiaoju 4a43a7f3dd refactor: update all consumers to import from @uncaged/workflow
- workflow-utils, workflow-meta: import workflow types from @uncaged/workflow
- adapter-cursor, adapter-hermes: same
- cli: same
- core: remove workflow re-exports, no longer depends on @uncaged/workflow

Phase 5+6 of #320, Testing: #323
2026-05-05 11:01:08 +00:00

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 (stateful compute(state) + JSON persistence), schedules them via interval / on in nerve.yaml, and orchestrates multi-step Workflows. Built for the Uncaged agent framework.

Core Concepts

External World → Sense(state) → { state, trigger? } → (shell in worker) / Log
                                      │
                              Workflow → Log   (CLI / daemon IPC only)
                  ↑
          scheduling: interval / on (per sense in nerve.yaml)
Concept Metaphor Role
Sense 👁️ Perception Stateful compute(state) returning { state, trigger }. State lives in data/senses/<name>.json.
Schedule ⏱️ When Each sense entry sets optional interval (periodic) and on: [other senses] (run after those senses complete a compute).
Workflow 🔧 Action Stateful multi-step execution with Roles and a Moderator. Started via CLI / daemon IPC (nerve workflow trigger, transport). Not started from sense compute() results.
Log 📝 Record Immutable audit trail. Cannot schedule senses or workflows (prevents feedback loops).

Sense → shell: when trigger is non-null it must be { command: string }. The sense worker runs it with shell: true (cwd = nerve root). Use trigger: null when no command should run. To start a workflow, invoke it from that shell command (for example calling the CLI) or trigger workflows separately via IPC.

Two extension points for what to observe (+ when) vs multi-step action — scheduling is declarative config on each sense, not a separate YAML section.

Packages

Package Description
@uncaged/nerve-core Shared types, config parser, sense trigger validation (parseSenseTrigger), daemon IPC protocol
@uncaged/nerve-store Append-only log SQLite, JSONL archive, CAS blob store, workflow run rows
@uncaged/nerve-daemon Kernel, sense workers, sense scheduler, workflow manager, file watcher, IPC
@uncaged/nerve-cli CLI (nerve) — init, validate, daemon, dev, logs, sense, store, workflow

Quick Start

# 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 (see `nerve init` for the full template)
mkdir -p senses/cpu-usage/src
cat > senses/cpu-usage/src/index.ts << 'EOF'
import { loadavg } from "node:os";

type CpuState = { lastLoad: number };

export const initialState: CpuState = { lastLoad: 0 };

export async function compute(state: CpuState) {
  const [oneMin] = loadavg();
  const lastLoad = typeof oneMin === "number" && !Number.isNaN(oneMin) ? oneMin : 0;
  return { state: { lastLoad }, workflow: null };
}
EOF

# Configure scheduling on each sense in nerve.yaml
cat > nerve.yaml << 'EOF'
senses:
  cpu-usage:
    group: system
    throttle: 10s
    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 (each with optional interval / on), optional workflows (concurrency), and optional engine max_rounds. Top-level reflexes is not supported — use interval and on on each sense.

max_rounds: 100              # default moderator cap (e.g. CLI workflow trigger)

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
    grace_period: 5s       # wait before first compute after startup
    interval: 30s          # periodic trigger

  derived-example:
    group: system
    throttle: null
    timeout: 30s
    grace_period: null
    on:
      - cpu-usage          # run after cpu-usage completes a compute

workflows:
  cleanup:
    concurrency: 1
    overflow: drop         # discard if already running
  code-review:
    concurrency: 3
    overflow: queue
    max_queue: 20

Declare workflows under workflows: and start them from Sense compute() (non-null workflow) or nerve workflow trigger.

Example — Sense starts a workflow (senses/disk-pressure/src/index.ts):

export const initialState = { checked: false };

export async function compute(state: typeof initialState) {
  const full = await diskNearlyFull();
  if (!full) return { state: { ...state, checked: true }, workflow: null };
  return {
    state: { ...state, checked: true },
    workflow: {
      name: "cleanup",
      maxRounds: 10,
      prompt: "Disk partition nearly full",
      dryRun: false,
    },
  };
}

Architecture

┌────────────────────────────────────────────────────────────────────────┐
│  Kernel                                                                 │
│                                                                         │
│  ┌──────────────┐   watches nerve.yaml / senses / workflows            │
│  │ File Watcher ├──────────────────────────────────────────┐           │
│  └──────────────┘                                          │           │
│  ┌──────────────┐   CLI ↔ newline JSON (trigger-workflow, │           │
│  │ Daemon IPC   │   trigger-sense, list-senses)            │           │
│  └──────┬───────┘                                          ▼           │
│         │            ┌──────────┐   ┌──────────┐   ┌──────────┐        │
│         │            │ Worker   │   │ Worker   │   │ Worker   │ (1 per│
│         │            │ (group A)│   │ (group B)│   │ (group C)│ group) │
│         │            │ sense-1  │   │ sense-3  │   │ sense-5  │        │
│         │            │ sense-2  │   │ sense-4  │   │          │        │
│         │            └────┬─────┘   └────┬─────┘   └────┬─────┘        │
│         │                 │              │              │            │
│         │                 └──────────────┼──────────────┘            │
│         │                                ▼                            │
│         │                        ┌──────────────┐                     │
│         │                        │Sense Scheduler                     │
│         │                        │(interval + on)                     │
│         │                        └──────┬───────┘                     │
│         │                              ▼                              │
│         │                    ┌───────────────────┐                    │
│         └───────────────────►│ Workflow Manager  │──→ @uncaged/nerve-store │
│                              └───────────────────┘    (logs.db, …)   │
└────────────────────────────────────────────────────────────────────────┘
  • Worker pool — one child process per sense group; isolation between groups.
  • Sense scheduler — interval timers + on reverse-index (upstream sense → dependents), with throttle/coalesce.
  • Workflow Manager — concurrency (drop/queue), per-workflow workers, crash recovery.
  • File watcher — hot reload for config, sense modules, and workflow modules.
  • Daemon IPC — Unix domain socket; used by the CLI when the daemon is running.
  • Log / blob storage — implemented in @uncaged/nerve-store (WAL SQLite, JSONL archive, CAS blobs).

Tech Stack

  • Zero native addons — uses Node.js built-in node:sqlite (DatabaseSync) for logs / workflow persistence via @uncaged/nerve-store
  • Sense state as JSON — files under data/senses/ written by sense workers
  • rslib (rspack) for building
  • Biome for formatting/linting
  • Vitest for testing
  • pnpm workspaces for monorepo management

Development

git clone https://git.shazhou.work/uncaged/nerve.git
cd nerve
pnpm install
pnpm build
pnpm -r test     # run all tests

Design Documents

License

MIT

S
Description
Observation engine — Sense, Reflex, Workflow
Readme 5.4 MiB
Languages
TypeScript 97.2%
HTML 2%
JavaScript 0.5%
Shell 0.3%