Compare commits

..
Author SHA1 Message Date
johnQ cfb393638c feat(req): REQ 连续推进(continuous)模式 + checkpoint
skill-gate / gate (pull_request) Waiting to run
- 新增 req-workflow/skills/references/continuous-mode.md:阶段自动循环、hard/soft 门禁分级、checkpoint schema、恢复协议、停止格式、staging 终点约定
- req / req-workflow SKILL.md 增加 continuous 小节与门禁分级说明
- 版本号、CHANGELOG、docs/skill-routing.md、catalog.json 同步
2026-11-01 09:56:32 +08:00
qiudl ae357a20f7 Merge pull request 'feat(governance): 技能治理节拍落到 launchd + 提案入口模板' (#20) from feat/skill-governance-schedulers into main
skill-gate / gate (push) Waiting to run
2026-10-31 21:52:02 +00:00
johnQ c6ef6820e4 feat(governance): 节拍落到 launchd + 提案入口
skill-gate / gate (pull_request) Waiting to run
- scripts/scheduled-task.sh:daily/weekly/monthly 只做确定性动作,需模型判断的部分生成 queue 文件
- scripts/install-schedulers.sh:装成用户级 launchd(daily 07:20 / weekly 周一 10:00 / monthly 1 日 10:00)
- .gitea issue/PR 模板:新技能提案走同一套 SCOPE 门槛问题
- README 一键部署 2 步 → 4 步;MAINTENANCE 增加定时任务一节与边界说明
2026-11-01 05:50:38 +08:00
qiudl 175c612d35 Merge pull request 'feat(skill): beta 技能 diagnosing-bugs + 月度审阅与 evals 工具' (#19) from feat/diagnosing-bugs-and-review-tools into main
skill-gate / gate (push) Waiting to run
feat(skill): beta 技能 diagnosing-bugs + 月度审阅与 evals 工具
2026-10-31 21:34:04 +00:00
16 changed files with 572 additions and 14 deletions
+2
View File
@@ -0,0 +1,2 @@
blank_issues_enabled: true
contact_links: []
+36
View File
@@ -0,0 +1,36 @@
---
name: 新技能提案
about: 提新技能或技能改动前先过 SCOPE.md 门槛(默认拒绝,能组合就不新增)
title: "[技能] "
labels: skill
---
## 1. 真实失败(必填)
在哪个真实任务/会话里出了问题?跑了什么、期望什么、实际什么。
> 假设性的「这样会更好」不算。说不清就说明还不到提的时候。
## 2. 为什么组合不出来(必填)
用现有哪个技能组合试过?为什么做不到?
> 能组合出来的,改现有技能,不新增。
## 3. 是否重复提案
- [ ] 已读 `.out-of-scope/` 三份拒绝档案,不是重复提案
## 4. 分桶与调用模式
- 初始分桶:`beta`(新技能一律先 beta)
- 调用模式:`model-invoked` / `user-invoked`
- 判定:这件事是不是「人下命令才开始」?是 → `user-invoked`(同时写 `disable-model-invocation: true`)
## 5. 最低交付
- [ ] `evals/evals.json` 3 条:正常路径 / 边界 / 失败恢复
- [ ] `docs/skills/<name>.md` 四段式:What it does / When to reach for it / Common questions / It's working if
- [ ] `docs/skill-routing.md` 已回改
- [ ] `catalog.json` 已 regenerate
- [ ] `CHANGELOG.md` + `plugin.json` 版本号
+24
View File
@@ -0,0 +1,24 @@
## 这个 PR 做了什么
<!-- 一句话,说明改的是哪个技能 / 哪套流程 -->
## SCOPE 门槛
- [ ] 真实失败:说清了在哪个真实任务里出的问题
- [ ] 组合不出来:说明用现有技能组合为什么做不到
- [ ] 已查 `.out-of-scope/`,不是重复提案
## 改动检查
- [ ] 分桶正确(新技能一律 `beta`;`promoted` 需要真实使用记录 + evals 通过)
- [ ] 调用模式正确(`user-invoked` 必须写 `disable-model-invocation: true`)
- [ ] `evals/evals.json` 3 条(正常 / 边界 / 失败恢复)
- [ ] `docs/skills/<name>.md` 四段式
- [ ] `docs/skill-routing.md` 已回改
- [ ] `catalog.json` 已 regenerate(`python3 scripts/generate-catalog.py`)
- [ ] `CHANGELOG.md` + `plugin.json` 版本号已更新
- [ ] 四道门禁通过:`validate-skills.py --strict`、`scan-skill.sh`、`generate-catalog.py --check`、`tests/install-skills.test.sh`
## 人工拍板项(有则写明)
<!-- deprecated 删除、路由变更、promoted 晋升,需要人确认 -->
+6
View File
@@ -25,3 +25,9 @@ __pycache__/
# Node
node_modules/
# 定时任务产出(本机运行产物,不回写仓库;evals 结果报告除外)
reports/skill-health/
reports/monthly/
reports/_scheduler/
reports/evals/queue-*.md
+22
View File
@@ -1,5 +1,19 @@
# Changelog
## 2026-11-01 — REQ 连续推进(continuous)模式
### 新增
- `req-workflow` 新增参考文档 `skills/references/continuous-mode.md`(中文):连续模式的目标与边界、阶段循环(做事 → 留证据 → checkpoint → 自动 `/req next`)、门禁分级(hard / soft)、`.ai-proj/req-<id>.state.json` checkpoint 约定与恢复协议、停止格式、staging 段与冒烟验证、反例。
- `req` 与 `req-workflow` 的 `SKILL.md` 增加 continuous 模式说明:默认自动 `/req next`,自动终点 = staging 部署成功 + 冒烟验证通过;只有 hard 门禁(方案确认、PRD 评审通过、生产发布授权、force、密钥/权限缺失、范围变更)才停下。
### 变更
- 门禁分级落地:讨论摘要确认、部署范围确认改为 soft 门禁(无人值守下按默认策略继续,把「待用户确认」写入 checkpoint / REQ 备注);「评审必须用户确认」「禁止自审批」保持 hard。
- 阶段切换新增 checkpoint 约定:每次 `/req next` 前后写 `.ai-proj/req-<id>.state.json`,新会话先读 checkpoint、复核 evidence 再按 `next_command` 继续。
- 版本:`req-plugin` 2.1.0 → 2.2.0;`req-workflow-plugin` 1.0.0 → 1.1.0。
- `docs/skill-routing.md` 补 `req` / `req-workflow` 的 continuous 模式指引;`catalog.json` 重新生成。
## Unreleased — 2026-10-31
### 新增
@@ -58,5 +72,13 @@
- 新增 beta 技能 `diagnosing-bugs`(难查 bug 诊断纪律:先建红循环再推理),补齐 evals 与四段式文档;路由表同步。
- 新增 `scripts/monthly-review.sh`:一条命令跑月度审阅(覆盖率 / 扫描 / 第三方 / catalog / description 异常)。
### 治理落地:定时任务与提案入口(2026-11-01)
- 新增 `scripts/scheduled-task.sh`:`daily` / `weekly` / `monthly` 三个确定性任务,只跑门禁、扫漂移、生成队列;需要模型判断的部分(真跑 evals、审阅 routing)生成 queue 文件交 agent。
- 新增 `scripts/install-schedulers.sh`:把节拍装成 macOS 用户级 launchd(`com.pipexerp.ai-proj-skill-{daily,weekly,monthly}`),不再依赖会话提醒;支持 `--status` / `--run` / `--uninstall`。
- 新增 `.gitea/issue_template/new-skill.md`、`.gitea/issue_template/config.yaml`、`.gitea/pull_request_template.md`:提案与 PR 走同一套 SCOPE 门槛问题。
- `README.md` 一键部署从 2 步改为 4 步(补 git hooks 与定时任务);`MAINTENANCE.md` 增加「定时任务」一节,写明脚本只做确定性动作的边界。
- `.gitignore` 排除定时任务产出(`reports/skill-health/`、`reports/monthly/`、`reports/_scheduler/`、`reports/evals/queue-*.md`)。
- 新增 `scripts/evals-status.py` 与 `reports/evals/TEMPLATE.md`:evals 覆盖率与回归报告模板。
- `skill-creator` 实战记录 #1:用标准流程新建 `diagnosing-bugs`(beta,待观察后晋升)。
+21
View File
@@ -45,6 +45,27 @@
- 复核覆盖率:`--coverage` 的两项缺口是否按路线图收敛。
- 更新本文件与 `CHANGELOG.md`。
## 定时任务(launchd,2026-11-01 起)
节拍不再挂在「会话提醒」上(会话一断就失效),改成宿主级 launchd:
```bash
./scripts/install-schedulers.sh # 安装(幂等;换机器重跑一次即可复现)
./scripts/install-schedulers.sh --status # 看状态与最近产出
./scripts/install-schedulers.sh --run daily # 立刻跑一次(调试)
./scripts/install-schedulers.sh --uninstall
```
| 任务 | 时间 | 脚本做什么 | 产出 |
| --- | --- | --- | --- |
| `daily` | 每天 07:20 | 漂移 audit + 入库安全扫描 + 覆盖率 | `reports/skill-health/daily-YYYY-MM-DD.md`(`latest.md` 供 7:30 日报直接读) |
| `weekly` | 每周一 10:00 | 算上周改动技能 + 3 个高风险项,生成 evals 抽样队列 | `reports/evals/queue-YYYY-MM-DD.md` |
| `monthly` | 每月 1 日 10:00 | 一条命令跑完月度审阅;1/4/7/10 月附季度治理清单 | `reports/monthly/review-YYYY-MM.md`、`quarterly-YYYY-Qn.md` |
**边界**:脚本只做确定性动作。真跑 evals、审阅 routing 这类需要模型判断的部分,脚本只生成队列文件,由项目经理 Bot 在 7:30 日报里接手执行——分工不写在脚本里就会漏。
日志:`reports/_scheduler/<job>.log`。
## 责任分工
- 项目经理 Bot:执行节奏、出周/月报、盯漂移与门禁。
+9 -1
View File
@@ -69,7 +69,7 @@ PRD 文档存储在思源笔记中,可以导出发送到飞书群,通过飞
- **Codex**([Skills 文档](https://developers.openai.com/codex/skills))或 **Claude Code** 已安装
- **ai-proj 账号 + MCP API Key**:联系管理员获取(Key 格式: `aiproj_pk_xxx`)
### 一键部署(2 步搞定)
### 一键部署(4 步搞定)
```bash
# 1. 克隆仓库
@@ -78,8 +78,16 @@ cd ai-proj-helper
# 2. 默认安装到 Codex 的用户级标准目录 ~/.agents/skills
./install-skills.sh
# 3. 装本地门禁(Gitea Actions 无 runner,commit/push 靠 git hook 兜底)
./scripts/install-git-hooks.sh
# 4. 装技能治理定时任务(macOS launchd:每日漂移检查 / 每周 evals 队列 / 每月审阅)
./scripts/install-schedulers.sh
```
第 3、4 步只对「本仓库的维护者」需要——只装技能给别人用的,跑完第 2 步就可以停。
安装器会复制完整技能目录,包括 `SKILL.md`、references、scripts 和 assets。Codex 会自动发现 `~/.agents/skills` 中的技能;若没有出现,重启 Codex。
Claude Code 用户显式选择 Claude 目标;需要同时配置 MCP 和 marketplace 时运行 `init.sh`:
+5 -5
View File
@@ -7,7 +7,7 @@
"missing_evals": [],
"missing_docs": []
},
"generated_at": "2026-10-31T21:33:50Z",
"generated_at": "2026-11-01T01:55:45Z",
"total": 62,
"counts": {
"promoted/user-invoked": 18,
@@ -710,13 +710,13 @@
{
"name": "req",
"category": "req",
"version": "2.1.0",
"version": "2.2.0",
"status": "promoted",
"invocation": "model-invoked",
"description": "需求工作流管理。用于 /req 命令使用、需求全生命周期管理(创建→PRD→评审→开发→测试→部署→归档)。当用户提到需求管理、/req 命令、REQ-XXX 相关任务时自动激活。",
"description_len": 90,
"path": "skills-req/req-plugin/skills/SKILL.md",
"digest": "193cf871b73faff1",
"digest": "1ba369ef4a51c0c7",
"has_evals": true,
"has_docs": true
},
@@ -801,13 +801,13 @@
{
"name": "req-workflow",
"category": "req",
"version": "1.0.0",
"version": "1.1.0",
"status": "promoted",
"invocation": "model-invoked",
"description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。",
"description_len": 61,
"path": "skills-req/req-workflow-plugin/skills/SKILL.md",
"digest": "87499da3817d162d",
"digest": "74ec85536d97b8c9",
"has_evals": true,
"has_docs": true
},
+2 -1
View File
@@ -15,7 +15,8 @@
| 任务 | 技能 |
| --- | --- |
| 讨论 / 调研 / 对比 | `req`、`req-research`、`req-compare` |
| 讨论 / 调研 / 对比 | `req`、`req-research`、`req-compare`(无人值守推进见 `req-workflow` 的 continuous 模式) |
| 完整流程 / 连续推进 / checkpoint | `req-workflow`(continuous 模式见 references/continuous-mode.md) |
| PRD / 原型 | `req-prd`、`req-prototype` |
| PRD 评审 | `req-review` |
| 设计 / 拆任务 | `req-design`、`dev-arch`、`db-migration` |
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# 安装 / 卸载 / 查看技能治理的定时任务(macOS 用户级 launchd)
#
# 为什么用 launchd 而不是会话提醒:会话提醒随会话消失,节拍就断了;
# launchd 是宿主级,跟仓库绑定,换机器重跑一次即可复现。
#
# 用法:
# ./scripts/install-schedulers.sh 安装(幂等,会先卸载再装)
# ./scripts/install-schedulers.sh --status 看三个任务的加载状态
# ./scripts/install-schedulers.sh --run daily 立刻跑一次(调试用)
# ./scripts/install-schedulers.sh --uninstall 卸载
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TASK="$ROOT/scripts/scheduled-task.sh"
AGENTS="$HOME/Library/LaunchAgents"
LOGDIR="$ROOT/reports/_scheduler"
PREFIX="com.pipexerp.ai-proj-skill"
UID_N="$(id -u)"
JOBS="daily weekly monthly"
SCHED_PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
if command -v node >/dev/null 2>&1; then
SCHED_PATH="$(dirname "$(command -v node)"):$SCHED_PATH"
fi
log() { printf '%s\n' "$*"; }
calendar_xml() {
case "$1" in
daily) printf ' <key>Hour</key><integer>7</integer>\n <key>Minute</key><integer>20</integer>' ;;
weekly) printf ' <key>Weekday</key><integer>1</integer>\n <key>Hour</key><integer>10</integer>\n <key>Minute</key><integer>0</integer>' ;;
monthly) printf ' <key>Day</key><integer>1</integer>\n <key>Hour</key><integer>10</integer>\n <key>Minute</key><integer>0</integer>' ;;
esac
}
write_plist() {
local job="$1" label="$PREFIX-$job" file="$AGENTS/$PREFIX-$job.plist" cal
cal="$(calendar_xml "$job")"
cat > "$file" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>$label</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>$TASK</string>
<string>$job</string>
</array>
<key>WorkingDirectory</key><string>$ROOT</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key><string>$HOME</string>
<key>PATH</key><string>$SCHED_PATH</string>
</dict>
<key>StandardOutPath</key><string>$LOGDIR/$job.log</string>
<key>StandardErrorPath</key><string>$LOGDIR/$job.err.log</string>
<key>RunAtLoad</key><false/>
<key>StartCalendarInterval</key>
<dict>
$cal
</dict>
</dict>
</plist>
PLIST
}
unload_one() {
local label="$PREFIX-$1"
launchctl bootout "gui/$UID_N/$label" >/dev/null 2>&1 || launchctl unload "$AGENTS/$label.plist" >/dev/null 2>&1
}
install() {
mkdir -p "$AGENTS" "$LOGDIR"
chmod +x "$TASK" 2>/dev/null
local job label
for job in $JOBS; do
label="$PREFIX-$job"
write_plist "$job"
unload_one "$job"
if launchctl bootstrap "gui/$UID_N" "$AGENTS/$label.plist" 2>/dev/null; then
log "已加载 $label"
elif launchctl load -w "$AGENTS/$label.plist" 2>/dev/null; then
log "已加载(load) $label"
else
log "加载失败 $label(检查 plist: $AGENTS/$label.plist)"
fi
done
log ""
log "触发时间:daily 每天 07:20 / weekly 每周一 10:00 / monthly 每月 1 日 10:00(1/4/7/10 月附季度清单)"
log "日志:${LOGDIR#$ROOT/}/<job>.log"
log "产出:reports/skill-health/、reports/evals/queue-*.md、reports/monthly/"
}
status() {
local job label
for job in $JOBS; do
label="$PREFIX-$job"
if launchctl print "gui/$UID_N/$label" >/dev/null 2>&1; then
printf '%-8s 已加载 %s\n' "$job" \
"$(launchctl print "gui/$UID_N/$label" 2>/dev/null | grep -E 'state =|last exit code' | tr -d '\t' | tr '\n' ' ')"
else
printf '%-8s 未加载\n' "$job"
fi
done
log ""
log "日志目录:${LOGDIR#$ROOT/}"
log "最近产出:"
ls -1t "$ROOT/reports/skill-health"/daily-*.md "$ROOT/reports/evals"/queue-*.md "$ROOT/reports/monthly"/review-*.md 2>/dev/null | head -3 | sed "s#^$ROOT/# - #"
}
run_now() {
local job="${1:-}"
case "$job" in daily|weekly|monthly) ;; *) log "用法: $0 --run daily|weekly|monthly"; exit 2 ;; esac
mkdir -p "$LOGDIR"
local label="$PREFIX-$job"
if launchctl print "gui/$UID_N/$label" >/dev/null 2>&1; then
launchctl kickstart -k "gui/$UID_N/$label" && log "已触发 $job(看 ${LOGDIR#$ROOT/}/$job.log)"
else
log "任务未加载,直接前台执行"
/bin/bash "$TASK" "$job"
fi
}
uninstall() {
local job label
for job in $JOBS; do
label="$PREFIX-$job"
unload_one "$job"
rm -f "$AGENTS/$label.plist"
log "已卸载 $label"
done
}
case "${1:-install}" in
install|--install) install ;;
--status|status) status ;;
--run) run_now "${2:-}" ;;
--uninstall|uninstall) uninstall ;;
*) log "用法: $0 [install|--status|--run daily|weekly|monthly|--uninstall]"; exit 2 ;;
esac
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env bash
# 技能治理定时任务入口(由 launchd 调用,见 scripts/install-schedulers.sh)
#
# 设计原则:脚本只做「确定性」的事——跑门禁、扫漂移、生成清单。
# 需要模型判断的部分(真跑 evals、人工审阅 routing)不在脚本里做,只生成 queue 文件,
# 由项目经理 Bot 在 7:30 项目日报里接手执行。这样节拍不依赖任何会话的记忆。
#
# 用法:
# ./scripts/scheduled-task.sh daily # 每天 07:20,先于 7:30 项目日报
# ./scripts/scheduled-task.sh weekly # 每周一 10:00
# ./scripts/scheduled-task.sh monthly # 每月 1 日 10:00(1/4/7/10 月附带季度清单)
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT" || exit 1
JOB="${1:-daily}"
DAY="$(date '+%F')"
HEALTH_DIR="$ROOT/reports/skill-health"
EVALS_DIR="$ROOT/reports/evals"
MONTHLY_DIR="$ROOT/reports/monthly"
mkdir -p "$HEALTH_DIR" "$EVALS_DIR" "$MONTHLY_DIR"
log() { printf '[%s] %s\n' "$(date '+%H:%M:%S')" "$*"; }
# ---------- 公共采集:漂移 / 入库扫描 / 覆盖率 / 第三方 ----------
DRIFT_LINE=""; SCAN_LINE=""; COV_LINE=""; THIRD_LINE=""
DRIFT_N="0"; HIGH_N="0"
collect_health() {
local audit
audit="$(./install-skills.sh --audit 2>&1)"
DRIFT_LINE="$(printf '%s\n' "$audit" | grep -E '[0-9]+ 个漂移' | tail -1)"
SCAN_LINE="$(./scripts/scan-skill.sh 2>&1 | grep '扫描完成' | tail -1)"
COV_LINE="$(/usr/bin/python3 scripts/validate-skills.py --coverage 2>&1 | grep '覆盖率' | tail -1)"
THIRD_LINE="$(./scripts/scan-installed.sh 2>&1 | grep '扫描完成' | tail -1)"
DRIFT_N="$(printf '%s' "$DRIFT_LINE" | grep -oE '[0-9]+ 个漂移' | grep -oE '^[0-9]+' || true)"
HIGH_N="$(printf '%s' "$SCAN_LINE" | grep -oE '[0-9]+ 个高危' | grep -oE '^[0-9]+' || true)"
DRIFT_N="${DRIFT_N:-0}"
HIGH_N="${HIGH_N:-0}"
AUDIT_OUT="$audit"
}
# ---------- 每日:漂移 + 入库扫描,写一份可被日报直接读的健康快照 ----------
run_daily() {
local md="$HEALTH_DIR/daily-$DAY.md" todo=0
collect_health
{
echo "# 技能健康 $DAY"
echo
echo "- 漂移:${DRIFT_LINE:-未采集}"
echo "- 入库扫描:${SCAN_LINE:-未采集}"
echo "- 覆盖率:${COV_LINE:-未采集}"
echo "- 第三方技能:${THIRD_LINE:-未采集}"
echo
echo "## 需要处理"
if [ "$DRIFT_N" != "0" ]; then
echo "- 漂移 ${DRIFT_N} 个(未安装 / 版本落后),按 MAINTENANCE「每日」处理"
todo=1
fi
if [ "$HIGH_N" != "0" ]; then
echo "- 入库扫描高危 ${HIGH_N} 个,立即处理,不等日报"
todo=1
fi
[ "$todo" = "0" ] && echo "无"
echo
echo "## 原始输出(audit 尾部)"
echo '```'
printf '%s\n' "$AUDIT_OUT" | tail -15
echo '```'
} > "$md"
cp "$md" "$HEALTH_DIR/latest.md"
log "daily -> ${md#$ROOT/}"
log "漂移 ${DRIFT_N} / 高危 ${HIGH_N} / ${SCAN_LINE:-扫描未采集}"
}
# ---------- 每周:生成 evals 抽样队列(执行仍需模型,见 MAINTENANCE「每周一」)----------
run_weekly() {
local md="$EVALS_DIR/queue-$DAY.md"
local changed changed_total highrisk reports
changed_total="$(git log --since='7 days ago' --name-only --pretty=format: 2>/dev/null \
| grep -oE '^skills-[a-z]+/[^/]+-plugin/' | sort -u | wc -l | tr -d ' ')"
changed="$(git log --since='7 days ago' --name-only --pretty=format: 2>/dev/null \
| grep -oE '^skills-[a-z]+/[^/]+-plugin/' \
| sed -E 's#^skills-[a-z]+/##; s#-plugin/$##' \
| sort | uniq -c | sort -rn | head -5 | awk '{print $2}' | tr '\n' ' ')"
highrisk="dev-coding dev-review req-design"
reports="$(ls "$EVALS_DIR"/*.md 2>/dev/null | grep -vE 'TEMPLATE|queue-' | wc -l | tr -d ' ')"
{
echo "# 本周 evals 抽样队列 $DAY"
echo
echo "现有回归报告:${reports:-0} 份(目标:每周至少 +1 份)"
echo
echo "## 范围"
echo
echo "- 上周改动技能共 ${changed_total:-0} 个,按改动次数取前 5:${changed:-(无)}"
echo "- 高风险固定项:$highrisk"
echo
echo "## 做法(每个技能)"
echo
echo "1. 取 1 条关键用例,跑「有技能 / 无技能」两遍;"
echo "2. 按 rubric 打分,写增量;"
echo "3. 结果写入 \`reports/evals/$DAY-<技能名>.md\`(模板 \`reports/evals/TEMPLATE.md\`)。"
echo
echo "## 判读"
echo
echo "- 连续两次无增量 → 按 \`SCOPE.md\` 评估降级。"
echo "- 全量只在治理大改时做,不做每周全量。"
echo
echo "> 本文件由 launchd 每周一 10:00 自动生成;脚本不调模型,执行由 agent 接手。"
} > "$md"
log "weekly -> ${md#$ROOT/}(报告现有 ${reports:-0} 份)"
}
# ---------- 每月:一条命令出齐审阅项;季度月附治理清单 ----------
run_monthly() {
local mo md mon q
mo="$(date '+%Y-%m')"
mon="$(date '+%m')"
md="$MONTHLY_DIR/review-$mo.md"
{
echo "# 技能月度审阅 $mo"
echo
./scripts/monthly-review.sh 2>&1
} > "$md"
collect_health
{
echo
echo "## 补充:漂移与第三方"
echo
echo "- ${DRIFT_LINE:-漂移未采集}"
echo "- ${THIRD_LINE:-第三方未采集}"
} >> "$md"
log "monthly -> ${md#$ROOT/}"
case "$mon" in
01|04|07|10)
q="$(date '+%Y')-Q$(( (10#$mon - 1) / 3 + 1 ))"
local mq="$MONTHLY_DIR/quarterly-$q.md"
{
echo "# 季度治理复核 $q"
echo
echo "按 MAINTENANCE「每季度首月 1 日 10:30」逐项打勾:"
echo
echo "- [ ] 过一遍 \`docs/skill-routing.md\`:删掉不再用的引用、补上新技能"
echo "- [ ] 清理 \`deprecated\`:满 3 个月且无回滚需求 → 删除插件目录"
echo "- [ ] 复核分桶与调用模式:还有没有命令型技能占着 \`model-invoked\`"
echo "- [ ] 复核覆盖率:\`--coverage\` 两项缺口是否按路线图收敛"
echo "- [ ] 更新 \`MAINTENANCE.md\` 与 \`CHANGELOG.md\`"
} > "$mq"
log "quarterly -> ${mq#$ROOT/}"
;;
esac
}
case "$JOB" in
daily) run_daily ;;
weekly) run_weekly ;;
monthly) run_monthly ;;
*)
echo "用法: $0 daily|weekly|monthly" >&2
exit 2
;;
esac
@@ -1,7 +1,7 @@
{
"name": "req-plugin",
"description": "需求工作流管理入口。用于 /req 命令使用、需求生命周期管理、需求撰写(含草稿门禁)。",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "qiudl"
},
+8 -5
View File
@@ -29,21 +29,24 @@ analysis → design → dev → review → testing → [待部署池] → releas
- **讨论结束后必须输出方案确认摘要**(强制流程:讨论 → 摘要 → 用户确认 → PRD):
1. AI 输出结构化摘要(`## 讨论结论` 章节),`ai-proj req update` 追加到 description 末尾
2. AskUserQuestion 确认:「方案确认通过」或「需要修改」
3. **用户确认后才能开始 PRD 编写,禁止跳过确认**
3. 用户确认后才能开始 PRD 编写;**无人值守/连续模式下「讨论摘要确认」按 soft 门禁处理** — 在 `## 讨论结论` 标注「待用户确认」并写入 checkpoint 后继续,但不得据此自行变更方案或需求范围(方案/范围变更仍是 hard 门禁)
- 需求描述三段式(技术方案写入 PRD,不写在需求中):
1. **需求描述** — 问题背景、现状痛点
2. **预期结果** — 期望达到的效果
3. **验收标准** — 可检查的完成条件(checklist,≥2 条)
- PRD 文档是提交评审的前置条件;代码评审是测试的前置条件
- **force=true 禁止自动使用** — 门禁未通过时必须 AskUserQuestion 确认 + 记录跳过原因
- **评审必须用户确认** — 禁止 AI 自审批
- **force=true 禁止自动使用** — 门禁未通过时必须 AskUserQuestion 确认 + 记录跳过原因(**hard 门禁**)
- **评审必须用户确认** — 禁止 AI 自审批(**hard 门禁**)
- **只有 hard 门禁才必须停下问人** — hard:需求方案确认、PRD 评审通过、生产发布授权、`force` 放行、密钥/权限缺失、需求范围变更;硬门禁未清空时禁止推进下一阶段
- **soft 门禁不停** — 讨论摘要确认、部署范围确认属 soft:无人值守/连续模式下按默认策略继续(摘要写 `## 讨论结论` 后即推进;部署范围按 REQ 关联任务推导),把「待用户确认」写入 checkpoint / REQ 备注,交付时统一列出
- **每次阶段切换写 checkpoint** — 写 `.ai-proj/req-<id>.state.json`(`stage` / `evidence` / `next_command` / `blockers`),新会话先读它再推进;规则见 `req-workflow` 技能的 `references/continuous-mode.md`
- **归档前 AC 逐条验收(Gate 0,强制)** — `/req done` 必须先提取需求描述中的验收标准逐条确认,无 AC 或有未确认项均阻断,用户必须提供证据或说明跳过原因
- **归档前类型化门禁检查** — Gate 0 通过后,`/req done` 再按需求类型(code/skill/ops)动态检查
- **部署是项目级动作**,由 `/req deploy` 统一触发
- **需求完成后必须 git 提交并 push** — commit 格式:`feat(skill): REQ-XXXX 需求标题`
- **操作前先确认实际 ID** — 从 URL 提取 ID(如 `/requirements/897` → ID=897)
- **务实路线关闭也必须补全关联任务** — 每个进度条阶段需创建关联任务
- **阶段内容门禁(防空转)** — `/req next` 时检查关键阶段任务是否有实质内容
- **阶段内容门禁(防空转)** — `/req next` 时检查关键阶段任务是否有实质内容(连续模式下缺内容就补齐文档再推进,不停下等确认)
- **复用盘点先于估工(Gate 5,强制)** — PRD 必须含「现有实现与复用盘点」章节:每个能力点给出**现有实现(file:line)+ 结论(复用 / 改造 / 新增)**;结论=复用/改造的只按「接入差异」估工,结论=新增的必须写「为什么现有实现不能满足」。没有 file:line 证据、或标「未排查」的,**禁止 submit、禁止按全新增估工**;独立复查由非 PRD 写作者用 grep 复核并在 note 留命令与命中结果
- **Harness 环境检测** — `/req dev` 启动开发前,快速检测项目基础设施(`.husky/` 存在?`scripts/check-*.sh` 存在?)。若两者都不存在(Level 0),输出一行提示:「项目无质量护栏,建议先运行 `/harness init`」。检测结果不阻塞开发,仅提示
@@ -149,7 +152,7 @@ PDV 结论: ✅ 全部通过 / ❌ {N}项失败,阻断推进
| **testing** | 测试任务有文档,含测试结果表格,含通过/失败结论 |
| **staging** | 部署任务有文档,含健康检查结果 |
未通过 → AskUserQuestion(补充文档 or 强制跳过+记录原因)
未通过 → AskUserQuestion(补充文档 or 强制跳过+记录原因);continuous 模式下默认「补文档后继续」并写 checkpoint,不停下等待
### 部署门禁(推进到 released 前)
@@ -1,7 +1,7 @@
{
"name": "req-workflow-plugin",
"description": "需求完整工作流。从创建到归档的完整流程、Hook 自动同步、测试环境流程。",
"version": "1.0.0",
"version": "1.1.0",
"author": {
"name": "qiudl"
},
@@ -32,6 +32,19 @@ description: 需求完整工作流。用于从创建到归档的完整流程、H
**每个阶段都有明确的任务、检查点和交付物,防止遗漏。**
## 连续推进(continuous)模式
默认按连续模式推进:每个阶段「做事 → 留证据 → 写 checkpoint → **自动 `/req next`** → 下一阶段」,**不在阶段边界停发问**。适合 Codex 等无人值守 agent。
- **自动终点**:staging 部署成功 + 冒烟验证通过;生产发布属硬门禁,必须人工授权。
- **硬门禁(停)**:需求方案确认、PRD 评审通过、生产发布授权、`force` 放行、密钥/权限缺失、需求范围变更。
- **软门禁(不停)**:讨论摘要确认、部署范围确认 —— 按默认策略继续,把「待用户确认」写入 checkpoint / REQ 备注。
- **checkpoint**:每次阶段切换写 `.ai-proj/req-<id>.state.json`(`stage` / `evidence` / `next_command` / `blockers`);新会话先读它 → 复核 evidence → 从 `next_command` 继续。
- **staging 段**:部署路径读目标项目 `AGENTS.md` 的 staging 约定,不在本技能写死。
- **停止**只输出五段:卡点 / 原因 / 已做到哪 / 下一步命令 / 需要谁确认。
规则细节(门禁分级表、checkpoint schema、恢复协议、反例)见 [references/continuous-mode.md](references/continuous-mode.md)。
## 5 阶段文档
| 阶段 | 文档名 | 技能 |
@@ -0,0 +1,117 @@
# 连续推进(continuous)模式
> 目的:让 Codex 等**无人值守 agent** 能从一个需求一路推进到 staging 验证通过,**只在硬门禁停**。
> 默认即 continuous;只有用户明确要求「一步一步来 / 每步问我」时才退回逐阶段确认。
## 1. 目标与边界
- **自动终点**:一个 REQ 从 `/req new` 自动推进到「**staging 部署成功 + 冒烟验证通过**」,并把证据写进 checkpoint。
- **不在自动范围内**:生产发布(`/req deploy prod`)属**硬门禁**,必须人工授权;`force` 放行、需求范围变更同样必须人工拍板。
- 每个阶段的文档、任务、证据都要真实落盘(REQ 备注 / 任务文档 / checkpoint),**不得凭记忆或口头声称阶段完成**。
- 无人值守不等于无人负责:soft 门禁产生的「待用户确认」项必须在 checkpoint 与交付汇报里显式列出。
## 2. 阶段循环
每个阶段固定四步,**一步不缺**:
```
做事 → 留证据 → 写 checkpoint → 自动 /req next → 下一阶段
```
- **做事**:按阶段职责产出交付物(讨论结论 / PRD / 设计 / 代码 + PR / CR 报告 / 测试报告 / 部署记录)。
- **留证据**:可复核的命令 + 结果(测试输出、CI 链接、健康检查返回、冒烟截图路径),写入 `evidence[]`。
- **写 checkpoint**:更新 `.ai-proj/req-<id>.state.json` 的 `stage` / `evidence` / `next_command`。
- **自动下一步**:直接执行 `/req next`(或等价推进命令),进入下一阶段。
**禁止在阶段边界停**:不允许以「这一阶段做完了,请确认是否继续」结束回合;`/req next` 的门禁信息门禁走默认补齐流程(补文档后继续)。
## 3. 门禁分级
| 级别 | 门禁 | 连续模式下的行为 |
| --- | --- | --- |
| **hard(停)** | 需求方案确认 | 停下,等用户拍板方案 |
| **hard(停)** | PRD 评审通过 | 停下;禁止自审批、禁止代替用户放行 |
| **hard(停)** | 生产发布授权 | 停下,等显式授权才能 `/req deploy prod` |
| **hard(停)** | `force` 放行 | 停下,等用户确认并记录跳过原因 |
| **hard(停)** | 密钥 / 权限缺失 | 停下,说明缺什么、谁能给 |
| **hard(停)** | 需求范围变更 | 停下,范围变更必须重新确认 |
| **soft(不停)** | 讨论摘要确认 | 写 `## 讨论结论` 并追加到需求 description,标注「待用户确认」后**继续**写 PRD |
| **soft(不停)** | 部署范围确认 | 按 REQ 关联任务(`linkRole=deploy` / `implementation`)推导默认部署范围,记录推导依据后**继续** |
**soft 门禁的落地方式**:不停下发问,但必须把「待用户确认」写进两处——checkpoint 的 `blockers[]`(`type: "soft"`)与 REQ 备注;交付时统一列给用户复核。soft 策略只允许「按已有证据推导默认值」,不允许「替用户改变需求范围或方案」。
## 4. checkpoint 约定
文件路径:项目根 `.ai-proj/req-<id>.state.json`(一台机器一份,按需求 id 分文件;`<id>` 为数值 id)。
```json
{
"req_id": 897,
"stage": "testing",
"updated_at": "2026-11-01T10:20:00+08:00",
"evidence": [
{
"stage": "dev",
"command": "go test ./... && /req ci",
"result": "pass",
"artifact": "PR #123 / CI run 4567 全绿"
},
{
"stage": "staging",
"command": "按项目 AGENTS.md 的 staging 部署约定执行",
"result": "deployed",
"artifact": "staging 健康检查 200;冒烟记录 reports/smoke/REQ-897.md"
}
],
"next_command": "/req test",
"blockers": [
{ "type": "soft", "reason": "讨论摘要待用户确认", "needs": "用户 5 分钟复核" }
]
}
```
- `stage`:当前所在 `delivery_stage`(`analysis` / `design` / `dev` / `review` / `integration` / `testing` / `staging` / `released`)。
- `evidence[]`:每项 `stage / command / result / artifact`,`command` 要能原样重跑。
- `next_command`:恢复后要执行的第一条命令,写具体命令而不是「继续推进」。
- `blockers[]`:每项 `type`(`hard` / `soft`)/ `reason` / `needs`;hard 未清空时不得推进。
**恢复协议**(新会话 / 上下文丢失 / 换 agent 时):
1. 先读 checkpoint;**没有就重建**:`ai-proj req get --id <id>` + `ai-proj req tasks --id <id>` 得到真实 `delivery_stage` 与任务状态,再写 checkpoint。
2. **复核 evidence 是否仍成立**:命令能否重跑通过、artifact 是否还在、REQ 阶段是否被人改过。失效的证据视为未完成,重做该阶段,不要沿用。
3. 从 `next_command` 继续;`blockers` 里还有 `type: "hard"` 时按 §5 停下。
4. checkpoint 与 REQ 实际状态冲突时,**以 REQ 状态为准**,修正 checkpoint 后再推进。
## 5. 停止格式
**只有命中 hard 门禁才停**,停下时固定输出五段:
```
卡点:<哪个 hard 门禁>
原因:<触发它的具体事实:报错 / 缺失 / 待授权的动作>
已做到哪:<最后一个有证据的阶段 + 证据位置>
下一步命令:<解除卡点后要执行的第一条命令>
需要谁确认:<用户 / 复核人 / 运维 / 安全>
```
除 hard 门禁外**不得停下发问**;soft 门禁只记录、不阻塞。
## 6. staging 段(自动终点)
- 合并与部署到 staging 的**真实路径不在本技能里写死**:先读目标项目根目录的 `AGENTS.md`,按其「staging 部署约定」执行(分支 / 构建 / 部署触发 / 环境地址 / 验证入口)。
- 项目 `AGENTS.md` 没有 staging 约定,或缺部署权限 → 视为 hard 门禁,按 §5 格式停下。
- **部署成功 ≠ 完成**:必须做冒烟验证——关键页面可达、核心 API 返回正常、主流程走通、日志无新增报错;把命令与结果写入 `evidence[]`(`stage: "staging"`),这一步通过才算**自动终点**。
- 冒烟失败:先自行修复重试;同类失败连续两次且判断需要人拍板(环境权限、外部系统、方案本身有问题)→ 按 hard 门禁停。
- 自动终点之后的一切(生产发布、验收、归档)都需要人工授权,不在 continuous 范围内。
## 7. 反例
| 反例 | 正确做法 |
| --- | --- |
| 每个阶段结束都 AskUserQuestion 等确认 | soft 门禁记入 checkpoint 后继续,只在 hard 门禁停 |
| 没有 evidence 就写「阶段已完成」 | 先跑命令拿到可复核结果,再写 `evidence[]` |
| 跳过 `/req ci` 直接推进到 review | `/req ci` 是 dev → review 的必跑门禁 |
| 把 staging 部署命令写死在技能里 | 读目标项目 `AGENTS.md` 的 staging 部署约定 |
| 把生产发布当成「下一步自动执行」 | 生产发布是 hard 门禁,必须显式授权 |
| 新会话凭记忆接着干 | 先读 checkpoint 并复核 evidence,再按 `next_command` 继续 |
| 换 agent 后重跑一遍已通过的阶段 | 证据仍成立就跳过,只补做失败或缺失的阶段 |