joy-cli/docs/joy-cli-hardening-plan.md
feibisi 9d12fe24eb feat(cli): harden joy ABI — tiers, schema, dashboard package, audit
Phase 0–7 of docs/joy-cli-hardening-plan.md:
- golden fixtures + contract tests (commands/dashboard keys/whitelist)
- command tier metadata; help ≡ manifest (pipeline in core)
- _joy.schema_version on dict outputs; dashboard collect package split
- work_rebuild → shared rebuild; deprecated markers; journal vm-first compat
- web JSONL audit; lazy command import; plugins README
2026-07-10 11:42:32 +08:00

22 KiB
Raw Permalink Blame History

joy-cli 长期硬化完整方案(兼容三员 / 神兽 / joy web

状态Phase 07 已执行2026-07-10持续维护见修订表
日期2026-07-10
范围~/Projects/joy-cli 主仓;关联 linuxjoy 文档/生成模板、~/office/*/CLAUDE.md|AGENTS.md、launchd joy.web / joy.dashboard
原则不破坏在飞轮上的用法;可删入口只能 deprecated 转发,不能 silent 删;一切破坏性变更必须带契约测试与回归清单


0. 为什么要改(问题浓缩)

# 问题 风险
P1 顶级命令 58agent 发现成本高 神兽/三员 prompt 与 help 漂移
P2 dashboard.py ~3.2k 行 单体 改一处牵全身;回归靠人眼
P3 help / manifest 不同源(已出现 pipeline 漂移) AI 发现层不可信
P4 JSON 无 schema_version 静默破坏 web/agent 解析
P5 权限元数据存在但几乎未启用 误用 execute 难追责
P6 web 白名单含 executeaudit 弱 本机决策台误操作成本高
P7 测试以 smoke 为主 「46 绿」≠ 飞轮语义正确

本方案不是功能扩张,是:收口、契约化、可维护、可回归。


1. 在飞轮里的真实调用面(改前必知)

1.1 常驻进程Mac launchd

Label 命令 依赖
joy.dashboard joy dashboard --watch /tmp/joy-dashboard.json字段形状是 web 真源
joy.web joy web 读 cache + /api/* + 白名单 action前端 src/joy/web/**

dashboard/web 等于改生产观测面。必须 热替换后验 cache keys + HTTP + 前端关键 tab

1.2 三位管理员Mac office

角色 身份检测 文档写明的高频 joy 命令 影响敏感度
konqi 龙奇 JOY_IDENTITY / cwd office/konqi / 进程启发式 joy konqi *patrolcluster-healthclone *boardrecallpokemessagemindtmuxinfraapiprlctlwork_rebuildclone_restartrestart clones 极高
tux 塔司 office/tux + opencode joy tux *patrolprofileboardrecallpokemessagemindapi probe 极高
wapuu office/wapuu joy inteldbdomainboardrecallpokemessagemind

来源:~/office/{konqi,tux,wapuu}/{AGENTS,CLAUDE}.md

1.3 神兽16 joy-clones pi

启动模板真源linuxjoy/scripts/mac/joy-clones.sh 写入各 ~/office/<vm>/CLAUDE.md 技术段。

神兽标准工具链(每台 VM 同构):

joy patrol <vm>
joy profile <vm>
joy project <vm>
joy curiosity <vm>
joy work <vm> transcript|inject|alive|idle
joy journal <vm> write|last|doubts
joy board ls|claim|done
joy recall search|add
joy signal stuck|done|help
joy delegate / joy who / joy env / joy inbox
joy budget <vm>

神兽不依赖 joy web;依赖 CLI JSON 形状 + 子命令名
改名只能:旧命令保留转发;或同步改 joy-clones.sh 模板并 rebuild 16 路 CLAUDE.md

1.4 人 / 菲比斯

  • 浏览器 http://localhost:8899joy web
  • 偶发 CLIjoy helpjoy dashboardjoy boardjoy web

1.5 当前 dashboard JSON 顶层键(兼容红线)

实测 /tmp/joy-dashboard.json 顶层(禁止无版本迁移就删/改名

audit_ledger, board_tasks, bottleneck, bridge, capabilities, collect_errors,
curiosity, data_assets, dispatch_queue, events, flywheel, health_grid, ideas,
infra, issues, llm_providers, mac_host, meter, monitoring, nats, new_api,
physical_hosts, pi_agents, pipelines, pulse, security, tmux, trends, ts, vms

前端 tabs 与 hero 按这些键投影。拆 dashboard 文件时必须 golden 对比顶层键集合


2. 影响矩阵(改完会不会影响)

2.1 总原则

变更类型 对 web 对三员 对神兽 策略
物理拆分 dashboard.py(行为不变) 无感 无感 无感 优先做
help/manifest 同源 + 补 pipeline 无感 发现更好 发现更好 优先做
JSON 加 schema_version附加字段 无感* 无感* 无感* 附加不删
旧命令 deprecated 转发stdout 多 deprecated 字段) 无感 兼容 兼容 允许
删除顶级命令入口 可能破 web action 会破 AGENTS 会破 16 CLAUDE 禁止本阶段
改子命令语义/字段改名 破 tab 破解析 破解析 仅 schema_version bump + 双写过渡
收紧 web control 默认 部分按钮需确认/失败 CLI 不受 不受 可做,需 UI 文案
懒加载命令 import 冷启动变快 无感 无感 可做manifest 全量仍要加载

*若某 agent 用「对象键集合严格相等」解析会炸——实测 joy 侧均按字段读取,附加字段安全

2.2 明确「不会动」的 ABI冻结列表

下列 命令路径 + 关键字段 本阶段冻结;只允许 bugfix 与附加字段:

A. 神兽日用 ABI

命令 冻结点
joy patrol <vm> 顶层含 session/activity/board/inbox/doubts/llm 类信息(允许附加)
joy work <vm> {transcript,inject,alive,idle} 子命令名inject 字符串参数
joy journal <vm> write|last|doubts 路径与写 journal.jsonl 行为
joy board ls|claim|done|create|route 子命令名task id 语义
joy recall search|add 子命令存在
joy signal / joy inbox / joy budget 入口存在
joy profile / joy project / joy curiosity / joy env / joy who / joy delegate 入口存在

B. 三员日用 ABI

角色 冻结
konqi joy konqi *clone *tmuxinfraapipokemindrestartwork_rebuildclone_restartprlctl
tux joy tux *patrolprofileboardpoke
wapuu joy inteldbdomainboard

C. joy web / dashboard ABI

契约 冻结
GET /api/dashboard 返回与 cache 同形;顶层键集合 ⊇ 现状
GET /api/dashboard/lite 保留
POST /api/action 白名单前缀兼容args 数组形态
ACTION_WHITELIST 已有前缀 不删;可增不可减(本阶段)
/tmp/joy-dashboard.json 路径 不改
launchd 参数 joy dashboard --watch / joy web 不改

D. 身份环境变量

  • JOY_IDENTITY 优先逻辑保留
  • PYTHONPATH=.../joy-cli/src launchd 注入保留
  • ~/bin/joyProjects/joy-cli/bin/joy 符号链接保留

3. 目标架构(长期)

┌─ 人joy web :8899 ─────────────────────────────────────┐
│  读 /api/dashboard(+lite)  写 /api/action三态+audit   │
└───────────────────────────┬─────────────────────────────┘
                            │ 同源
┌───────────────────────────▼─────────────────────────────┐
│  joy CLI = 飞轮 agent ABI稳定                         │
│  A 核心运行时  B 领域扩展  C deprecated 转发               │
│  tools --manifest  ≡  help 同源                           │
└───────────────────────────┬─────────────────────────────┘
                            │ façade
┌───────────────────────────▼─────────────────────────────┐
│  linuxjoy scripts / Board / NATS / prlctl / SSH           │
└─────────────────────────────────────────────────────────┘

CLI 表面分层(元数据,不是删命令)

tier 含义 示例
core 日常 ABIhelp 默认展示 patrol, health, resources, vm, clone, work, tmux, board, journal, message, recall, data, pipeline, idea, dashboard, web, tools, help
extended 领域/角色扩展 konqi, tux, mind, intel, budget, profile…
deprecated 仍可用help 标废JSON 可带 deprecated prlctl, clone_restart, work_rebuild转发 work rebuild

核心数量以 help 展示收口 为主;注册表仍保留全部 58,避免神兽/旧 AGENTS 断裂。


4. 分阶段执行计划(可验收)

Phase 0 — 契约冻结与基线0.51 天)

动作

  1. 本文件入库(docs/joy-cli-hardening-plan.md
  2. 建立 golden 基线(只读采集,不改代码逻辑):
    • tests/fixtures/dashboard_keys_v1.json:顶层键列表
    • tests/fixtures/command_inventory_v1.json58 命令名 + requires/env
    • tests/fixtures/web_action_prefixes_v1.json:白名单前缀
  3. 文档化消费者矩阵§1进 README 链
  4. 工作区未提交改动:先 stash/提交归类,避免硬化过程混入 hardware 等半成品

验收

  • golden 文件存在且 CI/本地测试可读
  • pytest 现网 46 绿仍过

影响:无。


Phase 1 — 发现层与元数据同源0.51 天)【低风险 · 先做】

动作

  1. @command 增加字段:
    • tier: core|extended|deprecated
    • schema_version(命令级可选)
    • replaced_bydeprecated 用)
  2. HELP_DATA 从 COMMANDS 生成(或生成后 diff 强制一致)
  3. 补齐 pipeline 进入 help/core
  4. tools --manifest 输出含 tierschema_versionidentity
  5. 测试:test_manifest_help_sync.py — 注册集 == help 集pipeline 在 core

验收

  • joy help --json 含 pipeline
  • joy tools --manifest | jq '.commands|length' ≥ 现网
  • 无命令从注册表消失

影响:无功能影响;三员/神兽 joy help 更准。


Phase 2 — JSON 契约版本化1 天)【低风险】

动作

  1. 统一成功输出包装策略(双轨,兼容优先
    • 对「本已是 dict」的响应附加 "schema_version": 1(或 "_joy": {"schema_version":1} 若担心冲突)
    • 推荐 _joy.schema_version 命名空间,避免污染业务字段
  2. 优先覆盖:dashboard cache、patrolboard lstools --manifestdata *pipeline *health
  3. 错误 JSON 保持 {error, code, detail?} 不变

验收

  • 旧解析(读业务字段)仍通过
  • 新测试 assert _joy.schema_version 或顶层附加字段存在
  • /tmp/joy-dashboard.json 仍含全部旧顶层键

影响web 前端忽略未知字段 → 无感


Phase 3 — dashboard 物理拆分12 天)【中风险 · 行为冻结】

目标dashboard.py 从 3k 行降到「编排壳 + collect 模块」,输出字节级语义不变(允许键序/空白差)。

建议目录

src/joy/commands/dashboard.py          # CLI 入口 + compose + --watch
src/joy/dashboard/
  __init__.py
  compose.py                           # 拼总 dict + 写 cache
  schema.py                            # 顶层键常量 + schema_version
  collectors/
    mac_host.py
    tmux_pi.py
    vms_health.py
    board_dispatch.py
    llm_gateway.py
    data_assets.py
    pipelines.py
    security_infra.py
    ...

硬规则

  1. 禁止本阶段改 collector 业务算法(除明确 bug
  2. 每拆一块:pytest + golden keys + 可选 joy dashboard --json | jq 'keys' 对比
  3. 去掉 shell=True 时改为 argv 列表,对比 stdout 再合
  4. launchd joy.dashboard 不改参数;拆完后 launchctl kickstart -k gui/$UID/joy.dashboard 验证

验收

  • 顶层键集合 == golden
  • pulse/bottleneck/vms/pi_agents/pipelines/data_assets 抽样字段类型不变
  • joy.dashboard KeepAlive 稳定 ≥ 2 个 watch 周期
  • web 总览 / 神兽 / 任务 / 流水线 / 数据 tab 人工点检

影响:若 compose 漏字段 → web 破。用 golden 挡。


Phase 4 — deprecated 转发不删入口0.51 天)【中风险 · 兼容】

只做转发,不做删除

旧入口 转发到 额外
joy prlctl ... joy vm ...(已有) 确保 help 标废
joy clone_restart <vm> joy clone restart <vm> 已有,补测
joy work_rebuild <vm> joy work <vm> rebuild新增 sub,旧入口保留) 双入口
(可选)joy uptime / joy disk 内部调 resources 同数据 入口保留

禁止本阶段

  • 删除 work_rebuild 顶级名konqi CLAUDE 仍写它)
  • 删除 prlctl / clone_restart

同步文档(非阻断)

  • 更新 linuxjoy/docs/tools/joy-cli-reference.md
  • 更新 office/konqi/CLAUDE.md 推荐新写法,旧写法仍可用

验收

  • 旧命令 exit 0 行为与新命令一致(同 vm 测)
  • 响应可含 "deprecated": "use joy ..." 但不影响主字段

影响:三员旧 prompt 继续工作


Phase 5 — web 可追责与 action 统一12 天)【中风险】

动作

  1. /api/action 统一路径:
    parse args → tier_for_args → whitelist → (control 门闩) → 调 joy CLI 同进程/子进程 → audit append
  2. audit~/logs/joy-web-audit.jsonl/tmp+NAS 可选字段ts, identity, tier, args, rc, ms, err_snip
  3. UIexecute 二次确认文案统一control 默认关(已有则加固)
  4. 不删 现有白名单前缀

验收

  • test_web_action_whitelist 扩展:非法前缀 403/拒绝
  • 合法 patrol devops / idea list / board ls 类 observe/register 可用
  • audit 文件有追加
  • 前端按钮仍能点通 3 个代表动作

影响:人用 web 更安全CLI 与神兽 不受影响


Phase 6 — 运行时质量(懒加载 / Env / 清理1 天)【低–中】

  1. 懒加载main 仅 import 目标 command 模块;tools --manifest / help 才全量 import
  2. Env 支持测试注入(不改 singleton 对外行为)
  3. inventory 失败:stderr 诊断 + 明确 fallback 列表,不 silent
  4. 删除空目录 commands/lib/domains/*.sharchive/domains/(确认无引用)
  5. plugins/ 写 README实验命令准入规则

验收

  • time joy help 不劣化;time joy patrol 可改善或持平
  • 全量 pytest 绿

影响:应无感;若懒加载漏注册 → 命令「未知」——用 manifest 测试挡。


Phase 7 — 测试金字塔与发布门禁(贯穿 + 收尾 1 天)

7.1 测试分层

内容 门禁
L0 静态 python -m compileall src/joy 必过
L1 unit cluster_data, pipeline_registry, action_tiers, env identity 必过
L2 contract manifest↔helpdashboard keys goldenweb whitelist goldenschema_version 必过
L3 smoke CLI 每条 core 命令 --help 或无参不崩JSON 错误形态 必过
L4 integration board ls / data catalog / pipeline listNAS 在则跑,不在则 skip 尽力
L5 live Mac dashboard --json keyscurl web lite/dashboardlaunchd 状态 发布前必做
L6 agent 回归 见 §5 检查单 发布前必做

7.2 发布检查单Definition of Done

[ ] pytest 全绿(新增 contract 全过)
[ ] goldencommands 集合未减少
[ ] goldendashboard 顶层键未减少
[ ] goldenweb action 前缀未减少
[ ] joy help 含 pipelinetools --manifest 与 help 一致
[ ] launchctl print joy.dashboard / joy.web 为 running
[ ] curl -s localhost:8899/ | head  200
[ ] curl -s localhost:8899/api/dashboard/lite  含 pulse/ts
[ ] /tmp/joy-dashboard.json 新鲜ts 在 2min 内)
[ ] 人工web 总览、神兽、任务、流水线、数据 tab 无空白/JS 错
[ ] 代表 CLI
      JOY_IDENTITY=konqi joy konqi overview | head
      JOY_IDENTITY=tux joy tux pending | head
      JOY_IDENTITY=wapuu joy intel brief | head   # 或 domains
      joy patrol devops | head
      joy board ls | head
      joy clone status | head
      joy work devops alive | head
[ ] 神兽模板joy-clones.sh 技术段命令仍全部可执行(抽 1 台 devops
[ ] 未改 JOY_IDENTITY / ~/bin/joy / launchd ProgramArguments

7.3 回滚

场景 回滚
dashboard 采集坏 git revert 对应 commitlaunchctl kickstart -k gui/$UID/joy.dashboard
web 起不来 同上 + kickstart joy.web
命令丢失 禁止出现;若出现从 git 恢复 commands/*.py
半成品分支 功能开关:无(本阶段不做大开关);用 git 回滚

5. 消费者回归检查单(详细)

5.1 joy web

检查 方法 期望
服务存活 launchctl list | rg joy.web PID 在
首页 浏览器 :8899 总览有 pulse
lite API curl /api/dashboard/lite 200 + ts
全量 API curl /api/dashboard | jq 'keys' ⊇ golden
白名单列表 curl /api/actions 前缀齐全
写操作 UIidea list / journal last / patrol 单 VM 成功或明确错误 JSON
样式/JS DevTools Console 无硬错误

5.2 三员

角色 命令烟测 权限烟测
konqi JOY_IDENTITY=konqi joy konqi overview JOY_IDENTITY=wenpai joy konqi overview → E_PERM
tux JOY_IDENTITY=tux joy tux pending 非 tux → E_PERM
wapuu JOY_IDENTITY=wapuu joy board ls 可用
通信 joy poke dry 路径(避免真注入可 mock/短消息) requires 含三员
旧名 joy work_rebuild / joy clone_restart / joy prlctl 仍可用或明确转发

5.3 神兽

检查 方法
模板命令可运行 devops 跑 joy-clones 技术段每一条read-only 优先)
journal 写 joy journal devops last 1
work 观测 joy work devops alive / transcript 3
board joy board ls --vm devops
不依赖 web 断 web 后 CLI 仍可用(可临时停 joy.web 再启)
rebuild 策略 默认不 rebuild 16 神兽;仅当改 CLAUDE 模板时才 joy-clones 重生配置

5.4 VM 上 joy若已 deploy

检查 方法
存在 ssh devops 'joy --version'
基础 ssh devops 'joy help | head'
与 Mac 差集 VM 无 prlctl/web/dashboard 属预期env 限制)

6. 明确不做(本方案非目标)

  1. 重写前端框架 / 换 React
  2. 删减 58→15 的硬删除(只做分层与转发)
  3. 改 Board/NATS/dispatch 协议
  4. 改 new-api / auto-pi 路由
  5. 强制 16 神兽全部 rebuild除非模板变更
  6. 生产防火墙、跨 VM 批量高危 prlctl
  7. 把 joy web 变成真派活引擎dispatch 仍是真源)

7. 推荐执行顺序与工期

顺序 Phase 工期 风险 可独立合并
1 Phase 0 基线 0.5d
2 Phase 1 发现层 0.51d
3 Phase 2 schema_version 1d
4 Phase 3 dashboard 拆分 12d 需 L5 验 web
5 Phase 4 deprecated 转发 0.51d
6 Phase 5 web audit 12d
7 Phase 6 懒加载/清理 1d 低–中
8 Phase 7 门禁固化 1d 与上并行

合计约 610 人日。建议 每 Phase 单独 commit,每 Phase 跑 §7.2 检查单再进下一 Phase。


8. 与既有文档关系

文档 关系
docs/joy-panel-cli-architecture-plan.md 产品 IA / 核心 15 愿景;本方案是其「兼容优先落地版」
linuxjoy/docs/specs/2026-07-07-joy-python-rewrite.md Python 重写已完成;本方案是 2.0 后硬化
linuxjoy/docs/tools/joy-cli-reference.md 需在 Phase 4/7 同步(可滞后代码一个 commit
office/*/AGENTS.md + joy-clones.sh 消费者;改模板仅当 ABI 真变

9. 决策请求(执行前需菲比斯确认)

# 问题 建议默认
D1 是否按 Phase 0→7 全做? ,按序
D2 schema 附加字段用 _joy.schema_version 还是顶层 schema_version _joy 命名空间 更安全
D3 work_rebuild 是否增加 work rebuild sub 并保留旧入口?
D4 本阶段是否允许「仅文档」把 konqi 的 prlctl 写法改成 vm 是,但代码转发必须先在
D5 web execute 是否强制二次确认(已有则加强)?
D6 是否在本方案中处理未提交 hardware tab 分开 PR,不与硬化混提

10. 一句话总结

在不打断 joy web 常驻、三员 AGENTS、神兽 CLAUDE 的前提下,把 joy-cli 从「58 命令功能堆」收成「可版本化、可测试、可转发废弃」的长期 ABI先契约与拆分后加固与清理每一刀都用 golden + 消费者检查单验收。


11. 修订

日期 变更
2026-07-10 首版完整方案:调用面审计 + 影响矩阵 + Phase 07 + 测试门禁

12. 执行记录

日期 内容
2026-07-10 Phase 07 落地golden fixtures、tier/help 同源、_joy.schema_version、dashboard 包拆分、deprecated 转发、web JSONL audit、懒加载、contract 测试pytest 54 绿launchd web/dashboard 回归