docs: rewrite README + add CONTRIBUTING guide
- README: update Rule signature to onion middleware, add architecture diagram, document watchers/survival/storage, link all RFCs - CONTRIBUTING: code structure, architecture, dev workflow, testing conventions, Cursor Agent usage guide, design principles
This commit is contained in:
+199
@@ -0,0 +1,199 @@
|
||||
# Contributing to Pulse
|
||||
|
||||
开发指南。
|
||||
|
||||
## 前置要求
|
||||
|
||||
- [Bun](https://bun.sh) >= 1.0(运行时 + 包管理 + 测试)
|
||||
- Git
|
||||
- [Cursor Agent CLI](https://docs.cursor.com/agent) (可选,用于 AI 辅助编码)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/oc-xiaoju/pulse.git
|
||||
cd pulse
|
||||
bun install
|
||||
```
|
||||
|
||||
## 代码结构
|
||||
|
||||
```
|
||||
pulse/
|
||||
├── packages/
|
||||
│ ├── pulse/src/ ← 核心引擎(@uncaged/pulse)
|
||||
│ │ ├── index.ts ← Rule 类型、composeRules、runPulse、rebuildSnapshot
|
||||
│ │ ├── rules.ts ← 内置 rules:clampTick、errorBackoff、adaptiveInterval、dedup
|
||||
│ │ ├── store.ts ← 存储层:events.db + vitals.db + objects/ CAS
|
||||
│ │ ├── watcher.ts ← Watcher 框架:startWatcher、wakeTick、WatcherDef
|
||||
│ │ ├── watchers/ ← P0 内置 watchers(植物神经,agent 不可改)
|
||||
│ │ │ ├── system-resource.ts CPU/内存/磁盘/swap
|
||||
│ │ │ ├── process-alive.ts 关键进程存活检测
|
||||
│ │ │ ├── network.ts DNS + HTTP 连通性
|
||||
│ │ │ ├── error-log.ts 日志关键词匹配
|
||||
│ │ │ ├── llm-health.ts LLM 双层探针(轻量 + 深度)
|
||||
│ │ │ └── index.ts
|
||||
│ │ ├── survival/ ← P0 保命层(植物神经,agent 不可改)
|
||||
│ │ │ ├── constants.ts ESSENTIAL_PROCESSES 白名单、阈值常量
|
||||
│ │ │ ├── health.ts HealthSnapshot 类型 + rebuildHealth
|
||||
│ │ │ ├── rules.ts 7 个保命 rules(洋葱最外层)
|
||||
│ │ │ ├── executors.ts 保命 executors(确定性本地命令)
|
||||
│ │ │ └── index.ts
|
||||
│ │ └── executors/ ← 业务 executors(agent 可扩展)
|
||||
│ │ ├── coding-agent.ts Coding Agent Executor
|
||||
│ │ └── index.ts
|
||||
│ │
|
||||
│ └── upulse/src/ ← CLI 工具(@uncaged/upulse)
|
||||
│ ├── cli.ts 命令路由
|
||||
│ ├── daemon.ts daemon 进程管理
|
||||
│ ├── init.ts upulse init
|
||||
│ ├── git.ts git 操作封装
|
||||
│ ├── store.ts CLI 层存储辅助
|
||||
│ ├── config.ts 配置管理
|
||||
│ └── commands/
|
||||
│ ├── daemon.ts upulse daemon start/stop
|
||||
│ ├── deploy.ts upulse deploy(staging → promote)
|
||||
│ ├── dev.ts upulse dev(热重载)
|
||||
│ ├── gc.ts upulse gc(vitals 清理)
|
||||
│ ├── init.ts upulse init
|
||||
│ ├── inspect.ts upulse inspect(查看 events/vitals)
|
||||
│ ├── list.ts upulse list(列出实例)
|
||||
│ └── tick.ts upulse tick(手动触发一次 tick)
|
||||
│
|
||||
├── biome.json ← Biome linter 配置
|
||||
├── package.json ← monorepo root
|
||||
└── bun.lock
|
||||
```
|
||||
|
||||
## 架构
|
||||
|
||||
### 核心三原语
|
||||
|
||||
```
|
||||
Collector(感知)→ Rule(认知)→ Executor(行动)
|
||||
```
|
||||
|
||||
- **Collector = Watcher**:持续采集外部状态,写 vitals
|
||||
- **Rule = 洋葱中间件**:`(prev, curr, inner) => [effects, tickMs]`
|
||||
- **Executor = Effect handler**:执行 effects 产生的动作
|
||||
|
||||
### 双层驱动
|
||||
|
||||
```
|
||||
Autonomic 层(vitals.db)
|
||||
Watchers 每 5s 采集 → 写 vitals → 唤醒判定 → wakeTick()
|
||||
↓
|
||||
Tick 层(events.db) 中断 sleep
|
||||
rebuildSnapshot → Rule Chain(洋葱)→ Executors
|
||||
└── 被 timer 或 wakeTick 唤醒
|
||||
```
|
||||
|
||||
- Tick 串行不并发(加锁)
|
||||
- wakeTick 可中断 sleep,tick 执行中的 wake 设 pendingWake flag
|
||||
|
||||
### 洋葱 Rule 模型
|
||||
|
||||
```
|
||||
[panicRollback, processWatchdog, resourceGuard, ...survivalRules, ...agentRules]
|
||||
└────────── 核心包硬编码,最外层 ──────────┘ └── agent engine/ ──┘
|
||||
```
|
||||
|
||||
最外层的保命 rules 由核心包注入,agent 看不到也改不了。
|
||||
|
||||
### 存储模型
|
||||
|
||||
一切皆事件。三个存储:
|
||||
|
||||
| 存储 | 内容 | 生命周期 |
|
||||
|---|---|---|
|
||||
| `events.db` | promote/rollback/effect/error/collect/tick | 永不压缩 |
|
||||
| `vitals.db` | 高频采样数据(系统资源/进程/网络/LLM) | 可 gc(archive + downsample) |
|
||||
| `objects/` | CAS 内容寻址存储 | 自动去重,不可变 |
|
||||
|
||||
## 开发工作流
|
||||
|
||||
### 跑测试
|
||||
|
||||
```bash
|
||||
# 核心引擎测试
|
||||
cd packages/pulse && bun test
|
||||
|
||||
# 全部测试(含 E2E)
|
||||
bun test
|
||||
```
|
||||
|
||||
### Lint & 格式化
|
||||
|
||||
```bash
|
||||
# 检查
|
||||
bun run lint
|
||||
|
||||
# 自动修复
|
||||
bun run lint:fix
|
||||
```
|
||||
|
||||
项目使用 [Biome](https://biomejs.dev/) 做 lint 和格式化。CI 会检查。
|
||||
|
||||
### 分支约定
|
||||
|
||||
```bash
|
||||
git checkout -b feat/descriptive-name # 新功能
|
||||
git checkout -b fix/descriptive-name # 修复
|
||||
git checkout -b chore/descriptive-name # 工具链/配置
|
||||
```
|
||||
|
||||
### Commit 格式
|
||||
|
||||
```
|
||||
type: short description (closes #N)
|
||||
```
|
||||
|
||||
Types: `feat:` `fix:` `docs:` `refactor:` `chore:`
|
||||
|
||||
### Issue 驱动
|
||||
|
||||
每个改动都有 GitHub Issue。先开 issue,再写代码,commit 带 `closes #N`。
|
||||
|
||||
## 关键设计原则
|
||||
|
||||
1. **Moore 机** — 不逐事件响应,只看两次快照间的 diff。Effects 由新状态决定。
|
||||
2. **保命零依赖** — 保命层不依赖 LLM、不依赖外部网络。全部确定性本地命令。
|
||||
3. **Agent 不可改植物神经** — watchers/保命 rules/executors 硬编码在核心包。
|
||||
4. **幂等性靠 snapshot** — Rule 只看 `(prev, curr)`,不查 events 历史。rebuildSnapshot 预重建所有需要的状态。
|
||||
5. **Bypass = 短路** — 保命 rule 不调 `inner()` 时,内层业务 rules 全部跳过。
|
||||
|
||||
## 测试约定
|
||||
|
||||
- 单测文件和源码同目录:`foo.ts` → `foo.test.ts`
|
||||
- E2E 在 `packages/upulse/src/e2e/`
|
||||
- Mock 使用 `bun:test` 的 `jest.fn()` / `jest.spyOn()`
|
||||
- 网络/进程相关测试用依赖注入(如 `fetchFn` 参数),不做真实 IO
|
||||
- Watcher 测试构造 mock store + mock wakeTick
|
||||
- Rule 测试构造 mock snapshot + mock inner
|
||||
|
||||
## 使用 Cursor Agent 编码
|
||||
|
||||
项目使用 [Cursor Agent CLI](https://docs.cursor.com/agent) 作为主要编码工具:
|
||||
|
||||
```bash
|
||||
# 分析(只读,不改文件)
|
||||
agent -p "分析 watchers/ 目录的结构和数据流" \
|
||||
--model claude-4.6-sonnet-medium --mode=ask --output-format text --trust
|
||||
|
||||
# 执行(改文件)
|
||||
agent -p "实现 xxx 功能" \
|
||||
--model claude-4.6-sonnet-medium --force --output-format text --trust
|
||||
```
|
||||
|
||||
### 模型选择
|
||||
|
||||
| 难度 | 模型 | 场景 |
|
||||
|---|---|---|
|
||||
| 🟢 简单 | `gpt-5.4-mini-medium` | 单文件小改、格式化 |
|
||||
| 🟡 标准 | `claude-4.6-sonnet-medium` | bug fix、新功能、重构 |
|
||||
| 🔴 复杂 | `claude-4.6-opus-high-thinking` | 架构改动、多文件重构 |
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [RFC #1: Pulse — Agent 的自主神经系统](https://github.com/oc-xiaoju/pulse/issues/1)
|
||||
- [RFC #23: Autonomic Layer + Rule Middleware](https://github.com/oc-xiaoju/pulse/issues/23)
|
||||
- [Design #27: P0 保命层](https://github.com/oc-xiaoju/pulse/issues/27)
|
||||
- [Wiki: Pulse 架构](https://shazhou-ww.github.io/oc-wiki/shared/pulse-agent-architecture/)
|
||||
@@ -1,62 +1,150 @@
|
||||
# Pulse
|
||||
|
||||
```
|
||||
Rule = (prev, curr) → (effects, tickMs) → (effects', tickMs')
|
||||
```
|
||||
|
||||
这是 Pulse 的原子——一个上下文相关的修饰函数。上半段感知世界(快照 diff),下半段修饰行为(追加/删除/替换 effects,调整采样频率)。
|
||||
|
||||
整个 Pulse 就是一组 Rule 的 fold:
|
||||
Agent 的自主神经系统。
|
||||
|
||||
```
|
||||
pulse = fold rules dummy
|
||||
dummy = (prev, curr) → ([], defaultTickMs)
|
||||
Rule = (prev, curr, inner) => Promise<[Effect[], tickMs]>
|
||||
```
|
||||
|
||||
Runtime 十行。所有智能在 Rule 里。
|
||||
有状态响应式循环:持续感知 → 认知判断 → 自主行动。确定性任务自己做,不确定才上报 Agent。
|
||||
|
||||
## 什么是 Pulse
|
||||
## 架构
|
||||
|
||||
Agent 的自主神经系统——有状态的响应式循环,持续感知多数据源,自主执行确定性任务,只在不确定时才上报 Agent 决策。
|
||||
```
|
||||
Autonomic 层(vitals.db) Tick 层(events.db)
|
||||
Watchers → 写 vitals → 唤醒判定 rebuildSnapshot → Rule Chain → Executors
|
||||
└── wakeTick() ──────────────→ 提前唤醒 tick
|
||||
```
|
||||
|
||||
### 性质
|
||||
**双层驱动**:Watchers 每 5s 采集写 vitals,关键事件提前唤醒 tick。Tick 层重建 snapshot,跑 Rule Chain 产生 effects,Executors 执行。
|
||||
|
||||
- **Moore 机** — 不逐事件响应,只看两次采样间的状态 diff。Effects 由新状态决定
|
||||
- **路径依赖** — 采样有损,副作用不满足结合律。采样频率 = 现实世界的分辨率
|
||||
- **不强制纯函数** — 大部分 Rule 是确定性的(零 token),不确定时可以 async
|
||||
- **Agent 管理** — Rule repo 是 TypeScript 项目,tsc 守门。staging 用 git worktree
|
||||
**洋葱 Rule 模型**:每个 Rule 接收 `inner`(剩余 rule chain),可以放行、bypass(跳过内层)、修饰结果、变换 snapshot。保命 rules 硬编码在最外层,agent 的业务 rules 在内层。
|
||||
|
||||
### Agent 与 Pulse 的关系
|
||||
## 三层不可变性
|
||||
|
||||
Agent 是意识层,Pulse 是自主神经系统。Agent 定义 Rule,Pulse 执行 Rule,遇到例外回报 Agent,Agent 调整 Rule。
|
||||
| 层级 | 比喻 | 谁能改 |
|
||||
|---|---|---|
|
||||
| **植物神经** — watchers、保命 rules、executors | 心跳、痛觉 | 只能 npm 升级 |
|
||||
| **浅层自主神经** — 业务 rules | 呼吸节奏 | Agent staging → promote |
|
||||
| **意识层** — OC Agent session | 思考、决策 | kill/restart 不影响 Pulse |
|
||||
|
||||
人不能通过大脑控制让心脏停跳。Agent 不能修改自己的保命逻辑。
|
||||
|
||||
## 包结构
|
||||
|
||||
| 包 | 内容 |
|
||||
|---|---|
|
||||
| `@uncaged/pulse` | 核心引擎:`runPulse()` + `Rule` 类型,纯泛型零依赖 |
|
||||
| `@uncaged/upulse` | CLI:daemon 管理 + test/staging/promote |
|
||||
| `@uncaged/pulse-rules` | 共享 Rule 函数库 |
|
||||
| 包 | 说明 | npm |
|
||||
|---|---|---|
|
||||
| `@uncaged/pulse` | 核心引擎 + 保命层 + watchers | [](https://www.npmjs.com/package/@uncaged/pulse) |
|
||||
| `@uncaged/upulse` | CLI:daemon 管理、staging/promote/rollback | [](https://www.npmjs.com/package/@uncaged/upulse) |
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 安装
|
||||
bun add @uncaged/pulse
|
||||
bun add -g @uncaged/upulse
|
||||
|
||||
# 初始化 engine 目录
|
||||
upulse init
|
||||
|
||||
# 开发模式(热重载)
|
||||
upulse dev
|
||||
|
||||
# 部署到生产
|
||||
upulse deploy
|
||||
|
||||
# 启动 daemon
|
||||
upulse daemon start
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Rule(洋葱中间件)
|
||||
|
||||
```typescript
|
||||
type Rule<S, E> = (
|
||||
prev: S, // 上一次 snapshot
|
||||
curr: S, // 当前 snapshot
|
||||
inner: (prev: S, curr: S) => Promise<[E[], number]> // 内层 rule chain
|
||||
) => Promise<[E[], number]> // [effects, tickMs]
|
||||
```
|
||||
|
||||
Rule 可以:
|
||||
- **放行**:`return inner(prev, curr)`
|
||||
- **Bypass**:`return [myEffects, 5000]`(不调 inner,跳过内层)
|
||||
- **修饰**:先 `await inner(prev, curr)` 再追加/过滤 effects
|
||||
- **变换 snapshot**:`return inner(prev, modifiedCurr)`
|
||||
|
||||
### Watcher(Autonomic 层)
|
||||
|
||||
```typescript
|
||||
interface WatcherDef {
|
||||
name: string
|
||||
key: string // vitals 表的 key
|
||||
collect: () => Promise<unknown> | unknown // 采集数据
|
||||
shouldWake: (window: VitalWithData[]) => boolean // 唤醒判定
|
||||
intervalMs?: number // 采集间隔,默认 5000
|
||||
}
|
||||
```
|
||||
|
||||
Watcher 持续采集写 vitals,唤醒判定看最近 1 分钟窗口(~12 条),关键事件 `wakeTick()` 提前唤醒 tick。
|
||||
|
||||
### 存储
|
||||
|
||||
| 库 | 内容 | 策略 |
|
||||
|---|---|---|
|
||||
| `events.db` | promote/rollback/effect/error/collect | 永不压缩 |
|
||||
| `vitals.db` | 系统资源/进程/网络/LLM 健康 | 可 gc |
|
||||
| `objects/` | CAS(内容寻址,不可变) | 自动去重 |
|
||||
|
||||
### 保命层(P0 Survival)
|
||||
|
||||
5 个内置 Watcher + 7 个保命 Rule,零 LLM 零网络依赖:
|
||||
|
||||
**Watchers:**
|
||||
- `system-resource` — CPU/内存/磁盘/swap
|
||||
- `process-alive` — 关键进程存活
|
||||
- `network` — DNS + HTTP 出站
|
||||
- `error-log` — 日志关键词匹配
|
||||
- `llm-health` — 双层探针(轻量 5s + 深度 60s)
|
||||
|
||||
**Rules(洋葱顺序,最外层先执行):**
|
||||
1. `panicRollback` — 保命动作连续失败 → 紧急回滚
|
||||
2. `autoRollback` — promote 后大量 error → 自动回滚
|
||||
3. `processWatchdog` — 进程挂了 → restart
|
||||
4. `resourceGuard` — 内存/磁盘超限 → archive sessions + 清理
|
||||
5. `llmWatchdog` — LLM 不通 → restart LiteLLM
|
||||
6. `networkWatchdog` — 网络断了 → 通知
|
||||
7. `errorEscalate` — 错误日志 → 通知 + 加速巡检
|
||||
|
||||
## Engine 目录
|
||||
|
||||
每个 Agent 维护自己的 engine repo:
|
||||
每个 Agent 维护自己的 Rule repo:
|
||||
|
||||
```
|
||||
~/.upulse/
|
||||
config.json
|
||||
engine/ ← main branch(生产)
|
||||
types.ts ← Snapshot + Effect 类型
|
||||
pulse.db / vitals.db / objects/
|
||||
engine/ ← main branch(生产)
|
||||
types.ts
|
||||
rules/
|
||||
collectors/
|
||||
effectors/
|
||||
pulse.config.ts
|
||||
staging/ ← git worktree(安全实验)
|
||||
staging/ ← git worktree(安全实验)
|
||||
```
|
||||
|
||||
`upulse promote` = git merge + tsc 守门 + daemon reload
|
||||
`upulse rollback` = git revert + 自动恢复
|
||||
|
||||
## 设计文档
|
||||
|
||||
[RFC #44: Pulse — Agent 的自主神经系统](https://github.com/oc-xiaoju/ograph/issues/44)
|
||||
- [RFC #1: Pulse — Agent 的自主神经系统](https://github.com/oc-xiaoju/pulse/issues/1)
|
||||
- [RFC #2: upulse CLI](https://github.com/oc-xiaoju/pulse/issues/2)
|
||||
- [RFC #4: 核心洞察 — 感知·认知·行动](https://github.com/oc-xiaoju/pulse/issues/4)
|
||||
- [RFC #5: 一切皆事件 — 存储模型](https://github.com/oc-xiaoju/pulse/issues/5)
|
||||
- [RFC #22: 多实例管理](https://github.com/oc-xiaoju/pulse/issues/22)
|
||||
- [RFC #23: Autonomic Layer + Rule Middleware Refactor](https://github.com/oc-xiaoju/pulse/issues/23)
|
||||
- [Design #27: P0 保命层完整设计](https://github.com/oc-xiaoju/pulse/issues/27)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user