Repository navigation
本页会随勘误就地更新。规范全文以
main为准。
这一版只回答一个问题
没人管它的时候,它在做什么?——以及,谁有权让它停下来?
前几版解决的都是"有事的时候怎么办":到线了压缩、出事了自己修、有新会话了抓取。这一版处理的是没事的时候:队列空了、没人发话、水位也够——它不必再"等下一次输入",可以把自己记下的事拿出来做。
设计思想(为什么给"空闲"单独设计一档)
- 空闲不是"待机",是它自己的时间。 一个只会响应输入的系统,没有输入时就是死的;既然记忆是文件、规则是文件,那么"接下来想做什么"也应该能写进文件,等下一次醒来接着做。
- 谁写的,谁负责。 这些事不是管理员配置的任务,是运行中的那个自己写下的意图(
by: self)。人也可以让它记一条(by: human),但两者记在同一条账上,出处分明。 - 一切是选择,从不指定。 心跳间隔 30 秒只是我们这套的默认值;换一个人设 1 秒、设 1 小时,都只是配置。每个自主动作都能被关掉——
off关整块、drop删单条、needs决定"能不能自己做"、优先级表决定"谁让谁"。没有任何一条是"必须执行"的。 - 自由有边界,而且边界写在代码里,不写在说明书里。 触摸红线的事(删记忆、改内核、换模型、迁移合并、改交接格式、改注入四闸、改成 350K/900s、出网、
pip install、git push)在写意图那一刻就被拒绝,不是等到执行时才拦。 - 不让它饿死,也不让它称霸。 想做的事连续被抢占 3 次、或 24 小时没做成 → 优先级上浮一档;但上浮永远到不了闹钟与人当场指令之上,且每天最多一次。低位不是特权,只是"别永远做不成"。
一条链路(醒来之后,到"它自己找事做")
心跳醒(默认 30 秒,可改)
│
├─ 加载:设定 + 交接包 + 台账
├─ 上报:读全局索引(index_total 合并进简讯)+ ⑦在办 ⑧现在能做 ⑨已自动开工
│
├─ 看任务:在办无未收尾?任务池无未完成?(有活 → 直接干,空闲循环不启动)
│
├─ 有空闲 → 空闲循环(persona_autoloop)
│ ├─ 按优先级挑:自述意图(按条) > 自检 > 检索历史 > 联网(默认关) > 休息
│ ├─ needs=none 且 run 非空 → 执行(可被抢占)
│ ├─ needs=human / external → 只报「要你点头 / 要外部条件」,不执行
│ └─ 全都不满足 → 休息(不执行任何命令,只记一行)
│
└─ 高优先级来了(闹钟 / 人当场指令 / 真任务)
→ 正在跑的低优先级命令 0.5 秒内被 terminate,账本记 preempted_by
→ 压缩 / 镜像 / git / 写 sessions·archive·续接 的命令**不杀**,排队等下次
要实现什么 → 对应机制
| 目标 | 机制 |
|---|---|
| 空闲时有"自己的事"可做 | ops\intents.jsonl 自述意图(只追加);wish 一句话写入 |
| 它想做的事不能越过红线 | wish 时过护栏,命中即 refused 并说明"属需人点头项" |
| 要联网/花钱/要人点头的事不擅自做 | needs: none / human / external 三档,后两档只报不做 |
| 有活时绝不"自行其是" | 只有在办与任务池都空时才 tick |
| 同一件事两套调度打架 | 优先级表 ops\sched-priority.json(数字越小越高),低的一方让位并写日志 |
| 低优先级跑不完 | 租约 + 0.5 秒轮询抢占,preempted_by 留痕;白名单里的命令不杀 |
| 想做的事被长期挤压 | 饥饿保护:连续 3 次被抢占或 24 小时未做成 → 上浮一档,每天最多一次 |
| 管理者随时能停 | off / enabled:false / drop / rm;整块停后其他调度照旧 |
细节(按职责)
- 意图账本:一行一条,
id / at / by / what / why / run / priority / min_gap / needs / status / done_at / result;同 id 后写的为准,历史不删。 - 护栏:匹配的是"动作语义"而不是关键字黑名单——删除/清理记忆、改内核、换模型、迁移合并、改交接格式、改注入四闸、改 350K/900s、出网、装依赖、push,命中即拒并记录拒绝理由。
- 抢占:开跑写
running租约(含 pid 与优先级);轮询到更小数字的pending就自己让位;Windows 先taskkill /T再 kill。被杀的记interrupted,min_gap从开始时间算,避免"跑一半被杀、立刻重跑"的抖动。 - 不杀的清单:
persona_compact、persona_mirror、git、任何写sessions/、archive/、续接/的命令。压缩被杀会留下半截现场,这条写死在代码里。 - 上报:简讯加
⑩ 我留给自己的(最多 3 条)、⑪ 现在要做的、⑫ 被挤压的(被挤掉几次 / 多久没做);只判不执行。
证据(2026-11-10 本机真跑)
$ python persona_sched.py status
job 租约 owner 到期 状态 被谁打断 优先级
compact-check alarm 17:06:26(剩 71s) idle — 1(alarm 1 / daemon 2)
$ python persona_autoloop.py status
意图(ops\intents.jsonl):0 条
(还没有:用 wish "我想做 X" 写一条)
开关:开
$ python persona_autoloop.py --once --dry-run
[dry-run] 休息(没有想做又能做的)
抢占与饥饿保护的沙盒证据(临时库,不碰生产):
- 低优先级
sleep 30在 1–2 秒内被高优先级任务 terminate,账本preempted_by正确、状态interrupted; - 同一沙盒里低优先级跑
persona_mirror.py --check时高优先级来了不杀(标nonpreemptible,等高优先级排队); - 连续被抢占 3 次的意图优先级上浮一次、账本出现
promoted、简讯⑫出现「被挤压」;第四次抢占不再上浮(每天一次上限)。
边界(这一版没做的)
- 没有"无限自由":空闲期随时可被闹钟、人的当场指令、现实法理打断;这一版给的是"被授权的自主",不是权利——AI 还没有独立法理地位,谈权利是空的。
- 不联网、不花钱:
needs=external只报不做;websearch之类留空槽,要开由人填。 - 不做语义级"理解用户喜好":想做的事仍由写意图的那一方决定(它自己或人),没有自动生成"目标"的机制。
- 抢占是进程级的:只能杀子进程;如果某个动作是"在会话里做"的(
run为空的想法),它无法被系统抢占,只能由对话本身让路。 - 跨平台未测:抢占用
taskkill,Windows 之外的实现没验证过(与全局的平台边界一致)。
修订记录
- 2026-11-10:首次发布。编号按人要求取 5.9(v5.8.0 之后的下一个 MINOR)。
- 与 v5.8.0 的关系:v5.8 通的是"机器与机器之间"的管子;这一版通的是"没人发话时"的那段时间。两者共用同一条判据——记忆是文件,模型只是引擎。