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