PR #80 changed pgrep to systemctl show --property=MainPID + ps, but tests still mocked only one execSync call (the ps call). Now mock systemctl call first, then ps call. Ref #80 Co-authored-by: 小橘 <xiaoju@shazhou.work>
Pulse
Agent 的自主神经系统。
Rule = (prev, curr, inner) => Promise<[Effect[], tickMs]>
有状态响应式循环:Percept → Understand → Execute。确定性任务自己做,不确定才上报 Agent。
三原语
| 层 | 英文 | 组件 | 输出 | 佛教映射 |
|---|---|---|---|---|
| 感知 | Percept | Watchers(六处) | Events(六入,按 sense 分类) | 六处触尘 |
| 认知 | Understand | Rules | Effects(序列化的行动参数) | 受想行 |
| 行动 | Execute | Executors | Events(执行结果) | 身口意业 |
一切皆业:Percept / Tick / Execute 都写 events。Events 是不可变的业的记录。
Effects 不是行动本身,是行动的描述——序列化的参数,由 Executor 解释执行。
架构
Percept 层(vitals.db) Understand + Execute 层(events.db)
Watchers → 写 vitals → 唤醒判定 rebuildSnapshot → Rule Chain → Executors
└── wakeTick() ──────────────→ 提前唤醒 tick
双层驱动:Watchers 每 5s 感知写 vitals,关键事件提前唤醒 tick。Tick 层重建 snapshot,Rules 认知产生 effects,Executors 执行。
洋葱 Rule 模型:每个 Rule 接收 inner(剩余 rule chain),可以放行、bypass(跳过内层)、修饰结果、变换 snapshot。保命 rules 硬编码在最外层,agent 的业务 rules 在内层。
三层不可变性
| 层级 | 比喻 | 谁能改 |
|---|---|---|
| 植物神经 — watchers、保命 rules、executors | 心跳、痛觉 | 只能 npm 升级 |
| 浅层自主神经 — 业务 rules | 呼吸节奏 | Agent staging → promote |
| 意识层 — OC Agent session | 思考、决策 | kill/restart 不影响 Pulse |
人不能通过大脑控制让心脏停跳。Agent 不能修改自己的保命逻辑。
包结构
快速开始
# 安装
bun add @uncaged/pulse
bun add -g @uncaged/upulse
# 初始化 engine 目录
upulse init
# 开发模式(热重载)
upulse dev
# 部署到生产
upulse deploy
# 启动 daemon
upulse daemon start
核心概念
三原语:Percept → Understand → Execute
| 层 | 英文 | 组件 | 输出 | 佛教映射 |
|---|---|---|---|---|
| 感知 | Percept | Watchers(六处) | Events(六入,按 sense 分类) | 六处触尘 |
| 认知 | Understand | Rules | Effects(序列化的行动参数) | 受想行 |
| 行动 | Execute | Executors | Events(执行结果) | 身口意业 |
一切皆业:Percept / Tick / Execute 都写 events。Events 是不可变的业的记录。
Effects 不是行动本身,是行动的描述——序列化的参数,由 Executor 解释执行。
Rule(洋葱中间件)
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(Percept 层)
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)
4 个内置 Watcher + 7 个保命 Rule,零 LLM 零网络依赖:
Watchers:
system-resource— CPU/内存/磁盘/swapprocess-alive— 关键进程存活network— DNS + HTTP 出站error-log— 日志关键词匹配
Rules(洋葱顺序,最外层先执行):
panicRollback— 保命动作连续失败 → 紧急回滚autoRollback— promote 后大量 error → 自动回滚processWatchdog— 进程挂了 → restartresourceGuard— 内存/磁盘超限 → archive sessions + 清理llmWatchdog— LLM 不通 → restart LiteLLMnetworkWatchdog— 网络断了 → 通知errorEscalate— 错误日志 → 通知 + 加速巡检
Engine 目录
每个 Agent 维护自己的 Rule repo:
~/.upulse/
config.json
pulse.db / vitals.db / objects/
engine/ ← main branch(生产)
types.ts
rules/
watchers/
executors/
staging/ ← git worktree(安全实验)
upulse promote = git merge + tsc 守门 + daemon reload
upulse rollback = git revert + 自动恢复
设计文档
- RFC #1: Pulse — Agent 的自主神经系统
- RFC #2: upulse CLI
- RFC #4: 核心洞察 — 感知·认知·行动
- RFC #5: 一切皆事件 — 存储模型
- RFC #22: 多实例管理
- RFC #23: Autonomic Layer + Rule Middleware Refactor
- Design #27: P0 保命层完整设计
License
MIT