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.
Files
nerve/.knowledge/sense.md
T
xiaoju 8dd82d99da refactor(core): remove WorkflowTrigger from SenseTrigger — shell only
Senses trigger shell commands only. Workflows are invoked via CLI.

SenseTrigger is now { command: string } — no discriminated union.

Closes #318

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-02 12:33:38 +00:00

2.9 KiB

Sense

A compute() function that samples or derives external data. The only first-class citizen in nerve.

Contract

Each sense module (src/index.ts) must export:

export { snapshots as table } from "./schema.ts";  // drizzle table for runtime to insert into

export async function compute(): Promise<ComputeResult<T>> { ... }  // pure, no args

Function Signature & Input Schema:

  • compute() is parameterless — no direct inputs, environment variables available
  • No database access within compute — runtime provides isolated execution context
  • Must be pure function (no side effects, no external API calls)

Return Value Contract (current engine):

  • compute(state) returns Promise<{ state: S; trigger: SenseTrigger | null }> where SenseTrigger = { command: string }.
    • trigger: null → persist state only; no shell command
    • trigger: { command } → persist state; worker runs the command with shell: true after a successful compute
  • Workflows are not started from trigger; use CLI / daemon IPC (nerve workflow trigger, etc.).

Error Handling & Serialization:

  • Exceptions caught by worker, logged as errors (state unchanged)
  • State must be JSON-serializable (persisted to data/senses/<name>.json)
  • Invalid trigger shapes fail IPC validation when the worker sends compute-result

Timeout & Scheduling Semantics:

  • Timeout priority: explicit config → AbortSignal → DEFAULT_TIMEOUT_MS (30s)
  • Enforced via Promise.race() with timeout promise
  • Grace period can trigger process.exit(1) after timeout (kills worker group)
  • Interval translation: YAML config values used directly as milliseconds in setInterval()
  • Jitter control: throttle mechanism prevents rapid-fire, single deferred trigger per throttle window

Config (nerve.yaml)

senses:
  cpu-usage:
    group: system        # senses in same group share a worker
    throttle: 10s        # min interval between computes
    timeout: 30s         # max compute duration
    grace_period: 5s     # wait before first compute
    interval: 30s        # periodic trigger (optional)
    on: [disk-pressure]  # trigger on signals from other senses (optional)

Manual Trigger Context

nerve sense trigger <name> sends IPC message to running daemon. The compute context is initialized as follows:

  • SQLite Database: Opened in read-write mode at data/senses/<name>.db
  • Migrations: All *.sql files in senses/<name>/migrations/ applied in lexicographic order
  • Environment: Inherits daemon process environment (no special secrets injection)
  • Arguments: No runtime arguments or mock inputs supported — compute() is always pure function with no parameters
  • Isolation: Runs in forked child process (worker) with full filesystem access within user permissions
  • Persistence: Runtime automatically calls db.insert(table).values(result.signal) if compute returns non-null signal