chore: add .knowledge/ cards + knowledge.yaml
7 curated knowledge cards extracted from RFCs and docs: - architecture: core pipeline, extension points, process isolation - sense: compute behavior, Sense→Workflow, config - workflow: engine, threads, WorkflowSpec - adapter: AgentFn protocol, available adapters, extract layer - coding-conventions: functional-first, Result type, naming - monorepo: package structure, dependency rules - knowledge-layer: sync/query CLI, embedding service knowledge.yaml indexes .knowledge/**/*.md only.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# Agent Adapters (RFC-003)
|
||||
|
||||
Adapter = capability. Role = scenario. Workflows declare adapters directly via import.
|
||||
|
||||
## AgentFn Protocol
|
||||
|
||||
```ts
|
||||
type AgentFn = (prompt: string, context: WorkflowContext) => Promise<string>
|
||||
```
|
||||
|
||||
- Input: prompt + context (start frame, messages, workdir, AbortSignal)
|
||||
- Output: raw string — structured extraction is separate
|
||||
- Adapter handles tool-specific details internally
|
||||
|
||||
## Available Adapters
|
||||
|
||||
| Package | Adapter | Tool |
|
||||
|---------|---------|------|
|
||||
| `@uncaged/nerve-adapter-cursor` | `cursorAdapter` / `createCursorAdapter()` | cursor-agent CLI |
|
||||
| `@uncaged/nerve-adapter-hermes` | `hermesAdapter` / `createHermesAdapter()` | hermes chat CLI |
|
||||
|
||||
Each exports a **default instance** (sensible defaults) and a **factory** for custom config.
|
||||
|
||||
## Usage in Workflows
|
||||
|
||||
```ts
|
||||
import { cursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
||||
|
||||
// RoleSpec
|
||||
{ adapter: cursorAdapter, prompt: "...", meta: schema }
|
||||
```
|
||||
|
||||
No registry, no nerve.yaml agent config. TypeScript catches missing adapters at compile time.
|
||||
|
||||
## Extract Layer
|
||||
|
||||
Parses agent raw string → typed meta. Configured in `nerve.yaml`:
|
||||
|
||||
```yaml
|
||||
extract:
|
||||
provider: dashscope
|
||||
model: qwen-plus
|
||||
```
|
||||
|
||||
Two-level merge: global → role override. Retry once on parse failure (feeds error back to LLM), then throw `ExtractError`.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Nerve Architecture
|
||||
|
||||
Observation engine for autonomous agents — sense the world, react to changes, run workflows.
|
||||
|
||||
## Core Pipeline
|
||||
|
||||
```
|
||||
External World → Sense → Signal → Reflex → Workflow → Log
|
||||
```
|
||||
|
||||
Causality is **one-directional**. Logs are the end of the chain — they cannot trigger Reflexes (prevents feedback loops).
|
||||
|
||||
## Three Orthogonal Extension Points
|
||||
|
||||
| Extension | Question | Nature |
|
||||
|-----------|----------|--------|
|
||||
| **Sense** | What to compute | `compute()` function |
|
||||
| **Reflex** | When to compute | Declarative YAML (interval / on) |
|
||||
| **Workflow** | What to do | Roles + Moderator |
|
||||
|
||||
Each is independent. Reflex doesn't know compute internals, Sense doesn't know when it's triggered, Workflow doesn't know why it was started.
|
||||
|
||||
## Two Event Types
|
||||
|
||||
- **Signal** — from Sense compute (non-null return). Pure fact, no intent. Drives the front half (perception).
|
||||
- **Command Event** — inside Workflow Threads. Has causal chain, must be responded to. Drives the back half (action).
|
||||
|
||||
## Process Isolation
|
||||
|
||||
- One worker per Sense group (long-lived)
|
||||
- One worker per Workflow type (on-demand)
|
||||
- Workers never talk to each other
|
||||
- All user code runs in isolated Workers; kernel never loads user code directly
|
||||
@@ -0,0 +1,57 @@
|
||||
# Nerve Coding Conventions
|
||||
|
||||
## Functional-First
|
||||
|
||||
- `type` over `interface`, `function` over `class`
|
||||
- No `this`, no inheritance, composition over inheritance
|
||||
- Immutability first: `Readonly<T>`, `as const`
|
||||
|
||||
## No Optional Properties
|
||||
|
||||
Never use `?:`. Use `T | null` for nullable fields. Use discriminated unions for mutually exclusive fields.
|
||||
|
||||
```ts
|
||||
// ✅ Good
|
||||
type Config = { throttle: string | null }
|
||||
|
||||
// ❌ Bad
|
||||
type Config = { throttle?: string }
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- `Result<T, E>` for expected failures
|
||||
- `throw` only for programmer errors (bugs)
|
||||
- No try-catch for flow control
|
||||
|
||||
## Naming
|
||||
|
||||
| Type | Style |
|
||||
|------|-------|
|
||||
| Files | `kebab-case.ts` |
|
||||
| Types | `PascalCase` |
|
||||
| Functions/vars | `camelCase` |
|
||||
| Constants | `UPPER_SNAKE` |
|
||||
|
||||
## Exports
|
||||
|
||||
- Always named exports, never default
|
||||
- One module = one responsibility
|
||||
|
||||
## Async
|
||||
|
||||
- Always `async/await`, never `.then()` chains
|
||||
|
||||
## No Dynamic Import
|
||||
|
||||
Static `import` only. Exceptions: `sense-runtime.ts`, `workflow-worker.ts` (runtime module paths).
|
||||
|
||||
## Toolchain
|
||||
|
||||
pnpm + TypeScript (strict) + Biome (lint/format) + Vitest (test)
|
||||
|
||||
```bash
|
||||
pnpm run check # biome check
|
||||
pnpm test # vitest
|
||||
pnpm run build # full build
|
||||
```
|
||||
@@ -0,0 +1,38 @@
|
||||
# Knowledge Layer (RFC-003 Phase 6)
|
||||
|
||||
Local-first, repo-scoped knowledge base for project context.
|
||||
|
||||
## Files
|
||||
|
||||
- `knowledge.yaml` — repo root, defines include/exclude globs
|
||||
- `knowledge.db` — SQLite, stores chunks + embeddings
|
||||
- `.knowledge/` — curated knowledge cards (indexed by sync)
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
nerve knowledge sync # chunk files, compute embeddings, write to knowledge.db
|
||||
nerve knowledge query "query" # search by cosine similarity (or word overlap fallback)
|
||||
nerve knowledge query -g "query" # global search across all indexed repos
|
||||
nerve knowledge query --repo /path "query" # search specific repo
|
||||
```
|
||||
|
||||
## Embedding
|
||||
|
||||
- Remote service: `embed.shazhou.workers.dev` (Cloudflare Worker + KV cache)
|
||||
- Model: Dashscope text-embedding-v3 (1024 dims)
|
||||
- Cache: content-addressable (sha256 of model+text), never expires
|
||||
- Fallback: word-overlap scoring when embed service not configured
|
||||
|
||||
## Chunking
|
||||
|
||||
- Markdown: split by headings, large sections split further by paragraphs (max 24)
|
||||
- TypeScript/JS: split by function declarations, fallback to paragraphs
|
||||
- Other files: single chunk
|
||||
|
||||
## Env Config
|
||||
|
||||
```
|
||||
EMBED_SERVICE_URL=https://embed.shazhou.workers.dev
|
||||
EMBED_AUTH_TOKEN=<token>
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
# Nerve Monorepo Structure
|
||||
|
||||
```
|
||||
nerve/
|
||||
packages/
|
||||
core/ # @uncaged/nerve-core — shared types, config parser, Result, spawn-safe
|
||||
cli/ # @uncaged/nerve-cli — CLI (init, validate, dev, daemon, knowledge)
|
||||
daemon/ # @uncaged/nerve-daemon — kernel, workers, signal bus, scheduler
|
||||
store/ # @uncaged/nerve-store — append-only log, SQLite, CAS blob store
|
||||
workflow-utils/ # @uncaged/nerve-workflow-utils — role factories, extract, LLM helpers
|
||||
adapter-cursor/ # @uncaged/nerve-adapter-cursor — cursor-agent CLI adapter
|
||||
adapter-hermes/ # @uncaged/nerve-adapter-hermes — hermes chat CLI adapter
|
||||
khala/ # Khala — Sense marketplace (future)
|
||||
skills/ # nerve-managed skills
|
||||
docs/ # RFCs, conventions
|
||||
.knowledge/ # curated knowledge cards (this directory)
|
||||
```
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
- `core` is the shared layer — everyone depends on it
|
||||
- `cli` and `daemon` must NOT depend on each other
|
||||
- Adapter packages depend only on `core`
|
||||
- `workflow-utils` depends on `core` and adapter packages
|
||||
@@ -0,0 +1,29 @@
|
||||
# Sense
|
||||
|
||||
A `compute()` function that samples or derives external data. The only first-class citizen in nerve.
|
||||
|
||||
## Behavior
|
||||
|
||||
- Returns `T | null` — non-null emits a Signal, null is silent (no storage write, no signal, no downstream trigger)
|
||||
- Each Sense has its own **independent SQLite database**
|
||||
- Cross-sense reads are read-only via `peers` parameter
|
||||
- Schema defined with Drizzle ORM (`schema.ts` is single source of truth)
|
||||
|
||||
## Sense → Workflow
|
||||
|
||||
If `compute()` returns an object with `workflow: "name|maxRounds|prompt"`, the engine starts that workflow and does **not** emit a Signal. `workflow: null` or `""` means emit signal normally.
|
||||
|
||||
See `routeSenseComputeOutput` / `parseSenseWorkflowDirective` in `@uncaged/nerve-core`.
|
||||
|
||||
## Config (nerve.yaml)
|
||||
|
||||
```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)
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
# Workflow Engine
|
||||
|
||||
Stateful multi-step execution driven by Roles and a Moderator.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
- **Workflow** — definition with concurrency strategy
|
||||
- **Thread** — one execution instance, unique `runId`
|
||||
- **Role** — executes actions (has side effects). `(start, messages) → { content, meta }`
|
||||
- **Moderator** — pure routing function. `(context) → next role | END`
|
||||
|
||||
## Thread Lifecycle
|
||||
|
||||
```
|
||||
trigger → queued → started → step_complete ↺ → completed
|
||||
↓
|
||||
failed / crashed
|
||||
```
|
||||
|
||||
## Concurrency Config (nerve.yaml)
|
||||
|
||||
```yaml
|
||||
workflows:
|
||||
cleanup:
|
||||
concurrency: 1
|
||||
overflow: drop # discard if already running
|
||||
code-review:
|
||||
concurrency: 3
|
||||
overflow: queue
|
||||
max_queue: 20 # queue limit, oldest discarded
|
||||
```
|
||||
|
||||
## WorkflowSpec (RFC-003)
|
||||
|
||||
User-facing authoring format that compiles to runtime `WorkflowDefinition`:
|
||||
|
||||
```ts
|
||||
const workflow: WorkflowSpec<MyMeta> = {
|
||||
name: "develop",
|
||||
roles: {
|
||||
coder: { adapter: cursorAdapter, prompt: "...", meta: schema },
|
||||
reviewer: { adapter: hermesAdapter, prompt: reviewFn, meta: schema },
|
||||
},
|
||||
moderator,
|
||||
};
|
||||
```
|
||||
|
||||
- `adapter: AgentFn` — direct function reference, no registry
|
||||
- `prompt: string | ((start, messages) => Promise<string>)` — static or dynamic
|
||||
- `meta: Schema<T>` — extract schema for typed output
|
||||
@@ -0,0 +1,4 @@
|
||||
include:
|
||||
- ".knowledge/**/*.md"
|
||||
|
||||
exclude: []
|
||||
Reference in New Issue
Block a user