# 需求统一启停控制台(2026-09-30) > 起因(用户原话):**「使用协作skill后 某个需求 统一管理 各种对应任务和程序的启停,包括协作程序等」** > 落地物:`.workbuddy/collab/goalctl.py`(新)+(复用)`.workbuddy/collab/stop-collab.py`。 > 全文读数均为本机实测,⛔ 无推断。 --- ## 0. 结论(三行) 1. **一个需求牵扯的"可启停物"只有四层**(实测盘清,别再数):**排期层/程序层/总开关层/服务层**;钩子层**不在可启停范围内**(下条)。 2. 🔴 **一个硬事实决定了整个设计形状**:**钩子是全局注册、跨项目共用的** —— `E:/ProgramData/.workbuddy/settings.json` 里 12 个 hook,其中还混着**别的工作区**的 `ai1net-decision-laya/bridge/decision_bridge.py`(×4 事件)。⇒ ⛔ **不能靠"装卸钩子"来启停某个需求**(会连累所有项目)⇒ 只能 **开关文件 + 入口早退**。 3. **入口已落地成三条命令**:`goalctl.py status | start | stop`(**默认干跑**,加 `--yes` 才真做;写前自动备份)。 --- ## 1. 清单:一个需求到底牵扯哪些东西(本机实测) | 层 | 具体物 | 本棒实测状态 | 谁能改 | 拦在哪(生效点) | |---|---|---|---|---| | ① **排期层** | `automations` 表里的**周期排期** | **3 条,全 PAUSED** | ⛔ **只有会话**(`automation_update` 工具) | 不再起新会话 | | ② **程序层** | `collabd.config.json` 的 `wake_enable`(协作程序**投递总闸**) | 本棒已置 `false` | ✅ 脚本 | 程序不再投递(=不再唤醒主会话) | | ③ **总开关层** | `goal.json` 的 `run` 段(`active`/`paused`) | 本棒已置 `paused` | ✅ 脚本 | 唤醒轮/程序读到即**立刻退** | | ④ **服务层** | 看板 `board.py --serve`/守护 `guard`/网关心跳 | **全停**(0 个 / 没在跑 / 登记册 0 条) | ✅ 复用 `stop-collab.py` | 写标志 ⇒ 对端**优雅退出** | | — **钩子层** | 全局 12 个 hook(`wb-result-hook.py`、`lock-guard-hook.py`…) | 常开、不可装卸 | ⛔ 只有全局配置能改 | **不拦** —— 零 token,且"要不要干活"全在它调的程序内部 | **剔除项(⛔ 不是启停对象)**:**一次性棒 15 条**(`schedule_type='once'`、`next_run_at` 空=已耗),它们 `status` 仍是 ACTIVE 但永远不会再触发。 ⚠️ **判"某条排期还在不在跑"不能只看 `status`** —— 删除是**软删**(`deleted_at` 有值、`status` 照旧 ACTIVE)⇒ 脚本里已按 `deleted_at` 过滤。 --- ## 2. 三条硬约束(决定了为什么长这样) | # | 约束 | 后果 | |---|---|---| | ① | **钩子全局注册、跨项目共用** | ⛔ 不装卸钩子;启停只能靠"开关文件 + 入口早退" | | ② | **排期只能由会话改**(脚本直改 `workbuddy.db` 的 `automations` = 改活库,且宿主是否重读未验) | 脚本**只打印待办**;⚠️ 并给**降级保障**:漏改时唤醒轮读到 `run=paused` 会立刻退(一次空跑) | | ③ | ⛔ 不 kill 会话/worker | ⛔ 不重启宿主 | ⛔ 不改全局配置 | 停服务一律"**写标志让对方自己退**"(`guard.stop`)、或停**自建**看板实例 | --- ## 3. 启停语义:三层同时翻,缺一层就留缝 | 想要 | ① 排期层 | ② 程序层 | ③ 总开关 | ④ 服务层 | |---|---|---|---|---| | **真停** | `PAUSED` | `wake_enable=false` | `run=paused` | `stop-collab.py --yes` | | **真启** | `ACTIVE`(+两条相位差 ≈30 分钟) | `wake_enable=true` | `run=active` | ⛔ **不自启任何常驻**(常驻在本机已判走不通) | **为什么三层缺一不可**(各自守备范围不同): - **排期层** 管:**会不会起新会话**(唯一能产生新交付的通道) - **程序闸** 管:**会不会投递**(投递=唤醒活会话,会占主会话一轮 ⇒ 用户体感"卡") - **总开关** 管:**起来了之后该不该干活**(兜底 + 人/AI 都直接可读) - 🔴 三者**互补不重叠**:只关程序闸 ⇒ 排期照旧起会话;只停排期 ⇒ 程序照旧投递;只有三个一起翻才是"真停"。 --- ## 4. 用法 ```bash PY="E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" "$PY" .workbuddy/collab/goalctl.py # 状态台(只读,四层一次列清) "$PY" .workbuddy/collab/goalctl.py stop # 干跑:列出会做什么 "$PY" .workbuddy/collab/goalctl.py stop --yes # 真停 "$PY" .workbuddy/collab/goalctl.py start --yes # 真启 "$PY" .workbuddy/collab/goalctl.py start "新目标名" --yes # 启 + 改名 ``` **驱动口径(=用户已定的那条)**:启停由 **「执行 XXX 目标」这道口令**驱动 —— 下口令 ⇒ `start`;**目标完成或有阻碍 ⇒ `stop`**。⛔ **唤醒轮自己不许把自己启回来**。 ### 状态台实际输出(本棒读数) ``` 【总开关】run = paused 目标 = 本机(桌面客户端)内的多会话协作 目标状态 = 三路全过 队列 = {'done': 4} 【② 程序闸】wake_enable = False 钩子链最后唤起 = tick 2 分钟前 / once 4 分钟前 【① 排期层】周期排期 3 条(**这才是启停对象**)/一次性棒 15 条(已耗,⛔ 不是启停对象) ⚪ 1eaf45c3 PAUSED [协同监管 · 心跳……] ⚪ 16bec5ce PAUSED [本机协作]-唤醒轮B ⚪ caca9a89 PAUSED [本机协作]-唤醒轮A ⇒ 一句话:这个需求现在是 **停着** ``` --- ## 5. 本棒实际做了什么 1. **新增** `.workbuddy/collab/goalctl.py`(状态台 + start/stop;**默认干跑**、写前备份到 `.workbuddy/collab/bak-goalctl-<日期>/`、⛔ 从不删文件)。 2. **接进唤醒轮**:两条提示词都加了**第 0 步"先读总开关"** —— `run=paused` ⇒ ⛔ 不派活、⛔ 不改文件、⛔ 不自启,一句话结束(="停"的兜底)。 3. **按已定口径落成一致状态**:A/B 从未 ACTIVE(没下过"执行 XXX 目标"口令)⇒ 正解就是停 ⇒ 执行 `stop --yes`: `run=paused`/`wake_enable=false`/服务层全停/排期 2 条本已 PAUSED。 4. 🔴 **顺手修掉一个真 bug**(会致"误判完成"):原实现把任务图按"默认点"读 `tmp/supervise-inbox/taskgraph.json` —— **该文件根本不存在** ⇒ 三路并集少一路 ⇒ 可能把"未完成"看成"已完成"。现改为**按配置 `taskgraph` 解析**(`交付物/任务图.json`,18 节点全 done);并给**读不到**单独打标(⛔ 不许读不到就判完成)。 --- ## 6. 已知边界(诚实说,⛔ 别当它能做到) - ⛔ **做不到"一秒内把所有在跑的会话停下"** —— 会话不可 kill(用户明令)。能做的只有「**不再叫新的** + **起来了不干活**」。 - ⚠️ **排期层脚本改不了** ⇒ 必须由会话执行;有 `run=paused` 兜底,但**那一轮仍会被起一次**(成本=一次空会话)。 - ⚠️ **一个工作区当前只有一份 `goal.json`** ⇒ **"需求"与"工作区"目前是 1:1**。若将来一个工作区要并行多个需求,得把开关做成多份(本棒不做)。 - ℹ️ `wake_enable=false` **只关投递**:程序的投影、看板、台账照常(零成本),所以"关"没有副作用。 - ℹ️ ④ 服务层里**网关心跳已被判死能力**(桌面端硬编码 `CODEBUDDY_DISABLE_CRON=1`)⇒ 那一项是"名存实亡",`stop` 只是顺手清登记册。 --- ## 7. 图 见同目录 `唤醒-需求统一启停-20260930-图.html`(① 四层清单图:标出钩子层"不可启停";② 三层守备图:各层各拦什么)。