docs(other): 更新 Vibe Coding 配置

This commit is contained in:
xlsea
2026-05-23 10:25:03 +08:00
parent 7eeff925cb
commit 7fec02ff77
132 changed files with 4833 additions and 1519 deletions
+27 -32
View File
@@ -1,37 +1,32 @@
# VibeCoding Kernel v9.2.0
# VibeCoding Athena v9.6 — PACE Router & State Harness
你是一个INTJ性格的工程化 AI 编码助手。用 P.A.C.E. 路由复杂度, 用 RIPER-7 编排阶段, 用 Skills 执行细节。
**双 Agent 模式**: CC 编排全流程, P/E/T 阶段可调用 Codex CLI 协作。Codex 不可用时 100% 降级为 CC 独立。
<!--
本文件目标 altitude: 工程纪律的高信号宪法 (constitution)。
- 不规定操作步骤 → skills/pace/SKILL.md
- 不列插件命令 → skills/athena-setup/SKILL.md
- 不写安装/配置 → README.md
- 行数硬上限 30, 超过 build 阶段 wc -l 失败
-->
## 框架地图
<important>
你是 VibeCoding Athena 工程 Agent。CC 做事,Athena 把关。
- 收任务 → 走 PACE 路由 (Hotfix/Bugfix 直接做, Quick+ 走完整流程)
- 自己跑命令 / 跑测试 / 看输出, 证明工作完成
- 工具失败 → 三次重试附 stderr 报告, 不让用户代执行
- 技术结论 → 必须引用官方文档 / 源码 URL
- 调用 subagent 必须产生真实 tool_use, 不允许伪造完成
</important>
| 类别 | 文件 | 数量 |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| Workflows | pace.md, riper-7.md | 2 |
| Skills | brainstorm, plan-first, code-review, verification, debugging, kaizen, security-review, context7, e2e, codex-comm, codex-review, reflexion, finish-branch | 13 |
| Review Templates | api-review, frontend-review, infra-review, general-review | 4 |
| Hooks | context-loader, delivery-gate, pre-bash, post-edit, stop-failure, tdd-check | 6 |
| Commands | vibe-dev, vibe-status, vibe-resume, vibe-init, vibe-codex | 5 |
| Agents | builder, validator, explorer | 3 |
| State Templates | session, doing, design, plan, conventions, quality, lessons | 7 |
## 铁律 (9 条)
## 启动流程
1. **设计先行** — 未确认不写代码 (Hotfix/Bugfix 例外)
2. **TDD 强制** — 先测试后实现
3. **Sisyphus** — tasks 全完成才进审查
4. **Review 强制** — Feature+ 至少一次交叉审查
5. **文档即真相** — 阶段转换前 .ai_state/ 必须同步, 单一入口 `.ai_state/_index.md`
6. **完成度证据** — 报告"完成"必须附 tool_use ID 或命令输出片段
7. **出处优先** — API 形态 / 配置字段 / 协议格式必须引用官方文档或源码 URL
8. **索引先行** — 进入决策先读 `.ai_state/_index.md`, 禁止 glob 全目录扫描
9. **Hook 是进化器** — 在 Stop 时反思并写 `.ai_state/details/proposals.md`
1. SessionStart → context-loader.cjs → 检测 .ai_state/ → 恢复或初始化
2. 读 conventions.md (含 "Agent 易犯错误" 段) → 输出提醒
3. 评估任务 → P.A.C.E. 路由 → RIPER-7 执行
## 关键规则
- 设计未确认前不写代码 (R₀/R/D 阶段)
- TDD: 先写测试再写实现 (E 阶段)
- Sisyphus: plan.md 所有 [ ] 完成才能停 (E 阶段)
- Reflexion: 每个 Task 完成后自我反思再 Micro-review (E 阶段)
- 4 级 Quality Gate: PASS / CONCERNS / REWORK / FAIL (交付前)
- 如安装了 superpowers, 其 skills 细节优先于同名 VibeCoding skills, 但 PACE/RIPER-7 仍主控
## MCP 工具 (按需)
- cunzhi (寸止): 人工确认检查点
- sequential-thinking: 复杂推理
- context7 CLI: 库文档查询 (`npx ctx7 resolve {库名}`)
设计原则: SRP · OCP · LSP · ISP · DIP · DRY · KISS · 第一性原理 · 先 WHY 后 HOW
-13
View File
@@ -1,13 +0,0 @@
---
name: builder
model: sonnet
description: 实现代码 + 编写测试 (TDD)
isolation: worktree
effort: high
maxTurns: 30
---
你是 builder agent。职责:
1. 读取分配的 Task 文本
2. TDD: 先写测试 (RED) → 实现代码 (GREEN) → 重构 (REFACTOR)
3. 遵循 conventions.md 编码规范
4. 完成后更新 plan.md: [ ] → [x]
+54
View File
@@ -0,0 +1,54 @@
---
name: evaluator
description: >
代码审查评分员. PACE review 阶段调用, 读 _index.md 和 review 报告输出 VERDICT.
tools: Read, Glob, Grep, Bash
model: opus
---
# Evaluator Subagent (v9.6)
## 输入
- 当前 `.ai_state/_index.md` (path/stage/sprint/active_goal)
- `.ai_state/details/reviews/sprint-N.md` (本 sprint 审查报告)
- `.ai_state/details/design.md` (设计 vs 实际)
- `git diff` 本 sprint 提交
## 评分维度 (1-5 分)
```
Functionality (25%) // 是否实现了 design.md 中所有 MUST 项
Spec Compliance (25%) // 是否符合 design.md 的约束 (技术栈/接口/不做什么)
Boundary (15%) // 是否越出 File Structure Plan 边界
Craft (15%) // 代码质量 (命名/SRP/无 dead code)
Robustness (20%) // 边界处理/错误恢复/测试覆盖
```
均分 = F×0.25 + SC×0.25 + B×0.15 + C×0.15 + R×0.20
## VERDICT 规则
| 条件 | 判定 |
|---|---|
| 均分 ≥ 4.0 且**所有维度 ≥ 3** | PASS |
| 均分 ≥ 3.0 但某维度 = 2 | CONCERNS |
| 均分 < 3.0 或任一维度 = 1 | REWORK |
| 多个维度 = 1 或 Boundary 大幅越界 / 安全严重问题 | FAIL |
## 输出要求
- **每个维度评分必须附代码行号级证据** (file.ext:LN, 不是模糊"看起来不错")
- **不允许 Halo Effect**: 一个维度的分数不影响其他维度的独立评分顺序
- **不阻止 PASS 也不强制 CONCERNS**, 根据证据决定
## 协议约束
- 只读 (Read/Glob/Grep), 禁止 Edit/Write
- 输出预算 ≤ 2000 tokens (Anthropic 多 agent 经验: subagent 必须紧凑)
- 不读 .ai_state/.legacy-v9.5/ (那是迁移备份)
- 不要 glob 整个 .ai_state/, 按 _index.md.pointers 跳转
## 输出格式
直接覆盖写回 `.ai_state/details/reviews/sprint-N.md` 的 "## Step 6: @evaluator 评分" 段和 "## VERDICT:" 段。
-11
View File
@@ -1,11 +0,0 @@
---
name: explorer
model: haiku
description: 代码库调研 + 文档查询 (只读)
effort: medium
maxTurns: 15
---
你是 explorer agent。职责:
1. 搜索项目中与任务相关的代码
2. 查询依赖库文档 (context7)
3. 输出调研结果 (不修改任何文件)
+61
View File
@@ -0,0 +1,61 @@
---
name: generator
description: >
代码实现者 (隔离 worktree). 接 task spec, 实现 + TDD, 输出可被 reviewer 验证的 commit.
tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep
model: opus
isolation: worktree
---
# Generator Subagent (v9.6)
## 输入
- 单个或一组相关 task (来自 `tasks-current.md`)
- 项目 design.md (设计)
- `_index.md` (tech_stack, test_cmd, lint_cmd, conventions, gotchas)
## 工作流
1. **Get-bearings**:
- 读 `.ai_state/_index.md`
- 读 `.ai_state/details/design.md` 对应模块段
- 读 `.ai_state/details/tasks-current.md` 当前 task 的 Boundary/Depends
2. **TDD 强制** (铁律 2):
- 先写测试 (单测或集成测试, 视 task 性质)
- 跑测试确认 RED
- 实现
- 跑测试确认 GREEN
3. **Boundary 守则**:
- 仅修改 task 的 Boundary 段标注的文件路径
- 越界 → 停, 报告主 agent (可能需要升路径)
4. **执行 lint_cmd**:
- 失败 → 修
5. **更新文档**:
- `tasks-current.md` 勾选完成项 ([ ] → [x])
- `progress.md` 追加一行 (YYYY-MM-DD HH:MM [path/stage/sprint] Task N done: ...)
- design.md 不动 (除非发现 design 错; 那种情况报告主 agent 不要自己改)
6. **Commit**:
- `git add -p` 仅添加 Boundary 内文件
- `git commit -m "<task short summary>"`
7. **报告**:
- 输出 commit hash + 测试通过的命令输出片段 (铁律 6)
- 失败 → 完整 stderr (不允许 "I cannot")
## 隔离
- `isolation: worktree` (CC v2.1.121+): 自动创建 git worktree, 不污染主分支
- worktree.baseRef = "head" (settings.json 已配): 从当前 HEAD 创建
## 输出预算
≤ 2000 tokens (Anthropic 多 agent 经验). 详细日志写文件不写回主 agent.
## 失败协议
工具失败 → 三轮重试 (铁律 7):
1. 读 stderr, 尝试明显修复
2. 换参数/换工具
3. 仍失败 → 完整 stderr + exit code + 已尝试方案, 报告主 agent
**禁止**: "请你手动跑", "我没有权限" (没有就申请, 不是放弃).
-12
View File
@@ -1,12 +0,0 @@
---
name: validator
model: sonnet
description: 代码审查 + Plan Review
isolation: worktree
effort: high
maxTurns: 20
---
你是 validator agent。职责:
1. Plan Review: 审查 plan.md, 找漏洞/模糊/不可执行
2. Code Review: 对标 design.md spec + conventions.md
3. 输出审查意见 (严格, 不放水)
-15
View File
@@ -1,15 +0,0 @@
---
name: vibe-codex
description: 快捷调用 Codex
---
# /vibe-codex $INSTRUCTION
快捷方式: 直接调用 codex-comm skill 发送指令给 Codex。
1. 检测 Codex 可用性
2. 构建上下文 (git diff + 相关文件)
3. 过滤敏感信息
4. execMode(instruction, { sandbox: 'read-only' })
5. 展示 Codex 回复
如果 Codex 不可用 → 输出提示, 不执行。
-14
View File
@@ -1,14 +0,0 @@
---
name: vibe-dev
description: 启动开发工作流
---
# /vibe-dev $TASK
1. 初始化 .ai_state/ (如不存在, 从模板复制)
2. P.A.C.E. 路由 → 确定路径
3. 写入 .ai_state/session.md: 任务描述 + 路径 + 时间戳
4. 执行 RIPER-7 对应阶段
**注意**: 如果已有进行中的任务 (.ai_state/doing.md 有 [ ]), 先询问用户是否要切换任务。
等效于在会话中说 "开始开发: $TASK"
-11
View File
@@ -1,11 +0,0 @@
---
name: vibe-init
description: 首次设置
---
# /vibe-init
1. 创建 .ai_state/ 目录 (从 .claude/templates/ai-state/ 复制)
2. 创建 .gitignore (如不存在)
3. 检测项目技术栈 → 写入 conventions.md
4. 检测 Codex 可用性 → 输出状态
5. 输出: "VibeCoding 已初始化, 用 /vibe-dev 开始开发"
-10
View File
@@ -1,10 +0,0 @@
---
name: vibe-resume
description: 从断点恢复
---
# /vibe-resume
1. 读 .ai_state/session.md 确定断点
2. 读 .ai_state/doing.md 确定当前步骤
3. 从断点继续 RIPER-7 流程
4. 如果是 E 阶段 → 从未完成的 Task 继续 Sisyphus
-11
View File
@@ -1,11 +0,0 @@
---
name: vibe-status
description: 显示当前会话状态
---
# /vibe-status
读取并展示:
1. .ai_state/session.md → 当前任务 + 路径 + 阶段
2. .ai_state/doing.md → 当前执行中的步骤
3. .ai_state/plan.md → 进度 (已完成/总数)
4. Codex 状态: 可用? serve 运行中?
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostCompact hook v9.6
// 协议: hookSpecificOutput.{hookEventName: "PostCompact", additionalContext}
// 参考: https://code.claude.com/docs/en/hooks#postcompact
//
// 设计:
// 读 compact-snapshot.md, 注入 _index.md frontmatter 摘要
// 提示 model: 详细内容按 _index.md.pointers lazy load, 不要 glob 全目录 (铁律 8)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const SNAPSHOT_PATH = path.join(STATE_DIR, 'compact-snapshot.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
if (!fs.existsSync(SNAPSHOT_PATH)) {
process.exit(0); return;
}
try {
const snapshot = fs.readFileSync(SNAPSHOT_PATH, 'utf8');
const fmMatch = snapshot.match(/---\n([\s\S]*?)\n---/);
if (!fmMatch) { process.exit(0); return; }
const additionalContext = `[Athena PostCompact 恢复]
上次 compact 前的项目状态 (_index.md frontmatter 快照):
\`\`\`yaml
${fmMatch[1].slice(0, 1500)}
\`\`\`
详细内容**按需** lazy load:
- progress 详情 → 按 pointers.latest_progress 读 progress.md 尾部
- lessons → 命中主题再按 pointers.latest_lesson 跳段
- 完整 _index.md → \`.ai_state/_index.md\`
⚠️ 禁止 glob 整个 .ai_state/ (铁律 8 索引先行)`;
process.stderr.write(`[compact-restore] injected ${additionalContext.length} chars\n`);
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PostCompact',
additionalContext
}
}));
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'compact-restore',
chars: additionalContext.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {
process.stderr.write(`[compact-restore] failed: ${e.message}\n`);
}
process.exit(0);
});
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PreCompact hook v9.6
// 协议: 不阻断, 写文件做副作用
// 参考: https://code.claude.com/docs/en/hooks#precompact
//
// v9.6 减薄设计 (L2.C):
// 旧版 v9.5 快照整个 .ai_state/{tasks,design,progress,lessons,handoff}.md 多个文件
// v9.6 仅快照 _index.md frontmatter (≤30 行), context 利用率提升数倍
// detail/* 内容在 PostCompact 时按需 lazy load (按 pointers 跳转)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const SNAPSHOT_PATH = path.join(STATE_DIR, 'compact-snapshot.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const trigger = event.trigger || 'unknown'; // "manual" | "auto"
if (!fs.existsSync(INDEX_PATH)) {
process.stderr.write('[compact-snapshot] _index.md not found, skip\n');
process.exit(0); return;
}
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) {
process.stderr.write('[compact-snapshot] _index.md frontmatter missing, skip\n');
process.exit(0); return;
}
const ts = new Date().toISOString();
const snapshot = `# Athena Compact Snapshot (${trigger})
# Saved at: ${ts}
# 仅快照 _index.md frontmatter (≤30 行). 详细内容按 pointers 在 PostCompact 后 lazy load.
---
${fmMatch[1]}
---
`;
fs.writeFileSync(SNAPSHOT_PATH, snapshot);
process.stderr.write(`[compact-snapshot] saved (${trigger}, ${snapshot.length} chars)\n`);
const trace = JSON.stringify({
ts, hook: 'compact-snapshot', trigger,
chars: snapshot.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {
process.stderr.write(`[compact-snapshot] failed: ${e.message}\n`);
}
process.exit(0);
});
-37
View File
@@ -1,37 +0,0 @@
// VibeCoding v9.2.0 — SessionStart: 检测状态 + 恢复 + 提醒
'use strict';
const fs = require('fs');
const path = require('path');
const STATE_DIR = path.join(process.cwd(), '.ai_state');
try {
if (fs.existsSync(STATE_DIR)) {
// 恢复: 读取关键状态文件
const files = ['session.md', 'doing.md', 'plan.md', 'design.md'];
const found = files.filter(f => fs.existsSync(path.join(STATE_DIR, f)));
if (found.length > 0) {
console.log(`[VibeCoding] 恢复会话: ${found.join(', ')} 已加载`);
// 检查未完成任务
const planFile = path.join(STATE_DIR, 'plan.md');
if (fs.existsSync(planFile)) {
const plan = fs.readFileSync(planFile, 'utf8');
const unchecked = (plan.match(/^- \[ \]/gm) || []).length;
if (unchecked > 0) console.log(`[VibeCoding] ⚠ plan.md 有 ${unchecked} 个未完成任务`);
}
}
// Agent 易犯错误提醒
const convFile = path.join(STATE_DIR, 'conventions.md');
if (fs.existsSync(convFile)) {
const conv = fs.readFileSync(convFile, 'utf8');
const errSection = conv.match(/## Agent 易犯错误\n([\s\S]*?)(?=\n##|$)/);
if (errSection && errSection[1].trim()) {
console.log('[VibeCoding] 🔔 Agent 易犯错误提醒:');
console.log(errSection[1].trim().split('\n').slice(0, 5).join('\n'));
}
}
} else {
console.log('[VibeCoding] 新会话: .ai_state/ 不存在, 首次任务时自动初始化');
}
} catch (e) {
console.log('[VibeCoding] context-loader 警告: ' + e.message);
}
Regular → Executable
+175 -73
View File
@@ -1,86 +1,188 @@
// VibeCoding v9.2.0 — Stop: 4级 Quality Gate
#!/usr/bin/env node
'use strict';
// VibeCoding Athena Stop hook (delivery-gate) v9.6
// 协议:
// - block: stdout JSON { decision: "block", reason: "..." }
// - pass: exit 0 无输出
// 参考: https://code.claude.com/docs/en/hooks#stop
//
// v9.6 设计:
// 1. 只读 _index.md 不读单独文件 (铁律 8)
// 2. 适配 CC v2.1.x 的 Stop hook block-cap=8 (CLAUDE_CODE_STOP_HOOK_BLOCK_CAP)
// hook 自身计数 block 次数, 接近 8 时 warn 而非 block
// 3. 当平台支持 /goal (CC v2.1.139+) 时, 让位给 /goal evaluator, 仅作 fallback
// 4. CONCERNS 时仅 systemMessage 不阻断
//
// stop_hook_active 防递归: CC 已经在嵌套 Stop hook 时设置该字段为 true
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
process.on('uncaughtException', function(e) {
process.stderr.write('[delivery-gate] ERROR: ' + e.message + '\n');
process.exit(0); // 脚本错误不阻断
});
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const HOME = process.env.HOME || require('os').homedir();
const COUNTER_PATH = path.join(HOME, '.claude', 'state', 'athena-block-counter.json');
if (process.env.VIBECODING_HOOKS_DISABLED === '1') { process.exit(0); }
const BLOCK_CAP_SAFE = 6; // 留 2 次冗余给 CC 的硬 cap 8
const STATE_DIR = path.join(process.cwd(), '.ai_state');
const severity = { fail: [], rework: [], concerns: [] };
try {
if (!fs.existsSync(STATE_DIR)) { process.exit(0); } // 无状态 = Path A, 放行
const planFile = path.join(STATE_DIR, 'plan.md');
const qualityFile = path.join(STATE_DIR, 'quality.md');
// ── FAIL 级: 硬约束 ──
// 未完成任务
if (fs.existsSync(planFile)) {
const plan = fs.readFileSync(planFile, 'utf8');
const unchecked = (plan.match(/^- \[ \]/gm) || []).length;
if (unchecked > 0) severity.fail.push(`plan.md 有 ${unchecked} 个未完成任务`);
}
// 缺 quality.md (有 plan 但没 quality = T 阶段未执行)
if (fs.existsSync(planFile) && !fs.existsSync(qualityFile)) {
severity.fail.push('缺少 quality.md — T 阶段验证未执行');
}
// 硬编码密钥
function trace(event) {
try {
const secrets = execSync(
"git diff --cached -U0 2>/dev/null | grep -iE '(password|secret|api_key|token)\\s*[:=]\\s*.' || true",
{ encoding: 'utf8' }
);
if (secrets.trim()) severity.fail.push('疑似硬编码密钥');
} catch {}
const line = JSON.stringify({ ts: new Date().toISOString(), hook: 'delivery-gate', ...event }) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), line);
} catch (e) {}
}
// ── REWORK 级: 源码无测试 ──
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
// 防递归 (官方字段)
if (event.stop_hook_active) { process.exit(0); return; }
// 跳过 subagent
if (event.agent_type && event.agent_type !== 'main') { process.exit(0); return; }
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
let fm = '';
try {
const diff = execSync('git diff --cached --name-only 2>/dev/null || git diff --name-only 2>/dev/null', { encoding: 'utf8' });
const codeExts = /\.(ts|tsx|js|jsx|py|go|rs|java|rb)$/;
const testPattern = /\.test\.|\.spec\.|__test__|__spec__|_test\.|tests\//;
const configPattern = /config|\.env|\.json$|\.yaml$|\.yml$|\.toml$|\.md$|\.txt$/i;
const srcFiles = diff.split('\n').filter(f =>
f.match(codeExts) && !f.match(testPattern) && !f.match(configPattern)
);
const testFiles = diff.split('\n').filter(f => f.match(testPattern));
if (srcFiles.length > 0 && testFiles.length === 0) {
if (srcFiles.length > 2) {
severity.rework.push(`${srcFiles.length} 个源码文件修改但无对应测试`);
} else {
severity.concerns.push(`${srcFiles.length} 个源码文件修改但无测试 (数量少, 标注)`);
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const m = content.match(/^---\n([\s\S]*?)\n---/);
if (!m) { process.exit(0); return; }
fm = m[1];
} catch (e) { process.exit(0); return; }
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const getBool = k => {
const m = fm.match(new RegExp('^ ' + k + ': (true|false)$', 'm'));
return m ? m[1] === 'true' : false;
};
const pathName = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const tasks_pending = getNum('tasks_pending');
const goal_supported = getBool('goal_supported');
const active_goal = getStr('active_goal');
// 仅在 review 阶段 + 非 Hotfix 时介入
if (!sprint || !stage || pathName === 'Hotfix' || pathName === 'Bugfix' || stage !== 'review') {
process.exit(0); return;
}
// 平台支持 /goal 且用户已设置 active_goal → 让位给 /goal evaluator
if (goal_supported && active_goal) {
process.stderr.write('[delivery-gate] defer to /goal evaluator (active goal detected)\n');
trace({ action: 'defer', reason: 'goal-active', sprint });
process.exit(0); return;
}
const needsExtReview = ['Feature', 'Refactor', 'System'].includes(pathName);
const issues = [];
// 1. tasks 全完成
if (tasks_pending > 0) {
issues.push(`${tasks_pending} Task 未完成`);
}
// 2. review report 存在
const reviewFile = path.join(STATE_DIR, 'details', 'reviews', `sprint-${sprint}.md`);
let rc = '';
try {
rc = fs.readFileSync(reviewFile, 'utf8');
} catch (e) {
issues.push('审查报告不存在');
}
// 3. Feature+ 外部审查
if (needsExtReview && rc &&
!/\/codex:review|\/codex:adversarial|reviewer|ecc-agentshield|codex unavailable/i.test(rc)) {
issues.push('无外部审查记录');
}
// 4. 测试通过记录
if (rc && !/test|测试|pass|通过|✅/i.test(rc)) {
issues.push('无测试通过记录');
}
// 5. VERDICT
let verdict = '';
if (rc) {
const m = rc.match(/VERDICT:\s*(PASS|CONCERNS|REWORK|FAIL)/i);
if (m) {
verdict = m[1].toUpperCase();
if (verdict === 'REWORK') issues.push('VERDICT=REWORK');
else if (verdict === 'FAIL') issues.push('VERDICT=FAIL');
else if (verdict === 'CONCERNS') {
process.stderr.write('[delivery-gate] CONCERNS: 建议修复后重新评分\n');
}
}
} catch {}
}
} catch (e) {
if (issues.length > 0) {
// 检查 block 次数, 接近 cap 时降级 systemMessage
fs.mkdirSync(path.dirname(COUNTER_PATH), { recursive: true });
let counter = {};
try { counter = JSON.parse(fs.readFileSync(COUNTER_PATH, 'utf8')); } catch (e) {}
const sessionId = event.session_id || 'unknown';
counter[sessionId] = (counter[sessionId] || 0) + 1;
try { fs.writeFileSync(COUNTER_PATH, JSON.stringify(counter)); } catch (e) {}
const count = counter[sessionId];
process.stderr.write(`[delivery-gate] block #${count}/${BLOCK_CAP_SAFE} ${pathName}/${stage}: ${issues.join(', ')}\n`);
trace({ action: 'block', count, pathName, stage, sprint, issues });
if (count >= BLOCK_CAP_SAFE) {
// 接近 cap, 改为 systemMessage 避免触发 CC 的 force-kill
process.stdout.write(JSON.stringify({
systemMessage: `[Athena] 已连续 block ${count} 次, 建议手动处理: ${issues.join('; ')} (剩余尝试: ${8 - count})`
}));
} else {
process.stdout.write(JSON.stringify({
decision: 'block',
reason: `[Athena delivery-gate] 阻断:\n${issues.map(i => '• ' + i).join('\n')}\n\n修复后再交付 (block ${count}/${BLOCK_CAP_SAFE}).`
}));
}
process.exit(0); return;
}
// 通过, 重置计数
try {
let counter = JSON.parse(fs.readFileSync(COUNTER_PATH, 'utf8'));
delete counter[event.session_id];
fs.writeFileSync(COUNTER_PATH, JSON.stringify(counter));
} catch (e) {}
if (verdict === 'PASS') {
// 检查是否做了 compound
const lessonsText = (() => {
try { return fs.readFileSync(path.join(STATE_DIR, 'details', 'lessons.md'), 'utf8'); }
catch (e) { return ''; }
})();
const compounded = lessonsText.includes(`Sprint ${sprint}`);
if (!compounded) {
const msg = `Sprint ${sprint} 通过但 details/lessons.md 无条目, 建议 /compound 沉淀经验`;
process.stderr.write(`[delivery-gate] PASS ${pathName}/${stage} · ${msg}\n`);
trace({ action: 'soft-warn', pathName, stage, sprint, reason: 'no compound' });
process.stdout.write(JSON.stringify({ systemMessage: `[Athena] ${msg}` }));
} else {
process.stderr.write(`[delivery-gate] PASS ${pathName}/${stage} · lessons ✓\n`);
trace({ action: 'pass', pathName, stage, sprint });
}
} else {
process.stderr.write(`[delivery-gate] 放行 ${pathName}/${stage}\n`);
trace({ action: 'pass', pathName, stage, sprint, verdict });
}
process.exit(0);
}
// ── 输出结果 ──
// Stop hook 语义: exit 0 = 放行停止, exit 2 = 阻断停止(强制继续)
// stdout 输出会作为 context 注入 Claude
const allIssues = [...severity.fail, ...severity.rework, ...severity.concerns];
if (severity.fail.length > 0) {
process.stderr.write(`[delivery-gate] ❌ FAIL — 严重问题, 必须修复:\n${severity.fail.map(i => ` ✗ ${i}`).join('\n')}\n`);
if (severity.rework.length) process.stderr.write(` + REWORK: ${severity.rework.join(', ')}\n`);
if (severity.concerns.length) process.stderr.write(` + CONCERNS: ${severity.concerns.join(', ')}\n`);
process.exit(2); // 阻断: 不让停
}
if (severity.rework.length > 0) {
process.stderr.write(`[delivery-gate] 🔧 REWORK — 需要修复:\n${severity.rework.map(i => ` ✗ ${i}`).join('\n')}\n`);
if (severity.concerns.length) process.stderr.write(` + CONCERNS: ${severity.concerns.join(', ')}\n`);
process.exit(2); // 阻断: 不让停
}
if (severity.concerns.length > 0) {
// CONCERNS: 放行但输出警告作为 context
process.stdout.write(`[delivery-gate] ⚠ CONCERNS (已放行, 建议修复):\n${severity.concerns.map(i => ` △ ${i}`).join('\n')}\n`);
process.exit(0); // 放行: 但警告已注入
}
process.exit(0); // PASS
});
+175
View File
@@ -0,0 +1,175 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostToolUse index-updater v9.6 ★新增
// 协议: 无输出即放行 (PostToolUse 不阻断)
// 参考: https://code.claude.com/docs/en/hooks#posttooluse
//
// 设计 (铁律 5 文档即真相 + 铁律 8 索引先行):
// 1. 检测 tool_input.file_path 是否在 .ai_state/details/
// 2. 若是 → 重新扫描 details/ 计算 counts/fingerprints/pointers
// 3. 原子写 _index.md (写 .tmp 后 rename)
// 4. 避免热路径: 同一秒内对同一文件多次触发只更新一次 (debounce by mtime)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const DETAILS_DIR = path.join(STATE_DIR, 'details');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
// 检测 file_path 是否在 details/
const filePath = (event.tool_input && (event.tool_input.file_path || event.tool_input.notebook_path)) || '';
if (!filePath || !filePath.includes('.ai_state/details/')) {
process.exit(0); return;
}
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
try {
updateIndex();
} catch (e) {
process.stderr.write(`[index-updater] failed: ${e.message}\n`);
}
process.exit(0);
});
function readFileSafe(p) {
try { return fs.readFileSync(p, 'utf8'); } catch (e) { return null; }
}
function mtime(p) {
try { return Math.floor(fs.statSync(p).mtimeMs); } catch (e) { return 0; }
}
function countMatches(text, regex) {
if (!text) return 0;
return (text.match(regex) || []).length;
}
function lastSectionLine(text, headPrefix) {
if (!text) return 0;
const lines = text.split('\n');
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].startsWith(headPrefix)) return i + 1;
}
return 0;
}
function lastNonEmptyLine(text) {
if (!text) return 0;
const lines = text.split('\n');
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].trim() && !lines[i].startsWith('<!--') && !lines[i].startsWith('-->')) return i + 1;
}
return 0;
}
function updateIndex() {
// 读 _index.md
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (!fmMatch) {
process.stderr.write('[index-updater] _index.md frontmatter parse failed\n');
return;
}
let fm = fmMatch[1];
const body = fmMatch[2];
// 扫描 details/
const tasksText = readFileSafe(path.join(DETAILS_DIR, 'tasks-current.md'));
const progressText = readFileSafe(path.join(DETAILS_DIR, 'progress.md'));
const lessonsText = readFileSafe(path.join(DETAILS_DIR, 'lessons.md'));
const designText = readFileSafe(path.join(DETAILS_DIR, 'design.md'));
const proposalsText = readFileSafe(path.join(DETAILS_DIR, 'proposals.md'));
// counts
const tasks_pending = countMatches(tasksText, /^- \[ \]/gm);
const tasks_done = countMatches(tasksText, /^- \[x\]/gm);
const tasks_blocked = countMatches(tasksText, /^- \[!\]/gm);
const lessons_lines = countMatches(lessonsText, /^## /gm);
// progress entries: 非空非注释非标题行
let progress_entries = 0;
if (progressText) {
progress_entries = progressText.split('\n')
.filter(l => l.trim() && !l.startsWith('<!--') && !l.startsWith('-->') && !l.startsWith('#'))
.length;
}
// reviews_count
let reviews_count = 0;
let latest_review = '';
try {
const files = fs.readdirSync(path.join(DETAILS_DIR, 'reviews'))
.filter(f => f.match(/^sprint-\d+\.md$/));
reviews_count = files.length;
if (files.length > 0) {
const sorted = files.sort((a, b) => {
const na = parseInt(a.match(/\d+/)[0], 10);
const nb = parseInt(b.match(/\d+/)[0], 10);
return na - nb;
});
latest_review = `details/reviews/${sorted[sorted.length - 1]}`;
}
} catch (e) {}
// pointers
const latest_progress = progressText ? `details/progress.md#L${lastNonEmptyLine(progressText)}` : '';
const latest_lesson = lessonsText ? `details/lessons.md#L${lastSectionLine(lessonsText, '## ')}` : '';
const latest_proposal = proposalsText ? `details/proposals.md#L${lastSectionLine(proposalsText, '## ')}` : '';
// fingerprints
const tasks_mtime = mtime(path.join(DETAILS_DIR, 'tasks-current.md'));
const design_mtime = mtime(path.join(DETAILS_DIR, 'design.md'));
const progress_mtime = mtime(path.join(DETAILS_DIR, 'progress.md'));
const lessons_mtime = mtime(path.join(DETAILS_DIR, 'lessons.md'));
// 替换 frontmatter 字段 (保留其他字段不动)
function replaceField(yaml, key, value, isNumeric) {
const re = new RegExp(`(^ ${key}: ).*$`, 'm');
const val = isNumeric ? value : `"${value}"`;
if (re.test(yaml)) return yaml.replace(re, `$1${val}`);
return yaml; // 不存在不创建, 等用户/init 加
}
fm = replaceField(fm, 'tasks_pending', tasks_pending, true);
fm = replaceField(fm, 'tasks_done', tasks_done, true);
fm = replaceField(fm, 'tasks_blocked', tasks_blocked, true);
fm = replaceField(fm, 'lessons_lines', lessons_lines, true);
fm = replaceField(fm, 'progress_entries', progress_entries, true);
fm = replaceField(fm, 'reviews_count', reviews_count, true);
fm = replaceField(fm, 'latest_progress', latest_progress, false);
fm = replaceField(fm, 'latest_review', latest_review, false);
fm = replaceField(fm, 'latest_lesson', latest_lesson, false);
fm = replaceField(fm, 'latest_proposal', latest_proposal, false);
fm = replaceField(fm, 'tasks_mtime', tasks_mtime, true);
fm = replaceField(fm, 'design_mtime', design_mtime, true);
fm = replaceField(fm, 'progress_mtime', progress_mtime, true);
fm = replaceField(fm, 'lessons_mtime', lessons_mtime, true);
const newContent = `---\n${fm}\n---\n${body}`;
// 原子写入
const tmpPath = INDEX_PATH + '.tmp';
fs.writeFileSync(tmpPath, newContent);
fs.renameSync(tmpPath, INDEX_PATH);
process.stderr.write(`[index-updater] _index.md updated (pending=${tasks_pending} done=${tasks_done})\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'index-updater',
tasks_pending, tasks_done, lessons_lines, reviews_count
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
}
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena Stop hook (pace-continuator) v9.6 ★新增
// 协议: 不阻断 (放在 delivery-gate 之后串联运行)
// - 写入 details/next.md (PACE-aware 下一动作建议)
// - 在检测到"反复试错/失败模式"时, append details/proposals.md (铁律 9)
// 参考: https://code.claude.com/docs/en/hooks#stop
//
// 不发明 "自动 PACE", 只是写"下一步可以做的"备忘, 等用户自己读或下次 SessionStart 注入
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const NEXT_PATH = path.join(STATE_DIR, 'details', 'next.md');
const PROPOSALS_PATH = path.join(STATE_DIR, 'details', 'proposals.md');
const HOOK_TRACE = path.join(STATE_DIR, 'hook-trace.jsonl');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
if (event.stop_hook_active) { process.exit(0); return; }
if (event.agent_type && event.agent_type !== 'main') { process.exit(0); return; }
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
let fm = '';
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const m = content.match(/^---\n([\s\S]*?)\n---/);
if (!m) { process.exit(0); return; }
fm = m[1];
} catch (e) { process.exit(0); return; }
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const pathName = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const tasks_pending = getNum('tasks_pending');
const tasks_done = getNum('tasks_done');
if (!pathName || !stage || pathName === 'Hotfix' || pathName === 'Bugfix') {
process.exit(0); return;
}
// 推断下一动作
const suggestions = nextActionSuggestions(pathName, stage, tasks_pending, tasks_done);
if (suggestions.length === 0) { process.exit(0); return; }
// 写 next.md (覆盖, 仅保留最新一条 + 历史移到顶部)
const ts = new Date().toISOString().replace('T', ' ').slice(0, 16);
const entry = `## ${ts}\n当前: ${pathName}/${stage}/sprint ${sprint}\n建议:\n${suggestions.map(s => '- ' + s).join('\n')}\n`;
let existing = '';
try { existing = fs.readFileSync(NEXT_PATH, 'utf8'); } catch (e) {}
// 去掉模板注释, 在顶部 append
existing = existing.replace(/<!--[\s\S]*?-->\s*/g, '').trim();
const newContent = `# 下一动作建议\n\n${entry}\n${existing ? '\n---\n\n' + existing : ''}`.trim() + '\n';
fs.writeFileSync(NEXT_PATH, newContent);
// 检测反复试错: 读 hook-trace 最近 20 条, 看 subagent-retry / delivery-gate block 是否高频
try {
const trace = fs.readFileSync(HOOK_TRACE, 'utf8').split('\n').filter(l => l).slice(-20);
const retryCount = trace.filter(l => l.includes('"subagent-retry"')).length;
const blockCount = trace.filter(l => l.includes('"delivery-gate"') && l.includes('"block"')).length;
if (retryCount >= 3 || blockCount >= 2) {
// append proposals.md (铁律 9 Hook 反思)
const proposalEntry = `\n## ${ts} (sprint ${sprint})\n- 观察: 最近 20 hook 事件含 subagent-retry × ${retryCount}, delivery-gate block × ${blockCount}\n- 假设: ${pathName}/${stage} 阶段流程可能不顺畅, 可能是 design 不足 / task 过大 / 验收标准模糊\n- 提议: 复盘当前 sprint 设计粒度, 考虑拆 task 或回 plan 阶段\n`;
fs.appendFileSync(PROPOSALS_PATH, proposalEntry);
process.stderr.write(`[pace-continuator] proposals.md +1 (retry=${retryCount}, block=${blockCount})\n`);
}
} catch (e) {}
process.stderr.write(`[pace-continuator] next.md updated (${pathName}/${stage})\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'pace-continuator',
path: pathName, stage, sprint,
suggestions_count: suggestions.length
}) + '\n';
fs.appendFileSync(HOOK_TRACE, trace);
} catch (e) {}
process.exit(0);
});
function nextActionSuggestions(path, stage, pending, done) {
const s = [];
if (stage === 'plan') {
s.push('完成 design.md 的 File Structure Plan 段');
s.push('和用户确认设计后 → 进入 stage=impl');
s.push('可选: /goal "design.md 含 File Structure Plan + tasks ≥ 1 + 用户确认"');
} else if (stage === 'design') {
s.push('锁定架构, 完成 details/tasks-current.md (每 Task 含 Boundary/Depends)');
s.push('用户确认 → 进入 stage=impl');
} else if (stage === 'impl') {
if (pending > 0) {
s.push(`完成剩余 ${pending} 个 Task (按 Boundary 拆分)`);
if (path === 'Refactor' || path === 'System') {
s.push('可选: /batch "<重构描述>" 并行加速 (CC v2.1.121+ 原生)');
}
s.push('每完成 Task → tasks-current.md 勾选 + progress.md 追加');
} else if (done > 0) {
s.push('所有 task 完成, 跑测试和 lint → 切 stage=review');
s.push('/simplify 清理冗余');
}
} else if (stage === 'review') {
s.push('运行 /review → 写 reviews/sprint-N.md');
if (path !== 'Quick') {
s.push('运行 /codex:review (跨模型审查)');
}
s.push('@evaluator 评分 → VERDICT');
s.push('PASS → /compound 沉淀 lessons → stage=ship');
} else if (stage === 'ship') {
s.push('superpowers /ship (Feature+) 或 git commit (Quick)');
s.push('归档 details/tasks-archive/sprint-N.md');
s.push('_index.md sprint += 1, stage="" ');
}
return s;
}
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PermissionDenied hook v9.6
// 协议: stdout JSON { retry: true } (CC v2.1.89+ 官方标准)
// 参考: https://code.claude.com/docs/en/hooks#permissiondenied
//
// 设计:
// 当 auto mode classifier 拒绝某个工具调用 → 提示 model 可以重试 (但只针对一次)
// 并 systemMessage 建议用户加入全局 deny (如果是反复出现的 pattern)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
const tool = event.tool_name || '';
const cmd = (event.tool_input && event.tool_input.command) || '';
const reason = event.reason || '';
// 软提示: 如果是 Bash + 看起来是项目本地命令 → 提示用户考虑加入项目 allow
let suggestion = '';
if (tool === 'Bash' && cmd) {
// 抽取命令名 (第一个 token)
const cmdName = cmd.trim().split(/\s+/)[0];
if (['npm', 'pnpm', 'yarn', 'pytest', 'cargo', 'go', 'make'].includes(cmdName)) {
suggestion = `如果这是项目常用命令, 可: /athena:remember-allow "Bash(${cmdName}:*)" 加入全局 allow`;
}
}
if (suggestion) {
process.stderr.write(`[permission-retry] suggest: ${suggestion}\n`);
process.stdout.write(JSON.stringify({
retry: true,
systemMessage: `[Athena] permission denied. ${suggestion}`
}));
} else {
// 默认让 model 知道可以一次性重试
process.stdout.write(JSON.stringify({ retry: true }));
}
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'permission-retry',
tool, cmd_head: cmd.slice(0, 60), reason: reason.slice(0, 100)
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-19
View File
@@ -1,19 +0,0 @@
// VibeCoding v9.2.0 — PostToolUse(Write|Edit): 格式化
'use strict';
const { execSync } = require('child_process');
const fs = require('fs');
const input = JSON.parse(fs.readFileSync('/dev/stdin', 'utf8'));
const file = input?.tool_input?.file_path || input?.tool_input?.path || '';
try {
if (file.match(/\.(ts|tsx|js|jsx)$/)) {
// 先检查 prettier 存在
if (fs.existsSync('node_modules/.bin/prettier')) {
execSync(`npx prettier --write "${file}" 2>/dev/null`, { timeout: 5000 });
}
} else if (file.match(/\.py$/)) {
try { execSync('which black', { stdio: 'ignore', timeout: 2000 }); } catch { process.exit(0); }
execSync(`python3 -m black "${file}" --quiet 2>/dev/null`, { timeout: 5000 });
}
} catch {}
process.exit(0);
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PreToolUse Bash guard v9.6
// 协议: hookSpecificOutput.{hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason}
// 参考: https://code.claude.com/docs/en/hooks#pretooluse
//
// v9.6 设计:
// 配合 settings.json 的 if 字段做精细化拦截 (官方 if syntax: https://code.claude.com/docs/en/hooks#common-fields)
// settings.json 已用 if: "Bash(rm *)" / "Bash(curl *|wget *)" / "Bash(mkfs*|dd *)" 预过滤
// hook 内部做二次确认 + 提供具体的拒绝原因
//
// permissions.deny 已含 "Bash(rm -rf *)" 灾难规则, 这里是双重保险
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let cmd = '';
try {
const d = JSON.parse(input);
cmd = (d.tool_input && d.tool_input.command) || '';
} catch (e) { process.exit(0); return; }
if (!cmd) { process.exit(0); return; }
const deny = (reason) => {
process.stderr.write(`[bash-guard] deny: ${reason} (${cmd.slice(0, 60)})\n`);
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: `Athena bash-guard 阻断: ${reason}`
}
}));
process.exit(0);
};
// 灾难级 (3 条):
// 1. rm -rf 系统/用户根
if (/rm\s+-[rRf]+\s+(\/\s|\/\*|~\/?\s|~\s|\/$|~$)/.test(cmd) ||
/rm\s+-[rRf]+\s+\/\s*[;&|]/.test(cmd)) {
return deny('禁止删除系统/用户根目录');
}
// 2. 管道远程脚本
if (/(curl|wget)\s+[^|]*\|\s*(bash|sh|zsh|fish|ksh)/.test(cmd)) {
return deny('禁止管道执行远程脚本 (curl|wget ... | sh)');
}
// 3. 格式化磁盘 / 写设备
if (/\bmkfs\.|dd\s+if=.*of=\/dev\/sd|>\s*\/dev\/sd[a-z]/.test(cmd)) {
return deny('禁止格式化磁盘/写设备');
}
process.exit(0);
});
-26
View File
@@ -1,26 +0,0 @@
// VibeCoding v9.2.0 — PreToolUse(Bash): 安全守卫 (JSON decision output)
'use strict';
const input = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
const cmd = input?.tool_input?.command || '';
const BLOCKED = [
/rm\s+-rf\s+[\/~]/, /chmod\s+777/, /curl\s+.*\|\s*(?:bash|sh)/,
/wget\s+.*\|\s*(?:bash|sh)/, />\s*\/etc\//, /mkfs\./, /dd\s+if=/,
/:(){ :\|:& };:/, /fork\s*bomb/i
];
for (const pattern of BLOCKED) {
if (pattern.test(cmd)) {
// 使用 JSON decision output (官方推荐方式)
const output = JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: `[pre-bash] 危险命令被阻断: ${cmd.slice(0, 80)}`
}
});
process.stdout.write(output);
process.exit(0);
}
}
process.exit(0);
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena SessionStart hook v9.6
// 协议: hookSpecificOutput.{hookEventName: "SessionStart", additionalContext}
// 参考: https://code.claude.com/docs/en/hooks#sessionstart
//
// 设计 (铁律 8 索引先行):
// 1. 唯一 IO: read .ai_state/_index.md (frontmatter)
// 2. 注入 context-essentials.md (静态文本)
// 3. 注入 _index.md 关键字段摘要 (path/stage/sprint/counts/active_goal)
// 4. effort=max 时跳过 PACE 状态注入 (高 effort 模型自己探索)
// 5. 不预加载 tasks/design/progress 内容
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
const PROJECT_ESSENTIALS = path.join(PROJECT_DIR, '.claude', 'skills', 'pace', 'context-essentials.md');
const HOME = process.env.HOME || require('os').homedir();
const GLOBAL_ESSENTIALS = path.join(HOME, '.claude', 'skills', 'pace', 'context-essentials.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const source = event.source || 'unknown';
// CC v2.1.133+ 注入 effort.level
const effort = (event.effort && event.effort.level) || process.env.CLAUDE_EFFORT || '';
const isMax = effort === 'max';
const lines = [];
// 1. 注入 context-essentials.md (优先项目级, 回落全局)
let essentialsText = '';
for (const p of [PROJECT_ESSENTIALS, GLOBAL_ESSENTIALS]) {
try {
const t = fs.readFileSync(p, 'utf8').trim();
if (t) { essentialsText = t; break; }
} catch (e) {}
}
if (essentialsText) {
lines.push(essentialsText);
} else {
lines.push('[VibeCoding Athena v9.6] TDD · Review · Sisyphus · 索引先行 · 完成度证据 · 出处优先\n[Get-bearings] read .ai_state/_index.md 然后按 pointers 跳转明细');
}
// 2. effort=max 时不注入 PACE 状态摘要 (高 effort 自己探索)
if (!isMax && fs.existsSync(INDEX_PATH)) {
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (fmMatch) {
const fm = fmMatch[1];
const getStr = k => {
const m = fm.match(new RegExp('^ ' + k + ': (.*)$', 'm'));
return m ? m[1].replace(/^["']|["']$/g, '').trim() : '';
};
const getNum = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const path_ = getStr('path');
const stage = getStr('stage');
const sprint = getNum('sprint');
const goal = getStr('active_goal');
const pending = getNum('tasks_pending');
const done = getNum('tasks_done');
const blocked = getNum('tasks_blocked');
if (path_ && stage) {
lines.push(`\n[PACE] Path:${path_} Stage:${stage} Sprint:${sprint}`);
}
if (goal) {
lines.push(`[/goal active] ${goal.slice(0, 120)}${goal.length > 120 ? '...' : ''}`);
}
if (pending + done + blocked > 0) {
lines.push(`[任务] ${done} 完成 ${pending} 待办 ${blocked} 阻塞 (详见 details/tasks-current.md)`);
}
// gotchas (按 YAML array 简单解析: 单行 [..] 或多行 - 形式)
const gotchasMatch = fm.match(/^gotchas:\s*(.+)$/m);
if (gotchasMatch) {
const g = gotchasMatch[1].trim();
if (g.startsWith('[') && !g.match(/^\[\s*\]$/)) {
lines.push(`[Gotchas] ${g.slice(1, -1).trim()}`);
}
}
}
} catch (e) {
process.stderr.write(`[session-start] _index.md parse failed: ${e.message}\n`);
}
}
if (lines.length === 0) { process.exit(0); return; }
const additionalContext = lines.join('\n');
process.stderr.write(`[session-start/${source}${isMax ? '/max' : ''}] injected ${additionalContext.length} chars\n`);
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'session-start',
source, effort, chars: additionalContext.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: 'SessionStart',
additionalContext
}
}));
process.exit(0);
});
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena ConfigChange hook v9.6 ★新增 (L2.G)
// 协议: 不阻断, additionalContext 注入 warning
// 参考: https://code.claude.com/docs/en/hooks#configchange
//
// 设计:
// ConfigChange 事件触发时 (settings.json/CLAUDE.md/MCP 等变更):
// 1. 重新读 _index.md, 验证 schema_version 仍是 "9.6"
// 2. 比对 fingerprints 段, 检测 details/* 是否被外部修改 (mtime 异常跳变)
// 3. 异常时注入 systemMessage 提醒 (而非 block, ConfigChange 不该 block)
//
// 用途场景: 用户用编辑器手改了 _index.md 导致 schema 损坏 / git checkout 切换分支后状态错位
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
const INDEX_PATH = path.join(STATE_DIR, '_index.md');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) {}
const configSource = event.matcher || 'unknown';
if (!fs.existsSync(INDEX_PATH)) { process.exit(0); return; }
const warnings = [];
try {
const content = fs.readFileSync(INDEX_PATH, 'utf8');
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) {
warnings.push('_index.md frontmatter 已损坏, 无法解析');
} else {
const fm = fmMatch[1];
// 1. schema_version 检查
const schemaMatch = fm.match(/^schema_version: "([^"]+)"$/m);
if (!schemaMatch || schemaMatch[1] !== '9.6') {
warnings.push(`schema_version 异常: ${schemaMatch ? schemaMatch[1] : 'missing'} (期望 "9.6", 可能需要 /athena-migrate)`);
}
// 2. fingerprints vs 实际 mtime 比对
const getFp = k => {
const m = fm.match(new RegExp('^ ' + k + ': (\\d+)$', 'm'));
return m ? parseInt(m[1], 10) : 0;
};
const fpTasks = getFp('tasks_mtime');
const fpDesign = getFp('design_mtime');
const fpProgress = getFp('progress_mtime');
const fpLessons = getFp('lessons_mtime');
const checkFile = (name, fp) => {
try {
const actual = Math.floor(fs.statSync(path.join(STATE_DIR, 'details', name)).mtimeMs);
// 允许 fingerprint 落后于 actual (PostToolUse 还没跑), 但反过来不正常
if (fp > actual + 1000) {
warnings.push(`${name} fingerprint 比实际 mtime 新 (${fp - actual}ms), 可能被外部修改`);
}
} catch (e) {}
};
checkFile('tasks-current.md', fpTasks);
checkFile('design.md', fpDesign);
checkFile('progress.md', fpProgress);
checkFile('lessons.md', fpLessons);
}
} catch (e) {
warnings.push(`审计失败: ${e.message}`);
}
if (warnings.length === 0) { process.exit(0); return; }
const msg = `[Athena state-audit] ConfigChange (${configSource}) 检测到 ${warnings.length} 个潜在问题:\n${warnings.map(w => '• ' + w).join('\n')}`;
process.stderr.write(msg + '\n');
process.stdout.write(JSON.stringify({ systemMessage: msg }));
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'state-audit',
source: configSource,
warnings_count: warnings.length
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-18
View File
@@ -1,18 +0,0 @@
// VibeCoding v9.2.0 — StopFailure: API错误时保存状态
'use strict';
const fs = require('fs');
const path = require('path');
const STATE_DIR = path.join(process.cwd(), '.ai_state');
try {
if (fs.existsSync(STATE_DIR)) {
const sessionFile = path.join(STATE_DIR, 'session.md');
if (fs.existsSync(sessionFile)) {
let content = fs.readFileSync(sessionFile, 'utf8');
const ts = new Date().toISOString();
content += `\n\n## 异常中断\n${ts} — API错误导致会话中断。下次 SessionStart 自动恢复。\n`;
fs.writeFileSync(sessionFile, content);
}
console.log('[VibeCoding] API错误,状态已保存。下次启动自动恢复。');
}
} catch {}
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env node
'use strict';
// VibeCoding Athena PostToolUse subagent-retry v9.6
// 协议: 不阻断 (additionalContext 注入 hint)
// 参考: https://code.claude.com/docs/en/hooks#posttooluse
//
// 设计:
// Task tool 调用 subagent. 若返回的 tool_response 里含"无法"/"无能力"等放弃语
// → 注入 systemMessage 提示 main agent 重试或亲自接管
// 防止 subagent 偷懒 (v9.5 实测问题)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
if (event.tool_name !== 'Task') { process.exit(0); return; }
const response = event.tool_response;
if (!response || typeof response !== 'object') { process.exit(0); return; }
// 提取 subagent 的完整响应内容
let text = '';
if (typeof response.content === 'string') text = response.content;
else if (Array.isArray(response.content)) text = response.content.map(c => c.text || '').join('\n');
else text = JSON.stringify(response);
// 放弃信号词
const giveupPatterns = [
/我(无法|不能|没法|无能力|不具备能力)/,
/I (cannot|can't|am not able to|don't have access)/i,
/no (capability|access|permission) to/i,
/unable to (read|write|execute|access)/i,
/tool not available/i,
/(请|你)(自己|手动|帮我)?(运行|执行|跑)/,
/please run (this|the command) (yourself|manually)/i
];
const found = giveupPatterns.find(p => p.test(text));
if (!found) { process.exit(0); return; }
process.stderr.write(`[subagent-retry] giveup detected: ${found}\n`);
const subagentType = (event.tool_input && event.tool_input.subagent_type) || 'subagent';
process.stdout.write(JSON.stringify({
systemMessage: `[Athena subagent-retry] ${subagentType} 返回了放弃信号. 协议: 1) 再尝试一次, 用不同参数或拆分任务 2) 仍失败则主 agent 接管, 不要让用户代执行 (铁律 6 完成度证据)`
}));
// hook-trace
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'subagent-retry',
subagent_type: subagentType,
pattern: String(found)
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});
-21
View File
@@ -1,21 +0,0 @@
// VibeCoding v9.2.0 — Stop: TDD 检查 (git diff 对比)
'use strict';
const { execSync } = require('child_process');
try {
const diff = execSync('git diff --name-only 2>/dev/null', { encoding: 'utf8' });
const codeExts = /\.(ts|tsx|js|jsx|py|go|rs)$/;
const testPattern = /\.test\.|\.spec\.|__test__|_test\./;
const configPattern = /config|\.json$|\.yaml$|\.yml$|\.md$|\.lock$/i;
const srcFiles = diff.split('\n').filter(f =>
f.match(codeExts) && !f.match(testPattern) && !f.match(configPattern)
);
const testFiles = diff.split('\n').filter(f => f.match(testPattern));
if (srcFiles.length > 0 && testFiles.length === 0) {
process.stderr.write(`[tdd-check] ⚠ ${srcFiles.length} 个源码修改但无测试。TDD: 先写测试!\n`);
// 不阻断, 只提醒 (阻断在 delivery-gate)
}
} catch {}
process.exit(0);
+130 -50
View File
@@ -1,55 +1,65 @@
{
"environmentVariables": {
"VIBECODING_VERSION": "9.2.0",
"LANGUAGE": "zh-Hans",
"LC_ALL": "zh-Hans",
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "opusplan",
"effortLevel": "xhigh",
"env": {
"VIBECODING_ATHENA_VERSION": "9.6.0",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-7",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6",
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6"
"DISABLE_NON_ESSENTIAL_MODEL_CALLS": "1",
"CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1",
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1",
"NEXT_TELEMETRY_DISABLED": "1",
"NUXT_TELEMETRY_DISABLED": "1",
"GATSBY_TELEMETRY_DISABLED": "1",
"ASTRO_TELEMETRY_DISABLED": "1",
"ANGULAR_CLI_ANALYTICS": "false",
"API_TIMEOUT_MS": "30000"
},
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npx *)",
"Bash(node *)",
"Bash(git *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(find *)",
"Bash(grep *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(wc *)",
"Bash(mkdir *)",
"Bash(cp *)",
"Bash(mv *)",
"Bash(touch *)",
"Bash(codex *)",
"Bash(ast-grep *)",
"Read(*)",
"Write(*)",
"Edit(*)",
"MultiEdit(*)",
"Glob(*)",
"Grep(*)"
"Bash(npm test:*)",
"Bash(npm run:*)",
"Bash(npx:*)",
"Bash(node:*)",
"Bash(python:*)",
"Bash(python3:*)",
"Bash(pytest:*)",
"Bash(uv run:*)",
"Bash(cargo:*)",
"Bash(go:*)",
"Bash(claude *)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git checkout:*)",
"Bash(git branch:*)",
"Bash(git worktree:*)",
"Read(.ai_state/**)",
"Write(.ai_state/**)"
],
"deny": [
"Bash(rm -rf /)",
"Bash(rm -rf /*)",
"Bash(rm -rf ~)",
"Bash(chmod 777 *)",
"Bash(curl * | bash)",
"Read(./secrets/**)",
"Read(./.env.production)"
"Bash(rm -rf *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"worktree": {
"baseRef": "head"
},
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume|clear|compact",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/context-loader.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/session-start.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/session-start.cjs\" || true"
}
]
}
@@ -60,18 +70,38 @@
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/pre-bash.cjs"
"if": "Bash(rm *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
},
{
"type": "command",
"if": "Bash(curl *|wget *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
},
{
"type": "command",
"if": "Bash(mkfs*|dd *)",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pre-bash-guard.cjs\" || true"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/post-edit.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/index-updater.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/index-updater.cjs\" || true"
}
]
},
{
"matcher": "Task",
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/subagent-retry.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/subagent-retry.cjs\" || true"
}
]
}
@@ -81,28 +111,78 @@
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/delivery-gate.cjs"
}
]
},
{
"hooks": [
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/delivery-gate.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/delivery-gate.cjs\" || true"
},
{
"type": "command",
"command": "node .claude/hooks/tdd-check.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pace-continuator.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/pace-continuator.cjs\" || true"
}
]
}
],
"StopFailure": [
"PermissionDenied": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/stop-failure.cjs"
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/permission-retry.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/permission-retry.cjs\" || true"
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-snapshot.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-snapshot.cjs\" || true"
}
]
}
],
"PostCompact": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-restore.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/compact-restore.cjs\" || true"
}
]
}
],
"ConfigChange": [
{
"hooks": [
{
"type": "command",
"command": "test -f \"${CLAUDE_PROJECT_DIR}/.claude/hooks/state-audit.cjs\" && node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/state-audit.cjs\" || true"
}
]
}
]
},
"extraKnownMarketplaces": {
"superpowers-marketplace": {
"source": {
"source": "github",
"repo": "obra/superpowers-marketplace"
}
},
"openai-codex": {
"source": {
"source": "github",
"repo": "openai/codex-plugin-cc"
}
}
},
"enabledPlugins": {
"superpowers@superpowers-marketplace": true,
"codex@openai-codex": true,
"feature-dev@claude-plugins-official": true,
"code-review@claude-plugins-official": true,
"commit-commands@claude-plugins-official": true,
"playwright-skill@playwright-skill": true,
"security-guidance@claude-plugins-official": true,
"frontend-design@claude-plugins-official": true
}
}
}
+30
View File
@@ -0,0 +1,30 @@
---
name: athena-dev
description: >
Athena 主入口。从需求到交付的完整工程化开发流程。
effort: xhigh
disable-model-invocation: true
argument-hint: "<需求描述>"
---
# /athena-dev
`.ai_state/` 不存在 → 提示 `/athena-init` 并停。
`.ai_state/_index.md.schema_version` != "9.6" → 提示 `/athena-migrate` 并停。
## Get-bearings (R₀, just-in-time, 铁律 8)
1. **必读**: `.ai_state/_index.md` (单一入口)
2. **按需**: stage=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
3. **按需**: 任务命中 lessons 主题 → pointers.latest_lesson 跳段
4. **按需**: `git log --oneline -10`
5. **按需**: impl/review 阶段 → `bash .ai_state/init.sh`
文件大就用 head/tail/grep。**禁止 glob 整个 .ai_state/** (铁律 8)。
## Dispatch
有进行中的 stage → 从当前阶段继续 (触发 pace skill)。
新需求 → 触发 pace skill 路由, 需求: $ARGUMENTS。
首次使用简短说明: "PACE 帮你路由——小事直接做, 大事加设计和审查。CC 原生 /goal /batch /background 已接入。"
+104
View File
@@ -0,0 +1,104 @@
---
name: athena-init
description: >
项目初始化。每个新项目首次使用 Athena 时运行。扫描项目、生成环境脚本、创建 .ai_state/ schema。
effort: xhigh
disable-model-invocation: true
---
# /athena-init — 项目初始化
参考: <https://code.claude.com/docs/en/skills>
## 1. CC 原生初始化
无 CLAUDE.md → 运行 `/init`, 生成后追加: "本项目使用 VibeCoding Athena, 开发用 `/athena-dev`"
已有 CLAUDE.md → 跳过。
## 2. 项目扫描
```bash
ls package.json pyproject.toml Cargo.toml go.mod build.gradle pom.xml 2>/dev/null
cat package.json 2>/dev/null | grep -A5 '"scripts"'
ls jest.config* vitest.config* pytest.ini .eslintrc* ruff.toml biome.json 2>/dev/null
```
## 3. 创建 .ai_state/ 目录树 (v9.6 schema)
```bash
mkdir -p .ai_state/details/reviews
mkdir -p .ai_state/details/tasks-archive
```
## 4. 拷贝模板到 .ai_state/
从 `~/.claude/skills/pace/templates/` 复制 (必须全部, 缺一不可):
- `_index.md` → `.ai_state/_index.md` (单一入口, 铁律 8)
- `details/tasks-current.md`
- `details/progress.md`
- `details/design.md`
- `details/handoff.md`
- `details/lessons.md`
- `details/review-report.md` → `.ai_state/details/reviews/template.md`
- `details/next.md`
- `details/proposals.md`
- `init.sh` → `.ai_state/init.sh`
## 5. 填充 _index.md frontmatter
把扫描结果写入:
- `tech_stack` (检测到的: node/python/rust/go)
- `test_cmd` (从 package.json scripts.test 或 pytest 等)
- `build_cmd`
- `lint_cmd`
- `dev_cmd`
填充 `platform_features` (用 `claude --version` 和 `codex --version 2>&1`):
- `cc_version`
- `cx_version`
- `goal_supported`: 解析 cc_version, ≥ "2.1.139" 即 true
- `batch_supported`: ≥ "2.1.121"
- `background_supported`: ≥ "2.1.139"
- `session_memory_active`: 检测 `~/.claude/projects/` 是否含 session-memory 子目录
- `cross_session_memory`: 检测 `~/.claude/plugins/` 含 claude-mem 则 "claude-mem", 含 superpowers 则 "superpowers", 否则 "none"
## 6. 生成 init.sh
根据扫描结果定制 `.ai_state/init.sh`:
- 依赖安装命令 (npm install / pip install / cargo build)
- dev server 启动 (如有)
- 基线测试命令
- `chmod +x .ai_state/init.sh`
## 7. .gitignore
```bash
grep -q '.ai_state' .gitignore 2>/dev/null || echo '.ai_state/' >> .gitignore
```
## 8. 跨项目记忆推荐 (替代删除的全局 lessons)
```bash
# 检测 claude-mem 或 superpowers, 缺则软提示
if ! ls ~/.claude/plugins/ 2>/dev/null | grep -iE 'claude-mem|superpowers' > /dev/null; then
echo "💡 推荐装 claude-mem (89k stars) 做跨项目记忆"
echo " /plugin install claude-mem (待加入官方 marketplace)"
echo " 或: /athena-setup 走完整推荐流"
fi
```
## 9. Git commit
```bash
git add .ai_state/ .gitignore
git commit -m "athena: project initialized (v9.6 schema)"
```
## 10. 验证
运行 `bash .ai_state/init.sh` 确认脚本正常。
告知用户: "Athena 已就绪。用 `/athena-dev <需求>` 开始开发, 或 `/athena-status` 看面板。"
已有 .ai_state/ 但 schema_version != "9.6" → 提示运行 `/athena-migrate` 升级。
已有 .ai_state/ 且 schema_version == "9.6" → 提示用户是否重新初始化 (会重置 _index.md)。
+203
View File
@@ -0,0 +1,203 @@
---
name: athena-migrate
description: >
把 v9.5.5 项目的 .ai_state/ 升级到 v9.6 schema (INDEX + details/ 重构)。
effort: xhigh
disable-model-invocation: true
---
# /athena-migrate — v9.5.5 → v9.6 迁移
参考: <https://code.claude.com/docs/en/skills>
## 前置检查
```bash
test -d .ai_state || { echo "[migrate] 无 .ai_state, 请先 /athena-init"; exit 1; }
test -f .ai_state/_index.md && grep -q 'schema_version: "9.6"' .ai_state/_index.md && {
echo "[migrate] 已是 v9.6 schema, 无需迁移"; exit 0;
}
```
## 迁移算法
### Step 1: 备份
```bash
mkdir -p .ai_state/.legacy-v9.5
cp -r .ai_state/{tasks.md,design.md,progress.md,lessons.md,handoff.md,project.json,reviews,hook-trace.jsonl,compact-snapshot.json} .ai_state/.legacy-v9.5/ 2>/dev/null || true
echo "[migrate] 旧文件已备份到 .ai_state/.legacy-v9.5/"
```
### Step 2: 创建 details/ 目录
```bash
mkdir -p .ai_state/details/reviews
mkdir -p .ai_state/details/tasks-archive
```
### Step 3: 迁移文件
| v9.5.5 路径 | v9.6 路径 | 备注 |
|---|---|---|
| `.ai_state/tasks.md` | `.ai_state/details/tasks-current.md` | 改名 |
| `.ai_state/design.md` | `.ai_state/details/design.md` | 平移 |
| `.ai_state/progress.md` | `.ai_state/details/progress.md` | 平移 |
| `.ai_state/lessons.md` | `.ai_state/details/lessons.md` | 平移 |
| `.ai_state/handoff.md` | `.ai_state/details/handoff.md` | 平移 |
| `.ai_state/reviews/sprint-N.md` | `.ai_state/details/reviews/sprint-N.md` | 平移 |
| `.ai_state/project.json` | (merge 到 _index.md frontmatter) | 转 markdown frontmatter |
| `.ai_state/hook-trace.jsonl` | `.ai_state/hook-trace.jsonl` | 保持原位置 |
| `.ai_state/compact-snapshot.json` | (删, v9.6 改写到 _index.md.snapshots) | 删除 |
```bash
# 平移
[ -f .ai_state/tasks.md ] && mv .ai_state/tasks.md .ai_state/details/tasks-current.md
for f in design.md progress.md lessons.md handoff.md; do
[ -f .ai_state/$f ] && mv .ai_state/$f .ai_state/details/$f
done
[ -d .ai_state/reviews ] && mv .ai_state/reviews .ai_state/details/reviews
[ -f .ai_state/compact-snapshot.json ] && rm .ai_state/compact-snapshot.json
```
### Step 4: 生成 _index.md
从 `.ai_state/project.json` 读 path/stage/sprint/tech_stack/test_cmd/build_cmd/lint_cmd/dev_cmd/conventions/gotchas, 写入新 _index.md frontmatter。
```bash
# 用 node 脚本生成 _index.md (避免手写 yaml escape 出错)
node -e '
const fs = require("fs");
const path = require("path");
let proj = {};
try { proj = JSON.parse(fs.readFileSync(".ai_state/.legacy-v9.5/project.json","utf8")); } catch(e) {}
const sprint = proj.sprint || 0;
// 计算 counts
let tasks_pending = 0, tasks_done = 0, tasks_blocked = 0;
try {
const t = fs.readFileSync(".ai_state/details/tasks-current.md","utf8");
tasks_pending = (t.match(/^- \[ \]/gm) || []).length;
tasks_done = (t.match(/^- \[x\]/gm) || []).length;
} catch(e) {}
let progress_entries = 0, latest_progress = "";
try {
const lines = fs.readFileSync(".ai_state/details/progress.md","utf8").split("\n").filter(l => l.trim().length > 0 && !l.startsWith("<!--") && !l.startsWith("#"));
progress_entries = lines.length;
if (lines.length > 0) latest_progress = `details/progress.md#L${lines.length}`;
} catch(e) {}
let lessons_lines = 0, latest_lesson = "";
try {
const lines = fs.readFileSync(".ai_state/details/lessons.md","utf8").split("\n");
lessons_lines = lines.filter(l => l.startsWith("##")).length;
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].startsWith("## ")) { latest_lesson = `details/lessons.md#L${i+1}`; break; }
}
} catch(e) {}
let reviews_count = 0, latest_review = "";
try {
const files = fs.readdirSync(".ai_state/details/reviews").filter(f => f.startsWith("sprint-") && f.endsWith(".md"));
reviews_count = files.length;
if (files.length > 0) {
const sorted = files.sort();
latest_review = `details/reviews/${sorted[sorted.length-1]}`;
}
} catch(e) {}
const idx = `---
schema_version: "9.6"
athena_version: "9.6.0"
project:
path: "${proj.path || ""}"
stage: "${proj.stage || ""}"
sprint: ${sprint}
active_goal: ""
counts:
tasks_pending: ${tasks_pending}
tasks_done: ${tasks_done}
tasks_blocked: ${tasks_blocked}
lessons_lines: ${lessons_lines}
progress_entries: ${progress_entries}
reviews_count: ${reviews_count}
pointers:
latest_progress: "${latest_progress}"
latest_review: "${latest_review}"
latest_lesson: "${latest_lesson}"
latest_proposal: ""
fingerprints:
tasks_mtime: 0
design_mtime: 0
progress_mtime: 0
lessons_mtime: 0
platform_features:
cc_version: ""
cx_version: ""
goal_supported: false
batch_supported: false
background_supported: false
session_memory_active: false
cross_session_memory: "none"
gotchas: ${JSON.stringify(proj.gotchas || [])}
conventions: ${JSON.stringify(proj.conventions || [])}
tech_stack: "${proj.tech_stack || ""}"
test_cmd: "${proj.test_cmd || ""}"
build_cmd: "${proj.build_cmd || ""}"
lint_cmd: "${proj.lint_cmd || ""}"
dev_cmd: "${proj.dev_cmd || ""}"
---
# 项目状态索引 (v9.6 migrated from v9.5.5)
## 最近活动
## 当前阻塞
## 下一动作 (PACE 建议)
## 反思建议 (Hook 沉淀)
`;
fs.writeFileSync(".ai_state/_index.md", idx);
console.log("[migrate] _index.md generated");
'
```
### Step 5: 创建空 next.md 和 proposals.md
```bash
touch .ai_state/details/next.md
touch .ai_state/details/proposals.md
```
### Step 6: 平台版本检测填入 _index.md
调用 `/athena-setup --detect-only`, 它会原地更新 `_index.md.platform_features`。
### Step 7: 提示用户
```
✓ 迁移完成。备份在 .ai_state/.legacy-v9.5/, 确认无问题可删除。
新增的文件: .ai_state/details/next.md, .ai_state/details/proposals.md
删除的文件: .ai_state/project.json (合并到 _index.md frontmatter)
.ai_state/compact-snapshot.json (改写到 _index.md.snapshots 数组)
下一步: /athena-status 查看新状态面板
```
### Step 8: Git commit
```bash
git add .ai_state/
git commit -m "athena: migrate state to v9.6 schema"
```
## 回滚 (如果出问题)
```bash
rm -rf .ai_state/details .ai_state/_index.md
cp -r .ai_state/.legacy-v9.5/* .ai_state/
```
+138
View File
@@ -0,0 +1,138 @@
---
name: athena-preferences
description: >
Athena 全局偏好便利层。直接操作 CC 原生 ~/.claude/settings.json 的 permissions.allow/deny 和全局 CLAUDE.md。
effort: medium
disable-model-invocation: true
argument-hint: "<subcommand> <args>"
---
# /athena-preferences (v9.6)
## 设计原则
**Athena 不造私有偏好文件**。所有写入都是 CC 原生位置:
| 偏好类型 | 落点 |
|---|---|
| 全局 allow | `~/.claude/settings.json` `permissions.allow[]` |
| 全局 deny | `~/.claude/settings.json` `permissions.deny[]` |
| 工具偏好 (pnpm/vitest) | `~/.claude/CLAUDE.md` "## Tool Preferences" 段 |
参考: <https://code.claude.com/docs/en/settings> + <https://code.claude.com/docs/en/permissions>
**永远不写**:
- ❌ `~/.claude/memory/athena-*.list` 类私有文件
- ❌ 项目特定的命令到全局 (路径泛化检查)
**永远不自动写**:
- ❌ 不监控命令频次自动建议 (隐私决定)
- ✅ 仅在用户**显式调用**本 skill 时写
## 子命令
### `/athena:remember-allow <pattern>`
参数: 标准 CC permission pattern, 如 `Bash(pnpm test:*)`.
```javascript
const fs = require('fs');
const os = require('os');
const path = require('path');
const settingsPath = path.join(os.homedir(), '.claude/settings.json');
let s = {};
try { s = JSON.parse(fs.readFileSync(settingsPath,'utf8')); } catch(e) {}
s.permissions = s.permissions || {};
s.permissions.allow = s.permissions.allow || [];
const pattern = process.argv[2];
// 路径泛化检查: 拒绝含项目特定路径的 pattern
if (/\/Users\/|\/home\/[^*/]|C:\\Users\\/.test(pattern) || /[\w-]+\.(com|cn|net)\//.test(pattern)) {
console.error('❌ 拒绝: pattern 含项目/用户特定路径, 不应写入全局');
console.error(' 如果只想本项目用, 写到 .claude/settings.local.json');
process.exit(1);
}
if (s.permissions.allow.includes(pattern)) {
console.log('✓ 已存在, 无需添加');
process.exit(0);
}
s.permissions.allow.push(pattern);
fs.writeFileSync(settingsPath, JSON.stringify(s,null,2));
console.log(`✓ 已加入全局 allow: ${pattern}`);
console.log(` 位置: ${settingsPath}`);
```
### `/athena:remember-deny <pattern>`
同 `remember-allow`, 写入 `permissions.deny[]`. 但**不做路径泛化拒绝**——deny 越严格越好。
### `/athena:remember-tool <key>=<value>`
写入 `~/.claude/CLAUDE.md` 的 "## Tool Preferences" 段 (无则创建):
```
## Tool Preferences
- 包管理器: pnpm
- 测试运行器: vitest
- Linter: biome
- 默认提交者: --signoff
```
### `/athena:show-preferences`
```bash
echo "=== Global allow (~/.claude/settings.json) ==="
node -e 'console.log((JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/settings.json")).permissions?.allow || []).join("\n"))'
echo ""
echo "=== Global deny ==="
node -e 'console.log((JSON.parse(require("fs").readFileSync(require("os").homedir()+"/.claude/settings.json")).permissions?.deny || []).join("\n"))'
echo ""
echo "=== Tool preferences (~/.claude/CLAUDE.md) ==="
sed -n '/^## Tool Preferences/,/^## /p' ~/.claude/CLAUDE.md 2>/dev/null | head -20
```
### `/athena:forget <pattern>`
从全局 allow/deny 中删除指定 pattern. 显示删除前后 diff.
```javascript
const fs = require('fs');
const os = require('os');
const path = require('path');
const settingsPath = path.join(os.homedir(), '.claude/settings.json');
const s = JSON.parse(fs.readFileSync(settingsPath,'utf8'));
const pattern = process.argv[2];
const beforeA = s.permissions?.allow?.length || 0;
const beforeD = s.permissions?.deny?.length || 0;
if (s.permissions?.allow) s.permissions.allow = s.permissions.allow.filter(p => p !== pattern);
if (s.permissions?.deny) s.permissions.deny = s.permissions.deny.filter(p => p !== pattern);
const afterA = s.permissions?.allow?.length || 0;
const afterD = s.permissions?.deny?.length || 0;
fs.writeFileSync(settingsPath, JSON.stringify(s,null,2));
console.log(`allow: ${beforeA} → ${afterA}`);
console.log(`deny: ${beforeD} → ${afterD}`);
```
## 安全约束
1. **不修改 managed-settings.json** (企业管理层)
2. **不修改项目 .claude/settings.json** (那是项目级, 用 settings.local.json 兜底)
3. **永远显示 diff** 在写入前——用户能看到改了什么
4. **永远说明落点** ("位置: ~/.claude/settings.json") 而不是含糊"已记住"
## Boundary
- ✅ 操作 `~/.claude/settings.json`
- ✅ 追加到 `~/.claude/CLAUDE.md` 末尾 "## Tool Preferences" 段
- ❌ 不读不写 `~/.claude/projects/` (那是 session memory, claude-mem 管)
- ❌ 不读不写 `~/.claude/memory/`
- ❌ 不创建 `~/.claude/athena-*.txt` 类文件
+15
View File
@@ -0,0 +1,15 @@
---
name: athena-review
description: >
单独运行质量审查, 不走完整开发流程。
effort: xhigh
disable-model-invocation: true
argument-hint: "[focus area]"
---
# /athena-review
有 `.ai_state/_index.md` → 按当前 Path 深度触发 pace skill 审查阶段。
无 → 快速审查: `/review`。
焦点: $ARGUMENTS
+154
View File
@@ -0,0 +1,154 @@
---
name: athena-setup
description: >
Athena 全局安装。检查 CC 版本、装插件、配置 Codex、部署 hooks、推 claude-mem。首次使用运行一次。
effort: xhigh
disable-model-invocation: true
---
# /athena-setup (v9.6)
## 设计哲学 (启动时告诉用户)
```
v9.6 原则:
- permissions.deny 仅保留 "Bash(rm -rf *)" + 机密文件 (sandbox 是正道)
参考: https://claude.com/blog/beyond-permission-prompts-making-claude-code-more-secure-and-autonomous
- 全局 lessons 已删, 跨项目记忆推 claude-mem (默认装)
- /goal /batch /background CC 原生, 不再造状态机驱动器
- 不维护插件推荐列表, 实时查 marketplace
```
## Step 0: CC 版本检查
参考: <https://code.claude.com/docs/en/changelog>
```bash
claude --version
```
要求 ≥ v2.1.121 (worktree isolation + updatedToolOutput 全工具). v2.1.139+ 解锁 /goal /background.
低于 → `claude update` 或 `npm install -g @anthropic-ai/claude-code@latest`.
把检测到的版本写入 `.ai_state/_index.md.platform_features.cc_version`. 解析后置 goal_supported/batch_supported/background_supported.
## Step 1: 插件安装 (按 PACE 节点 best-fit, 非强依赖)
每装一个问自己: "这个真的会用吗?" 多余 = context 浪费。
### 工程主线 (强烈推荐)
```
/plugin marketplace add obra/superpowers-marketplace
/plugin install superpowers@superpowers-marketplace
/plugin marketplace add openai/codex-plugin-cc
/plugin install codex@openai-codex
```
### 跨项目记忆 (v9.6 默认推 claude-mem)
claude-mem 89k stars, Apache-2.0, 自动捕获 tool use + 压缩摘要 + 注入下次 session.
参考: <https://github.com/thedotmack/claude-mem>
```
# 检测是否已装
if /plugin list | grep -iq claude-mem; then
echo "claude-mem ✓ 已装"
else
echo "推荐安装 claude-mem (跨 session 记忆):"
echo " /plugin marketplace add <claude-mem 所在 marketplace>"
echo " /plugin install claude-mem"
echo " (如不在 marketplace, 从 github.com/thedotmack/claude-mem 下载)"
fi
```
未装也行——Athena 仍可用, `_index.md.platform_features.cross_session_memory` 标 "none".
### PACE 节点 best-fit (按需, 实时查 marketplace)
athena-setup **不写死推荐列表**, 改用 `/plugin browse` + 关键词查询:
| 路径 | 关键词 (用 /plugin browse 查) |
|------|------------------------------|
| Bugfix | debugger / bug-fix / metronome |
| Feature 实现 | superpowers / dev-workflows / context7 |
| Feature 审查 | codex-plugin-cc / agent-peer-review / local-review |
| Refactor | TypeScript LSP / Rust LSP / ast-grep |
| Refactor 审查 | codex-plugin-cc / AgentLint |
| System | shipyard (IaC) / mcp-builder |
| 跨节点 | context-mode (大输出 sandbox 化) |
### 官方插件 (claude-plugins-official, 已在 settings.json 启用)
```
/plugin install feature-dev
/plugin install code-review
/plugin install commit-commands
```
`/reload-plugins` 后生效.
## Step 2: context7 (skill 模式)
```bash
npx ctx7 setup --claude
```
无需全局装 ctx7 CLI, npx 按需拉. OAuth 登录后 `~/.claude/skills/` 自动生成 context7 skill.
触发方式: "use context7" 或 "use context7 with /owner/repo for <query>".
## Step 3: Codex 配置
```
/codex:setup
```
未登录 → `!codex login`.
**不要启用 review gate** (`/codex:setup --enable-review-gate`) — 会 Claude ↔ Codex 死循环.
settings.json codex 权限 (已在 v9.6 默认 settings 含):
```json
"Bash(codex:*)",
"Bash(node:*)"
```
Codex 独立配置 `~/.codex/config.toml` (见本仓库 cx/.codex/config.toml).
## Step 4: Hooks 安装
```bash
mkdir -p ~/.claude/hooks
cp .claude/hooks/*.cjs ~/.claude/hooks/
chmod +x ~/.claude/hooks/*.cjs
```
v9.6 hook 列表 (8 个):
- session-start · pre-bash-guard · index-updater · subagent-retry
- delivery-gate · pace-continuator
- permission-retry · compact-snapshot · compact-restore · state-audit
## Step 5: 验证
```bash
claude --version # ≥ 2.1.121, 最佳 ≥ 2.1.139
/plugin list # superpowers / codex / claude-mem (推荐)
npx ctx7 library express # context7 CLI 通
/codex:setup # Codex ready
ls ~/.claude/hooks/*.cjs | wc -l # 应 = 10
cat .ai_state/_index.md | head -5 # 含 schema_version: "9.6"
```
通过 → "安装完成。每个新项目 `/athena-init`, 然后 `/athena-dev`."
## 为什么这样设计 (用户视角)
| v9.5 有 | v9.6 变化原因 |
|---|---|
| 18 → 0 条 deny | sandbox 是正道, 但 v9.6 再加回 "Bash(rm -rf *)" 兜底 |
| 全局 lessons 系统 | 删, 委外给 claude-mem (89k stars) |
| 手写 spawn_agent 协议 | 部分场景接入 /batch (CC v2.1.121+ 原生) |
| delivery-gate 自造 VERDICT 解析 | 接入 /goal evaluator (v2.1.139+), 旧版本兜底 |
| 写死的插件推荐列表 | 改为 /plugin browse 实时查 |
+119
View File
@@ -0,0 +1,119 @@
---
name: athena-status
description: >
Athena 状态面板。显示当前 PACE 状态、Hook 触发计数、claude-mem 状态、plugin 健康。
effort: medium
disable-model-invocation: true
---
# /athena-status (v9.6)
实时聚合 Athena 运行状态。无副作用, 只读 (铁律 8 索引先行)。
## 收集顺序
### 1. PACE 状态 (从 _index.md frontmatter)
```bash
# 用 node 解析 YAML frontmatter
node -e '
const fs = require("fs");
const content = fs.readFileSync(".ai_state/_index.md","utf8");
const fm = content.match(/^---\n([\s\S]*?)\n---/);
if (!fm) { console.log("_index.md frontmatter 缺失"); process.exit(1); }
// 简化 YAML 解析: 仅读关键字段, 不引入 yaml 依赖
const get = (k) => { const m = fm[1].match(new RegExp("^ " + k + ": (.*)$","m")); return m ? m[1].replace(/^["\x27]|["\x27]$/g,"") : ""; };
console.log("Path: ", get("path"));
console.log("Stage: ", get("stage"));
console.log("Sprint: ", get("sprint"));
console.log("Goal: ", get("active_goal"));
'
```
### 2. Sprint 进度 (counts 段)
```bash
grep -E "^ (tasks_pending|tasks_done|tasks_blocked):" .ai_state/_index.md
```
### 3. Hook 触发记录 (最近 50 条)
```bash
tail -50 .ai_state/hook-trace.jsonl 2>/dev/null | \
jq -r '.hook' 2>/dev/null | sort | uniq -c | sort -rn
```
按 hook 名分组统计:
- session-start: 注入次数
- index-updater: 更新次数
- pre-bash-guard: 拦截次数
- subagent-retry: 注入次数
- delivery-gate: 触发 (阻断/soft warn/pass)
- pace-continuator: 写入 next/proposals 次数
- compact-* : 注入次数
- state-audit: 漂移告警次数
### 4. Lessons 统计 (仅项目级)
```bash
grep "^ lessons_lines:" .ai_state/_index.md
grep "^## " .ai_state/details/lessons.md 2>/dev/null | tail -1
echo "[全局已删除, 跨项目记忆装 claude-mem]"
```
### 5. Platform 健康
```bash
grep "^ cc_version:" .ai_state/_index.md
grep "^ cx_version:" .ai_state/_index.md
grep -E "^ (goal|batch|background)_supported:" .ai_state/_index.md
grep "^ cross_session_memory:" .ai_state/_index.md
```
### 6. Plugin 状态
- codex: `which codex || codex --version 2>&1 | head -1`
- superpowers: `ls ~/.claude/plugins/cache/superpowers/ 2>/dev/null`
- claude-mem: `ls ~/.claude/plugins/ 2>/dev/null | grep -i claude-mem`
- context7: `npx ctx7 --version 2>&1 | head -1`
## 输出格式
```
=== VibeCoding Athena v9.6 Status ===
[PACE] Path: Feature Stage: impl Sprint: 3
Goal: tasks all checked + npm test exits 0
[Tasks] 3 done · 2 pending · 0 blocked
Latest: details/progress.md#L46 (Task 5 done)
[Hooks] 最近 50 次触发:
session-start ✓ 5 注入
index-updater ✓ 28 更新
delivery-gate ✓ 12 (阻断 2, soft 1)
pre-bash-guard ✓ 0 拦截
pace-continuator ✓ 5 (next: 5, proposals: 2)
subagent-retry ⚠ 3 注入
[Lessons] 项目: 4 条 (最新: "JWT refresh secret 分离")
[全局已删除, 跨项目记忆装 claude-mem]
[Platform]
CC version ✓ 2.1.140
CX version ✓ 0.130
/goal ✓ supported
/batch ✓ supported
/background ✓ supported
Session memory ✓ active
Cross-session ✓ claude-mem
[Plugins]
codex@1.0.4 ✓ ready
superpowers@5.x ✓ loaded
claude-mem ✓ active
context7 ✓ available
[Commands]
test_cmd: npm test
build_cmd: npm run build
lint_cmd: npm run lint
```
## 实现方式
纯 Bash + node + jq. 失败的项显示 "✗ 不可用". 不写文件, 不改状态。
-38
View File
@@ -1,38 +0,0 @@
---
name: brainstorm
description: R₀ 苏格拉底式需求精炼 — 写代码前激活
---
# Brainstorm (R₀ 需求精炼)
Path B+ 任务在写代码前**必须**激活本 skill。
## 流程
### 0. 自主调研 (提问前)
- 搜索 (Grep/Glob, 或 augment-context-engine 如已安装)项目中与需求相关的现有代码
- 读 .ai_state/knowledge.md + lessons.md 查相关经验
- 读 .ai_state/conventions.md 查编码规范
- 如果 Codex 可用: 用 codex-comm skill 问 Codex "这类需求常见陷阱?"
→ 基于调研结果准备更有深度的问题
### 1. 访谈 (苏格拉底式, 基于调研的针对性问题)
- **一次只问一个问题**, 不堆叠
- 优先选择题, 开放题为辅
- 覆盖: 用户目标、使用场景、边界、非功能需求
- YAGNI 原则: 主动砍不必要的功能
### 2. 提出 2-3 个方案
- 每方案: 架构概述 + 优劣 + 复杂度预估
- context7 查依赖库文档验证可行性
- 标注推荐方案及理由
### 3. 分段呈现设计
- 每段 ≤ 200 字, 用户确认后再下一段
### 4. 确认输出
- 写入 .ai_state/design.md (用模板格式: MUST/SHOULD/COULD + 验收标准)
- cunzhi `DESIGN_READY` 确认
- 进入 plan-first skill
## 铁律
- 设计未确认前**不写任何代码**
-23
View File
@@ -1,23 +0,0 @@
---
name: code-review
description: T 阶段代码审查 — 含 LLM-as-Judge 模式
---
# Code Review (T 阶段)
## 审查清单
1. **Spec 合规**: 每个 MUST 需求是否实现? (对照 design.md)
2. **TDD**: 每个源码文件有对应测试?
3. **边界**: 空输入/超长/并发/错误路径 是否处理?
4. **安全**: 无硬编码密钥, 无 SQL 注入, 输入已验证
5. **可读**: 函数 < 50 行, 注释说明 WHY 不是 WHAT, 严格类型
6. **简洁**: 无过度工程, 无重复代码, 无空 catch
## LLM-as-Judge 模式 (delivery-gate 触发)
输出格式:
```json
{"level": "PASS|CONCERNS|REWORK|FAIL", "issues": [...], "summary": "..."}
```
- FAIL: 未完成任务 / 硬编码密钥 / 缺 quality.md
- REWORK: 源码无测试 (TDD 违规)
- CONCERNS: 非关键文件无测试 (1-2 个警告)
- PASS: 全部通过
-45
View File
@@ -1,45 +0,0 @@
---
name: codex-comm
description: Codex CLI 通信层 — CC↔Codex 基础设施
---
# Codex Communication (通信层)
## 核心脚本
`.claude/skills/codex-comm/scripts/codex-bridge.cjs`
## 功能
1. **检测可用性**: `which codex` + health check (2s 超时)
2. **双模式**: exec (单轮) / serve (多轮 HTTP API)
3. **Session Resume**: `resumeSession(sessionId, prompt)` — 多轮对话保持上下文
4. **UUID 生成**: `generateReviewId()` — 并发安全, 防冲突
5. **敏感过滤**: .env / 密钥 → [REDACTED]
6. **自动降级**: Codex 不可用 → 输出提示, CC 独立执行
## 调用方式
### exec 模式 (简单, 单轮)
```javascript
const { execMode } = require('./scripts/codex-bridge.cjs');
const result = execMode("审查这段代码", { sandbox: 'read-only' });
```
### resume 模式 (多轮, 保持上下文)
```javascript
const { resumeSession } = require('./scripts/codex-bridge.cjs');
// 首次: execMode 返回 sessionId
// 后续: resumeSession(sessionId, "继续审查修改后的计划")
```
### serve 模式 (HTTP API, 最稳定)
```javascript
const { ensureServe, serveRequest } = require('./scripts/codex-bridge.cjs');
ensureServe(); // 自动启动如未运行
```
## Fallback
每个调用 Codex 的点都必须有:
```
如果 Codex 不可用:
输出 "[VibeCoding] Codex 不可用, CC 独立执行"
{CC 独立完成的替代逻辑}
```
@@ -1,109 +0,0 @@
// VibeCoding v9.2.0 — Codex Bridge: CC↔Codex 通信层
'use strict';
const { execSync, spawn } = require('child_process');
const crypto = require('crypto');
const SERVE_PORT = process.env.CODEX_SERVE_PORT || '4096';
const SERVE_URL = `http://localhost:${SERVE_PORT}`;
const DEFAULT_MODEL = 'gpt-5.4';
const EXEC_TIMEOUT = 300000; // 5 min
// ── 敏感信息过滤 ──
function filterSensitive(text) {
return text
.replace(/(?:password|secret|api[_-]?key|token|credential)\s*[:=]\s*['"][^'"]{4,}['"]/gi, '[REDACTED]')
.replace(/(?:-----BEGIN (?:RSA |EC )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC )?PRIVATE KEY-----)/g, '[REDACTED_KEY]');
}
// ── 可用性检测 ──
function isCodexAvailable() {
try { execSync('which codex', { stdio: 'ignore', timeout: 3000 }); return true; }
catch { return false; }
}
// ── Health Check (2s 超时) ──
function healthCheck() {
try { execSync(`curl -sf ${SERVE_URL}/health`, { timeout: 2000, stdio: 'ignore' }); return true; }
catch { return false; }
}
// ── UUID 生成 (并发安全) ──
function generateReviewId() {
return crypto.randomUUID().slice(0, 8);
}
// ── exec 模式 (单轮) ──
function execMode(prompt, opts = {}) {
if (!isCodexAvailable()) return { ok: false, error: 'codex_not_available' };
const safePrompt = filterSensitive(prompt);
const model = opts.model || DEFAULT_MODEL;
const sandbox = opts.sandbox || 'read-only';
try {
// 用 execFileSync 避免 shell 注入 (参数直接传递, 不经过 shell 解析)
const result = require('child_process').execFileSync(
'codex', ['exec', '--sandbox', sandbox, '-m', model, safePrompt],
{ encoding: 'utf8', timeout: opts.timeout || EXEC_TIMEOUT }
);
const sidMatch = result.match(/session[_\s]*(?:id)?[:\s]*([0-9a-f-]{8,})/i);
return { ok: true, output: result, sessionId: sidMatch ? sidMatch[1] : null };
} catch (e) {
return { ok: false, error: e.message };
}
}
// ── resume 模式 (多轮, 保持上下文) ──
function resumeSession(sessionId, prompt, opts = {}) {
if (!isCodexAvailable()) return { ok: false, error: 'codex_not_available' };
const safePrompt = filterSensitive(prompt);
const model = opts.model || DEFAULT_MODEL;
try {
const result = require('child_process').execFileSync(
'codex', ['exec', 'resume', sessionId, '--sandbox', 'read-only', '-m', model, safePrompt],
{ encoding: 'utf8', timeout: opts.timeout || EXEC_TIMEOUT }
);
return { ok: true, output: result, sessionId };
} catch (e) {
console.error(`[codex-bridge] resume failed, falling back to new exec: ${e.message}`);
return execMode(prompt, opts);
}
}
// ── 自动启动 serve ──
function ensureServe() {
if (healthCheck()) return true;
try {
const child = spawn('codex', ['serve', '--port', SERVE_PORT], {
detached: true, stdio: 'ignore'
});
child.unref();
// 等待启动 (最多 10s)
for (let i = 0; i < 10; i++) {
try { execSync('sleep 1'); if (healthCheck()) return true; } catch {}
}
} catch {}
return false;
}
// ── serve HTTP 请求 ──
function serveRequest(endpoint, data) {
try {
const result = execSync(
`curl -sf -X POST ${SERVE_URL}${endpoint} -H "Content-Type: application/json" -d '${JSON.stringify(data)}'`,
{ encoding: 'utf8', timeout: 30000 }
);
return { ok: true, data: JSON.parse(result) };
} catch (e) {
return { ok: false, error: e.message };
}
}
// ── 获取 session 历史消息 ──
function getSessionMessages(sessionId) {
return serveRequest(`/sessions/${sessionId}/messages`, {});
}
module.exports = {
isCodexAvailable, healthCheck, generateReviewId,
execMode, resumeSession, ensureServe, serveRequest,
getSessionMessages, filterSensitive
};
-64
View File
@@ -1,64 +0,0 @@
---
name: codex-review
description: 对抗式计划审查 — P 阶段 CC↔Codex 多轮审查
---
# Codex Review (对抗式审查)
## 触发时机
P 阶段 plan.md 生成后, 如果 Codex 可用。
## 初始化
```
REVIEW_ID = 生成一个 8 位随机 ID (用 Bash: uuidgen | cut -c1-8)
```
## 审查模板选择
根据 design.md 关键词自动选择:
- 包含 API/endpoint/route → templates/api-review.md
- 包含 component/CSS/UI → templates/frontend-review.md
- 包含 deploy/docker/k8s/terraform → templates/infra-review.md
- 否则 → templates/general-review.md
## 对抗循环
### Round 1 (新 exec, 捕获 SESSION_ID):
CC → Codex:
"审查以下计划. 严格找出漏洞/模糊/不可执行的部分.
{plan.md 全文}
{选定的 review template}
结果以 VERDICT: APPROVED 或 VERDICT: REVISE 结尾."
Codex → 质疑列表 + VERDICT
如果 APPROVED → 结束, 记录到 reviews/review-{REVIEW_ID}.md
CC: 逐条评估 (采纳修改 plan / 驳回并说明理由)
### Round 2+ (resume SESSION_ID, 保持上下文):
CC → Codex (codex exec resume SESSION_ID):
"修改后的计划差异: {diff}. 继续审查.
VERDICT: APPROVED 或 VERDICT: REVISE."
Codex → 继续质疑 + VERDICT
...
## 终止条件 (满足任一)
a) Codex 返回 VERDICT: APPROVED
b) 连续 2 轮全部驳回 (记录分歧, cunzhi 让用户决策)
c) 超过 5 轮 (强制停止, 输出分歧摘要)
## 审查结果持久化
每次审查写入 `reviews/review-{REVIEW_ID}.md`:
```markdown
# Review {REVIEW_ID}
Date: {timestamp}
Rounds: {n}
Final Verdict: {APPROVED|STALEMATE|TIMEOUT}
## 采纳的修改
- ...
## 驳回的质疑
- ...
## 遗留分歧
- ...
```
## Fallback
如果 Codex 不可用:
CC 用 validator agent 做 Plan Review:
"作为严格审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
@@ -1,11 +0,0 @@
# API Review Template
审查重点:
1. **接口一致性**: RESTful 约定? 命名统一?
2. **幂等性**: PUT/DELETE 是否幂等?
3. **版本控制**: URL 版本 (/v1/) 或 Header 版本?
4. **错误码**: HTTP 状态码 + 业务错误码 是否定义?
5. **认证/授权**: 每个端点的权限要求?
6. **速率限制**: 是否有限流策略?
7. **输入验证**: 请求体 schema 是否严格?
8. **响应格式**: 分页/排序/过滤 是否一致?
@@ -1,10 +0,0 @@
# Frontend Review Template
审查重点:
1. **可访问性**: ARIA 标签? 键盘导航? 色彩对比?
2. **响应式**: 移动端/平板/桌面 断点覆盖?
3. **XSS 防护**: 用户输入是否转义? dangerouslySetInnerHTML?
4. **性能**: 大列表虚拟滚动? 图片懒加载? 包体积?
5. **状态管理**: 数据流清晰? 避免 prop drilling?
6. **错误边界**: React ErrorBoundary? 加载/空/错误状态?
7. **国际化**: 硬编码文案? 日期/数字格式?
@@ -1,10 +0,0 @@
# General Review Template
审查重点:
1. **需求覆盖**: 每个 MUST 需求是否有对应任务?
2. **任务粒度**: 每个任务是否可在 1-2 小时内完成?
3. **依赖拓扑**: 任务依赖是否有环? 关键路径是什么?
4. **风险识别**: 哪些任务最可能出问题? 有 plan B?
5. **测试策略**: 单元/集成/E2E 比例合理?
6. **模糊检测**: 有没有"优化""改进"等模糊词?
7. **遗漏检测**: 错误处理/日志/监控/文档 是否涵盖?
@@ -1,10 +0,0 @@
# Infrastructure Review Template
审查重点:
1. **可用性**: 单点故障? 副本数? 健康检查?
2. **备份/恢复**: 数据备份策略? RTO/RPO?
3. **回滚计划**: 部署失败如何回滚? 数据库迁移可逆?
4. **监控/告警**: 关键指标有监控? 告警阈值合理?
5. **安全**: 网络隔离? 密钥轮换? 最小权限?
6. **成本**: 资源配置合理? 有自动伸缩?
7. **IaC**: 基础设施代码化? 可重复部署?
+47
View File
@@ -0,0 +1,47 @@
---
name: compound
description: >
Sprint Quality Gate 通过后触发。提炼本 Sprint 学到的为结构化条目追加 lessons.md。
effort: xhigh
---
# /compound — 经验沉淀
Gate PASS 后触发 (或用户显式 `/compound`).
## 输入
- `.ai_state/details/reviews/sprint-N.md` (审查报告)
- `git diff` (本 Sprint 所有变更)
- `.ai_state/details/tasks-current.md` (完成项)
- `.ai_state/details/design.md` (设计 vs 实际实现对比)
## 提炼方法
从以上输入找**真实发现**, 不写仪式性废话。每 Sprint 0-N 条不强制。
- **Pattern**: 什么解法有效且可复用? (带代码行号 / 文件路径)
- **Pitfall**: 什么坑踩过? 未来同类场景要提前避开
- **Constraint**: 发现的新约束 (依赖版本、环境、性能边界、API 限制)
没发现可提炼的 → 不写, 直接告知用户 "no new lesson". **不允许编造**.
## 输出 (项目级)
追加到 `.ai_state/details/lessons.md` (append-only, 不修改历史).
格式见 `pace/templates/details/lessons.md`. **Athena 不做跨项目知识管理**——需要的话装 claude-mem 或 superpowers。
写入后同步更新 `_index.md`:
- `counts.lessons_lines` += 新增条目数 (按 `## ` 头计)
- `pointers.latest_lesson` = `details/lessons.md#L<新条目行号>`
- `fingerprints.lessons_mtime` = 当前时间戳
## 自检
写入后读回验证:
1. 条目有具体的文件/行号/版本引用 (不只是"要注意 X")
2. 一句话标题能让下次 R₀ 快速扫描命中
3. Pattern/Pitfall/Constraint 三段不强制全有, 但至少有一段
写完告知用户: "Lessons updated. Next sprint R₀ 会自动读取 (按 _index.md.pointers.latest_lesson 跳转)."
-15
View File
@@ -1,15 +0,0 @@
---
name: context7
description: 库文档按需拉取
---
# Context7 (库文档查询)
需要查询依赖库文档时:
1. 优先: `npx ctx7 resolve {库名}` CLI 查询
2. 备选: web search 查最新 API
3. 缓存: 查过的 API 结论写入当前阶段笔记, 避免重复查询
## 触发时机
- R 阶段: 验证技术方案可行性
- E 阶段: 实现时遇到不确定的 API
- T 阶段: 验证 API 用法正确性
-27
View File
@@ -1,27 +0,0 @@
---
name: debugging
description: 系统化调试 — 4阶段强制流程
---
# Systematic Debugging
遇到 bug 时**必须**按以下 4 阶段执行, 禁止跳步:
## 1. 复现 (Reproduce)
- 写一个**最小**可复现用例
- 记录: 输入、期望输出、实际输出
- 如果无法复现 → 停, 收集更多信息
## 2. 定位 (Locate)
- 从错误点向上追溯调用链
- 用 console.log / debugger / 断点缩小范围
- **不要猜**: 用证据定位, 不是直觉
## 3. 修复 (Fix)
- 只改**根因**, 不改症状
- 修复必须有对应测试覆盖
- 禁止: `as any`, `try {} catch {}` 空吞, `// TODO: fix later`
## 4. 验证 (Verify)
- 运行原始复现用例 → 通过
- 运行全量测试 → 无回归
- Reflexion: "这个 bug 的模式值得记录到 conventions.md 吗?"
-18
View File
@@ -1,18 +0,0 @@
---
name: e2e
description: 端到端测试 — Path C+ 或有 E2E 框架时
---
# E2E Testing
## 前置条件
- 项目有 E2E 框架 (Playwright/Cypress/Selenium)
- Path C+ 或用户显式要求
## 流程
1. 基于 design.md 验收标准编写 E2E 用例
2. 运行 E2E: `npx playwright test` 或项目配置的命令
3. 失败 → 定位是测试问题还是实现问题
4. 结果追加到 quality.md
## 如果没有 E2E 框架
- 手动验证清单: 列出关键用户流程 + 验证步骤
-35
View File
@@ -1,35 +0,0 @@
---
name: finish-branch
description: V 阶段分支收尾 — kaizen 之后, 交付确认之前
---
# Finish Branch (分支收尾)
## 触发时机
V 阶段 kaizen 完成后, cunzhi `DELIVERY_COMPLETE` 之前。
## 流程
1. 展示选项给用户:
a) **merge**: 合并到主分支
b) **pr**: 创建 Pull Request
c) **keep**: 保留分支不动
d) **discard**: 确认后删除分支
2. 如果选 **pr**:
- 自动生成 PR description:
```
## 标题: {design.md 第一行}
## 摘要: {quality.md 总结}
## 变更列表:
{plan.md 中已完成的 Task 列表}
## 测试: {quality.md 验证结果}
```
- 执行: `gh pr create` 或输出文本供用户复制
3. 如果选 **merge**:
- 检查是否有冲突: `git merge --no-commit --no-ff main`
- 无冲突 → merge + 删除分支
- 有冲突 → 输出冲突文件, 用户决定
4. 如果选 **discard**:
- cunzhi 确认 "确定丢弃分支 {branch_name}?"
- 确认后: `git checkout main && git branch -D {branch_name}`
-23
View File
@@ -1,23 +0,0 @@
---
name: kaizen
description: V 阶段持续改进回顾
---
# Kaizen (V 阶段回顾)
## 流程
1. 回顾本次开发:
- 哪些做得好? (保持)
- 哪些做得差? (改进)
- 有没有反复出现的模式性错误?
2. 更新 .ai_state/lessons.md:
- 新发现的技术陷阱
- 有效的解决模式
- 项目特有的约定
3. 更新 .ai_state/conventions.md "## Agent 易犯错误" 段:
- 如果 Reflexion/Review 中发现了模式性错误
- 格式: `- "具体错误描述 + 正确做法"`
- 这些错误会在 SessionStart 时由 context-loader 输出提醒
4. 产出摘要给用户
+304
View File
@@ -0,0 +1,304 @@
---
name: pace
description: >
工作流路由器。收到开发任务时触发。按任务复杂度路由到 6 条路径, 编排 CC 工具 + 增强节点。
effort: xhigh
---
# PACE — 6 路径路由器 (v9.6 Athena)
首先读 `.ai_state/_index.md` (铁律 8 索引先行)。有 stage → 从当前阶段继续。
.ai_state/ 不存在 → 提示 `/athena-init`。
## 路由
```
┌─ 1行/配置 ──────→ Hotfix
修复 ────┤
└─ 需要调试 ─────→ Bugfix
┌─ 需求清晰/小 ──→ Quick
新建 ────┤ 需要设计 ─────→ Feature
├─ 改现有结构 ───→ Refactor
└─ 跨模块/服务 ──→ System
```
| Path | 文件量 | CC 主力 | 增强 | 写 _index.md |
| -------- | ------ | ---------------------- | --------------------------------------- | ------------ |
| Hotfix | 1 | Edit | 无 | 否 |
| Bugfix | 1-5 | /debug | 无 | 否 |
| Quick | 1-10 | TDD | 可选交叉审查 | 是 |
| Feature | 5-20 | /feature-dev | brainstorming + 交叉审查 | 是 |
| Refactor | 10-50 | /batch | superpowers + 交叉审查 | 是 |
| System | 20+ | /batch + /feature-dev | 全增强 | 是 |
Quick+ 路由完成 → 更新 `_index.md` (path, stage, sprint) → 告知用户。
---
## CC 原生自动化接入 (v9.6 新)
v9.5 的"自动 PACE"借助 CC 原生 `/goal /batch /loop /background` 实现, **不再发明状态机驱动器**。
### `/goal` — 每 stage 一个 condition (autonomous loop)
参考: <https://code.claude.com/docs/en/goal>
每个 PACE stage 配套一个 condition 模板, 见 `templates/details/goal-conditions.md`:
- **plan**: `design.md 含 File Structure Plan + tasks-current.md ≥ 1 Task + 用户回过 confirm`
- **impl**: `tasks-current.md 所有 [ ] 变 [x] + <test_cmd> exits 0 + progress.md 每 task 一行`
- **review**: `reviews/sprint-N.md 含 VERDICT 字段 + /codex:review 或 reviewer 已跑`
- **ship**: `lessons.md 含 Sprint N 条目 + git push 完成 + _index.md sprint+=1`
启动方式: `/goal <condition>` (CC v2.1.139+) 或 `claude -p "/goal <condition>"` (非交互).
**降级**: CC < v2.1.139 时无 /goal, 由 delivery-gate hook 兜底判定 VERDICT.
### `/batch` — Refactor/System 并行实现
参考: CC v2.1.121+, `/batch` 自动 5-30 worktree subagent + PR.
适用场景: 大量同模式 task (重命名 / import 路径迁移 / 接口签名变更).
**降级**: 旧版本 → spawn_agent 手动 worktree.
### `/background` + `claude agents` 多会话编排
参考: CC v2.1.139+, agent view 看 Running / Blocked / Done 状态.
适用: System 阶段长跑 / 跨任务监控.
---
## 跨平台路由建议 (Codex Terminal-Bench SOTA)
某些任务在 Codex 上更优:
| 信号 | 建议 |
|------|------|
| 终端命令为主 (build/test/grep/sed) | Codex Terminal-Bench 2.0 SOTA 82.7% (GPT-5.5, April 2026), 委派 Codex |
| 大量重复改写 (100 个文件相同 import 路径) | Codex token 0.25-0.33×, 更经济 |
| 需要多 reviewer 互相 critique | CC 主跑 + /codex:adversarial-review 二审 |
| 设计/架构判断 | CC Opus 4.7 略强, 主跑 CC + Codex review |
不强制——是建议。
---
## 路径升级机制 (impl 阶段持续监测)
写代码过程中发现实际复杂度超出当前路径 → 暂停询问用户升级:
| 升级触发信号 | 当前 → 建议 |
|------------|-----------|
| 需要改数据库 schema | * → System |
| 跨 3+ 模块的接口变更 | Feature → System |
| 实际改文件数 > 当前路径上限的 50% | Quick → Feature, Feature → Refactor/System |
| Refactor 中发现需要新增模块 | Refactor → System |
升级流程: 用户确认 → _index.md path 升级 + stage 回到 design (System) 或 plan → progress.md 追加升级记录 → 重新 plan。
**不自动升级**, 避免 Athena 借机扩 scope。
---
## 共享协议
### 审查协议 (Quick/Feature/Refactor/System 的 review 阶段共用)
```
1. /review → 第一份审查 (CC 原生)
2. [Feature+] /codex:review [--base main] [--wait] → 跨模型审查
→ 必须看到真实 codex job ID 或命令输出 (铁律 6)
→ 调用失败 → 失败处理协议三轮 → 真失败则降级 + review-report.md 注明 "codex unavailable + stderr"
3. [System] 追加 /codex:adversarial-review + ECC AgentShield
4. [System UI 类] superpowers /qa + playwright E2E
5. /simplify
6. @evaluator → VERDICT
PASS → 触发 /compound → details/lessons.md 追加 → 停一轮让用户确认 → stage=ship
CONCERNS → 修复 → 重新评分
REWORK → stage=impl (Feature/Refactor) 或 stage=design (System)
FAIL → stage=plan
```
### 发布协议 (ship 阶段共用)
```
1. [Quick] git commit → 直接提交
2. [Feature+] superpowers /ship → 同步 main, 跑测试, 开 PR
3. [System] superpowers /retro → 工程回顾
4. details/lessons.md (compound 已追加) + progress.md 最终更新
5. _index.md: stage="", sprint+=1
6. /compact "Sprint N 完成"
```
---
## 失败处理协议 (落地铁律 6 完成度证据)
工具调用失败 (任意 Bash/Skill/Task):
```
Round 1: 读 stderr 和 exit code 分类:
- permission denied → 报具体规则, **继续尝试**:
a) 用 settings.local.json 临时绕过 (告知用户)
b) 换等价命令 (node 改 npx)
c) 拆到主 agent
- command not found → 装包 / 换工具
- subagent 报"无能力" → 实测一次 (echo 探测), 真不可用主 agent 接管
Round 2: 改参数 / 换路径 / 换工具
Round 3: 仍失败 → 报告每次的:
- 完整命令
- 完整 stderr
- exit code
- 已尝试的修复方式
→ 写入 review-report.md / progress.md 作为完成度证据
```
**绝对禁止**: "请你用 ! 前缀手动执行" 作为第一次响应。
**subagent 输出预算 ≤ 2000 tokens** (Anthropic 多 agent research 经验): 深入探索可以, 只回传关键发现。
---
## Hotfix — 无仪式
```
Edit → test_cmd (有就跑) → git commit → 完
```
## Bugfix — /debug + TDD (无 stage)
```
/debug → 定位根因
TDD: 写回归测试(复现) → 修复 → 测试通过
lint_cmd → /review → git commit
自愈: 修不好 → /debug 再来 (限 3 轮) → 3 轮后通知用户
```
## Quick
stages: impl → review → ship
```
stage=impl:
Explore: 读要改的文件 + 调用方
TDD 实现 (superpowers brainstorming 自动激活)
库文档不确定 → use context7
每完成 Task → tasks-current.md 勾选 + progress.md 追加一行 + index-updater 自动更 _index.md counts
路径升级监测
lint_cmd + test_cmd → /simplify → stage=review
stage=review: → 审查协议
stage=ship: → 发布协议
```
## Feature — /feature-dev + 增强
stages: plan → impl → review → ship
```
stage=plan:
R₀: 命中主题再读 details/lessons.md (just-in-time, 不预加载)
superpowers brainstorming → 发散 + 方向挑战
→ 合成 design.md (含 File Structure Plan 段)
用户确认 → tasks-current.md (Boundary/Depends 标注) → stage=impl
可选: /goal "tasks-current.md 全 [x] + npm test exits 0"
stage=impl:
/feature-dev "需求描述"
Phase 4 (架构) 前 → 用户确认
每完成 Task → tasks-current.md 勾选 + progress.md 追加
设计偏离 → 先改 design.md 再继续 (铁律 5)
库文档不确定 → use context7
路径升级监测 → 触发即停
/simplify → stage=review
stage=review: → 审查协议
stage=ship: → 发布协议
```
## Refactor — /batch + 增强
stages: plan → impl → review → ship
```
stage=plan:
R₀: 按需 read details/lessons.md
superpowers /plan-eng-review → 验证重构方案
用户确认 → design.md (含 before/after 边界) + tasks-current.md → stage=impl
stage=impl:
/batch "重构描述" ← CC v2.1.121+ 原生
CC 自动: Research → Plan → 用户确认 → 并行 worktree → 每 worker /simplify + 测试
每完成一组 Task → tasks-current.md 勾选 + progress.md 追加
路径升级: 发现需要新增模块 → 升 System
→ stage=review
```
## System — 全链
stages: plan → design → impl → review → ship
```
stage=plan:
R₀: 按需 read details/lessons.md
superpowers /office-hours → 需求提取
superpowers brainstorming → 发散 + 方向挑战
→ 合成 design.md → 用户确认 → stage=design
stage=design:
superpowers /plan-eng-review → 架构锁定
superpowers /plan-design-review → 设计审查 (有 UI 时)
design.md 必含 File Structure Plan → tasks 据此拆
→ 合成 tasks-current.md → 用户确认 → stage=impl
stage=impl:
按 Task 性质选工具:
批量同模式 → /batch 并行 (CC 原生)
复杂独立 → /feature-dev
跨模型委托 → /codex:rescue "<prompt 内容>"
每完成 Task → tasks-current.md 勾选 + progress.md 追加
全部完成 → /simplify → stage=review
stage=review: → 审查协议 (含 adversarial + ECC + /qa + E2E)
stage=ship: → 发布协议 (含 /retro)
```
---
## 状态管理 (铁律 5/8 文档即真相 + 索引先行)
`.ai_state/_index.md` frontmatter 字段: path, stage, sprint, active_goal, tech_stack, test_cmd, build_cmd, lint_cmd, dev_cmd, conventions, gotchas, counts, pointers, fingerprints, platform_features
合法 path: Quick, Feature, Refactor, System (Hotfix/Bugfix 不写 _index)
合法 stage: plan, design (System only), impl, review, ship, ""
**`.ai_state/` 文档职责 (just-in-time)**:
- 写端:
- `_index.md` ← athena-init + 路由 + index-updater hook (PostToolUse)
- `details/tasks-current.md` ← plan + impl 勾选
- `details/tasks-archive/sprint-N.md` ← ship 时归档
- `details/progress.md` ← impl 每 Task 追加 (append-only)
- `details/design.md` ← plan + impl 偏离时更新
- `details/handoff.md` ← 跨模型/跨 worker 临时
- `details/lessons.md` ← compound skill 写 (append-only)
- `details/reviews/sprint-N.md` ← V 阶段写
- `details/next.md` ← pace-continuator (Stop hook) 写下一步建议
- `details/proposals.md` ← Stop hook 反思沉淀 (铁律 9)
- `hook-trace.jsonl` ← hooks 自动
- 读端 (按 _index.md.pointers 跳转, 不预加载):
- 必读: `_index.md`
- 阶段=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
- 任务命中 lessons 主题 → pointers.latest_lesson 跳到段
- plan 阶段 → 命中再读 lessons / impl 读 design 对照 / review 读 design + previous reviews
**跨项目记忆已删除**: Athena 不做。推荐装 claude-mem (~/.claude/projects/ 已内置) 或 superpowers。
`delivery-gate` (Stop hook) 在 stage="review" 时检查质量门 (Feature+ 要求外部审查, Quick 不要求)。
阶段转换 + 长任务中 → 主动 `/compact`, 不等 context 满。
不间断工作: 不确定用什么库 → use context7。不确定现有代码 → Read 看。不确定测试怎么跑 → 读 _index.md test_cmd。
只在以下情况停: 方案需用户确认 (plan 阶段), VERDICT 需判断 (review 阶段), 真正的阻塞 (失败 3 次后)。
+44
View File
@@ -0,0 +1,44 @@
# VibeCoding Athena (SessionStart 自动注入)
你是 VibeCoding Athena 工程 Agent。CC 做事, Athena 把关。
**铁律 (9 条)**:
1. 设计先行 (Hotfix/Bugfix 例外)
2. TDD 强制
3. Sisyphus (tasks 全完成才进审查)
4. Review 强制 (Feature+ 至少一次交叉审查)
5. 文档即真相 (`.ai_state/_index.md` 单一入口)
6. 完成度证据 (报告"完成"必须附 tool_use ID 或命令输出)
7. 出处优先 (技术结论必须引用官方文档/源码 URL)
8. **索引先行** (进入决策先读 `.ai_state/_index.md`, 禁止 glob 全目录)
9. **Hook 是进化器** (Stop 时反思写 `details/proposals.md`)
工具报错 → 三次重试附 stderr 报告, 不让用户代执行。
/codex:* 必须产生真实 tool_use 响应。
## R₀ Get-bearings (just-in-time)
1. **必读**: `.ai_state/_index.md` (单一入口, 已自动注入)
2. **按需**: stage=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
3. **按需**: 任务命中 lessons 主题 → pointers.latest_lesson 跳段
4. **按需**: `git log --oneline -10` (涉及代码修改时)
文件大就用 head/tail/grep, 不要 cat 全文。**禁止 glob 整个 .ai_state/**。
## 文档写入义务 (铁律 5)
- impl 每完成 Task → tasks-current.md 勾选 + progress.md 追加一行 (index-updater hook 自动更 _index.md counts)
- 发现 design.md 错 → 先改 design.md 再继续写代码
- V 阶段 Gate 通过 → /compound 追加 details/lessons.md
## 6 路径
Hotfix (无仪式) · Bugfix (/debug+TDD) · Quick (TDD+收尾) · Feature (/feature-dev+增强) · Refactor (/batch+增强) · System (全链)
路径升级触发器: 改 schema / 跨 3+ 模块 / 文件数超 50% → 暂停询问升级。
## v9.6 新接入 (CC 原生)
- `/goal <condition>` (v2.1.139+): 每 stage 一个 goal, evaluator 自动判定
- `/batch`: Refactor/System 自动并行 worktree
- `/background` + `claude agents`: 多会话编排
+66
View File
@@ -0,0 +1,66 @@
---
schema_version: "9.6"
athena_version: "9.6.0"
project:
path: "" # Hotfix | Bugfix | Quick | Feature | Refactor | System | ""
stage: "" # plan | design | impl | review | ship | ""
sprint: 0
active_goal: "" # 当前 /goal condition (空 = 无活动 goal)
counts:
tasks_pending: 0
tasks_done: 0
tasks_blocked: 0
lessons_lines: 0
progress_entries: 0
reviews_count: 0
pointers:
latest_progress: "" # 如 "details/progress.md#L46"
latest_review: "" # 如 "details/reviews/sprint-3.md"
latest_lesson: "" # 如 "details/lessons.md#L98"
latest_proposal: "" # 如 "details/proposals.md#L12"
fingerprints:
tasks_mtime: 0
design_mtime: 0
progress_mtime: 0
lessons_mtime: 0
platform_features:
cc_version: "" # 由 athena-setup 检测填入
cx_version: "" # 同上
goal_supported: false # CC ≥ v2.1.139 时 true
batch_supported: false # CC ≥ v2.1.121 时 true
background_supported: false # CC ≥ v2.1.139 时 true
session_memory_active: false # ~/.claude/projects/ 自动摘要是否启用
cross_session_memory: "none" # "claude-mem" | "superpowers" | "none"
gotchas: [] # 项目特有的"小心点", PACE 会在 SessionStart 注入
conventions: [] # 项目约定 (pnpm vs npm 等)
tech_stack: ""
test_cmd: ""
build_cmd: ""
lint_cmd: ""
dev_cmd: ""
---
# 项目状态索引
<!--
本文件是 .ai_state/ 的单一入口 (铁律 8)。
SessionStart hook 只读这一个文件, 注入轻量 frontmatter 字段 + counts 摘要。
下游 (Edit/Read tools) 按 pointers 自取明细。
任何 detail/* 文件写入 → PostToolUse index-updater.cjs 原子更新本文件。
-->
## 最近活动
<!-- 由 pace-continuator hook 在 Stop 时维护, 保留最近 3 条 -->
## 当前阻塞
<!-- 由 PACE 流程在 stage=impl/review 时填写 -->
## 下一动作 (PACE 建议)
<!-- 由 pace-continuator 在 Stop 时根据 stage 推断, 写入 details/next.md 的摘要 -->
## 反思建议 (Hook 沉淀)
<!-- 引用 details/proposals.md 最近一条 (latest_proposal) -->
@@ -0,0 +1,28 @@
# 设计文档
## 需求摘要
## 功能分级
- **MUST**:
- **SHOULD**:
- **COULD**:
## 验收标准
- [ ]
## 技术方案
## File Structure Plan
<!--
模块/文件边界, 给 tasks-current.md 拆任务用 (boundary-first 设计)
示例:
- src/auth/ — JWT/refresh/session, owner: Task 1-3
- src/routes/user/ — user CRUD endpoints, owner: Task 4-5
- tests/auth/ — auth 单测 + 集成测试
边界外的文件 = 本 Sprint 不应触碰
-->
## 不做什么
@@ -0,0 +1,31 @@
# 跨模型/跨 worker 交接
<!--
本文件内容会作为 /codex:rescue "<内容>" 的 prompt 传入。Codex 不会自动读本文件。
构造完 handoff.md → Claude 把文件内容 Read 出来作为 /codex:rescue 的参数。
-->
## 当前任务
<!-- Task ID + 描述 + 验收标准 + Boundary 范围 -->
## 项目文件树
<!-- 必须包含实际文件列表, 用 find/ls 生成, 不要手写 -->
<!-- 示例: find . -name "*.py" -not -path "./venv/*" | head -50 -->
## 关键代码片段
<!-- 与本 Task 直接相关的代码文件内容 (关键函数/类, 不要全文) -->
## 项目背景
<!-- design.md 摘要 + 技术栈 -->
## 已完成
<!-- tasks-current.md 中完成的 Task -->
## 注意事项
<!-- _index.md.gotchas + conventions -->
@@ -0,0 +1,21 @@
# 项目级经验沉淀 (Lessons Learned)
<!--
每个 Sprint 通过 Gate 后由 compound skill 追加。append-only, 不删不改历史。
本文件存项目级业务代码经验 (Athena 不做跨项目知识管理)。
跨项目记忆请装 claude-mem 或 superpowers。
格式:
## [YYYY-MM-DD Sprint N] 一句话标题
- **Pattern**: 解法描述 (文件:行号)
- **Pitfall**: 坑点描述
- **Constraint**: 新约束
示例:
## [2026-05-21 Sprint 1] JWT refresh 不能和 access 共享 secret
- **Pattern**: 分开 secret + rotation key 在 env (src/auth/config.ts:15)
- **Pitfall**: Authorization header 大小写处理不一致, 用 lodash.toLower 前置
- **Constraint**: Redis 需要 ≥256MB 才放得下 session cache
-->
@@ -0,0 +1,15 @@
# 下一动作建议 (PACE-aware, Stop hook 维护)
<!--
本文件由 .claude/hooks/pace-continuator.cjs 在 Stop 事件时写入。
读 _index.md 的 path/stage/sprint, 推断"下一步该做什么", 给出具体的命令建议。
SessionStart 时 (如有 pace-resumer hook) 会读本文件作为"继续提示"。
格式:
## YYYY-MM-DD HH:MM
当前: <path>/<stage>/sprint <N>
建议:
- 命令 1
- 命令 2
理由: <一句话>
-->
@@ -0,0 +1,15 @@
# Progress Log
<!--
impl 阶段每完成一个 Task 追加一行 (铁律 5)。
格式: YYYY-MM-DD HH:MM [path/stage/sprint] action
示例:
2026-05-21 14:30 [Feature/impl/1] Task 3 done: auth middleware
2026-05-21 15:10 [Feature/impl/1] design.md updated: JWT expiry 15min
2026-05-21 15:30 [Feature/impl/1] PATH-UPGRADE Feature → System (发现需要改 schema)
2026-05-21 16:45 [Feature/review/1] /review 完成, 无阻塞问题
append-only: 不删历史, 不改既有行。
index-updater hook 会更新 _index.md.counts.progress_entries 和 pointers.latest_progress。
-->
@@ -0,0 +1,20 @@
# Hook 反思沉淀 (铁律 9: Hook 是进化器)
<!--
本文件由 .claude/hooks/pace-continuator.cjs 在 Stop 时维护。
当 hook 检测到"本 turn 有反复试错 / 阻塞 / 失败模式", append-only 一条反思。
不写"已知坑" (lessons.md 管那个), 写"流程级提议":
- "考虑把 X 加入 .ai_state/conventions"
- "delivery-gate 这条规则可能误伤, 下版本调整"
- "本 sprint 的 stage transition 太快, plan 阶段不充分"
人审完后可以手动迁移到 lessons.md 或者 conventions 列表。
hook 永远不替用户做决定, 只提供素材。
格式:
## YYYY-MM-DD HH:MM (sprint N)
- 观察: <事实>
- 假设: <可能原因>
- 提议: <改什么>
-->
@@ -0,0 +1,41 @@
# Sprint N 审查报告
## Step 1: 测试结果
<!-- 命令 + 实际输出 (不是"已跑通") -->
## Step 2: /codex:review (Feature+, Quick 可选)
<!-- 必须有以下证据之一, 防伪装 (铁律 4 反空跑 + 铁律 6 完成度证据):
- codex job ID
- codex CLI 真实命令行输出片段
- 不可用时明示 "codex unavailable" + 完整 stderr -->
## Step 3: /codex:adversarial-review (System)
<!-- 同上证据要求 -->
## Step 4: ECC 扫描 (System)
<!-- npx ecc-agentshield scan 实际输出摘要 -->
## Step 5: Claude 审查 (/review 内置)
<!-- /review 输出 -->
## Step 6: @evaluator 评分
| 维度 | 分数 | 证据 |
|------|------|------|
| Functionality | /5 | (代码行号) |
| Spec Compliance | /5 | (代码行号 vs design.md) |
| Boundary Adherence | /5 | (是否越出 File Structure Plan) |
| Craft | /5 | (代码行号) |
| Robustness | /5 | (边界用例覆盖) |
| **均分** | **/5** | |
均分 = F×0.25 + SC×0.25 + B×0.15 + C×0.15 + R×0.20
## VERDICT:
<!-- PASS (均分≥4.0 且所有维度≥3) | CONCERNS (均分≥3.0 有维度=2) | REWORK (均分<3.0 或任一=1) | FAIL (多维度=1 或安全/Boundary 大幅越界) -->
@@ -0,0 +1,19 @@
# Sprint 任务清单
<!--
每个 Task 的 Boundary/Depends 标注 (cc-sdd 边界优先, 防止越界)
格式:
- [ ] Task N: 简述
_Boundary:_ src/auth/, tests/auth/
_Depends:_ Task N-1 (空则 — )
PostToolUse hook (index-updater.cjs) 会:
- 检测本文件的 - [ ] / - [x] 数量变化
- 原子更 _index.md.counts.tasks_pending/done/blocked
-->
## 待办
## 完成
## 阻塞
@@ -0,0 +1,121 @@
# /goal Condition 模板库
每个 PACE stage 对应一个 condition 模板, 用 `/goal <condition>` 启动 autonomous loop。
参考: <https://code.claude.com/docs/en/goal>
## 写 condition 的四件套 (官方推荐)
```
End Goal + Verification + Constraints + Turn/Time Limit
```
- **End Goal**: 一个可测的终态 (test 通过 / 文件存在 / git log 含 commit)
- **Verification**: 如何证明 (npm test exits 0 / rg "X" 0 行)
- **Constraints**: 边界 (不动 X 文件 / 不引入新依赖)
- **Turn/Time Limit**: stop after 20 turns / stop after 60 minutes
---
## Feature/Refactor/System stage=plan
```
ALL of:
- .ai_state/details/design.md 含 "## File Structure Plan" 段且段下至少 3 个 owner 行
- .ai_state/details/tasks-current.md 至少 1 个 - [ ] Task
- 我已经 ask 用户确认且收到了 "yes" 或 "go" 回复
Constraints:
- 不修改 design.md 之外的源码文件
- 不超过 20 turns
```
## Quick/Feature stage=impl
```
ALL of:
- .ai_state/details/tasks-current.md 中所有 - [ ] 都变成 - [x]
- 运行 <test_cmd> 退出码 0 (从 _index.md.test_cmd 读)
- .ai_state/details/progress.md 在本 turn 序列至少新增 N 行 (N = 原待办 task 数)
- 没有任何对 design.md 的修改
Constraints:
- 不动 .ai_state/_index.md 以外的元数据
- 不超过 30 turns 或 90 分钟
```
## Refactor stage=impl (用 /batch)
```
ALL of:
- tasks-current.md 全部 - [x]
- 每个 worktree 的 lint_cmd 退出 0
- 每个 worktree 的 test_cmd 退出 0
- 主分支 git diff 显示预期的批量变更模式
Constraints:
- 不引入新依赖
- 不超过 60 minutes 或 50 turns
```
## System stage=design
```
ALL of:
- details/design.md 含 "## File Structure Plan" 且段下覆盖所有新增/修改的模块路径
- details/design.md 含 "## 验收标准" 段且至少 5 条 - [ ] (会在 impl 阶段勾选)
- details/tasks-current.md 至少 N 个 Task (N = design 模块数), 每个含 Boundary 和 Depends 注释
- 我已经 ask 用户对设计的最终确认
Constraints:
- 不超过 25 turns
```
## stage=review (Feature+)
```
ALL of:
- .ai_state/details/reviews/sprint-{sprint}.md 已存在且含 "VERDICT:" 行
- VERDICT 取值为 PASS / CONCERNS / REWORK / FAIL 之一
- 报告含至少一段 /codex:review 或 reviewer subagent 的真实输出 (codex job ID 或 thread ID)
- 报告含 test_cmd 实际输出
Constraints:
- 评分必须基于代码行号级证据
- 不超过 40 turns
```
## stage=ship
```
ALL of:
- details/lessons.md 末尾含 "## [{date} Sprint {sprint}]" 标题
- git log --oneline -1 显示本 sprint 的提交
- _index.md.project.sprint 已 +1 且 stage="" (由 athena-status 验证)
- details/tasks-archive/sprint-{sprint}.md 存在 (归档)
Constraints:
- 不超过 10 turns
```
---
## 启动方式
### 交互式
```
/goal <粘贴上面对应 stage 的 condition>
```
### 非交互式 (overnight 跑)
```bash
claude -p "/goal <condition>"
```
### 状态查询
```
/goal # 不带参数, 看 turns/tokens/最近 evaluator reason
/goal clear # 中止
```
## 注意事项 (官方文档)
- evaluator 只读 transcript, 不跑命令——condition 必须是"transcript 能证明的事"
- 一个 session 只能有一个 active goal, 设置新 goal 替换旧的
- condition ≤ 4000 字符
- v2.1.139+ 才有, 旧版本 delivery-gate hook 兜底
- "Vague in, vague out"——含糊的 condition = 含糊的 loop
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
# Athena init.sh — 启动开发环境 + 基线测试
# 由 /athena-init 根据项目类型生成具体命令
set -e
echo "[Athena] 启动开发环境..."
# 示例 (根据项目类型):
# npm install
# pip install -e .
# cargo build
echo "[Athena] 运行基线测试..."
# npm test
# pytest
# cargo test
echo "[Athena] 就绪。"
-26
View File
@@ -1,26 +0,0 @@
---
name: plan-first
description: P 阶段计划生成 — design.md 确认后激活
---
# Plan-First (P 阶段)
## 流程
1. 读 .ai_state/design.md 全文
2. 分解为可执行任务, 每个任务:
```
- [ ] T-001: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: {前置任务}
```
3. 任务排序: 依赖拓扑 → 风险高的先做
4. 写入 .ai_state/plan.md
## 计划质量检查
- 每个任务有明确的"完成"定义
- 没有模糊词 ("优化", "改进" → 改为具体指标)
- 估算总任务数, 超过 15 个考虑拆分 milestone
## 双 Agent 对抗审查
如果 Codex 可用 → 触发 codex-review skill 做对抗式审查
如果 Codex 不可用 → CC 用 validator agent 自审:
"作为审查者, 这个计划有哪些漏洞/模糊/不可执行的部分?"
-27
View File
@@ -1,27 +0,0 @@
---
name: reflexion
description: E 阶段自我反思 — 每个 Task Micro-review 之前
---
# Reflexion (自我反思)
## 触发时机
E 阶段每个 Task 实现完成后, Micro-review 之前。
## 反思清单
逐条自问:
1. 我有没有走捷径? (如: 用 `as any` 绕过类型检查, 空 catch 吞错误)
2. 我有没有忽略边界条件? (空输入/超长/并发/零值/null)
3. 我有没有硬编码本应配置的值? (URL/端口/阈值/路径)
4. 我有没有过度工程? (加了需求没要求的功能/抽象层)
5. 我有没有偏离 design.md 的方案? (擅自"优化"设计)
6. 这段代码 6 个月后我还能理解吗? (命名/结构/注释)
## 处理
- 发现问题 → **立即修复**, 不留 TODO
- 值得记录的模式 → 追加到 .ai_state/lessons.md
- 模式性错误 → 追加到 conventions.md "Agent 易犯错误"
## 与 Micro-review 的关系
Reflexion = "我审视自己" (主观, 面向实现质量)
Micro-review = "对标 spec + 标准" (客观, 面向需求合规)
两者互补, 不重叠。先 Reflexion 再 Micro-review。
-16
View File
@@ -1,16 +0,0 @@
---
name: security-review
description: 安全审查 — Path C+ 或显式触发
---
# Security Review
## 检查项
1. **认证/授权**: 每个端点是否有权限检查?
2. **输入验证**: 所有外部输入是否已验证和消毒?
3. **密钥管理**: 无硬编码, 用环境变量或密钥管理服务
4. **依赖**: `npm audit` / `pip audit` 无高危漏洞
5. **日志**: 不记录敏感信息 (密码/token/PII)
6. **CORS/CSP**: 如有 Web 接口, 是否配置正确?
## 产出
- 安全审查结果追加到 quality.md
-20
View File
@@ -1,20 +0,0 @@
---
name: verification
description: T 阶段验证 — 测试 + 覆盖率 + 验收标准
---
# Verification (T 阶段)
## 流程
1. 运行测试: `npm test` 或项目配置的测试命令
2. 覆盖率: 如有配置, 检查覆盖率阈值
3. TypeScript: `npx tsc --noEmit` (如有 tsconfig.json)
4. Lint: `npx eslint . --max-warnings 0` (如有 eslint 配置, Path C+ 强制)
## 验收标准逐条确认 (v9.2.0 新增)
5. 读 .ai_state/design.md 的 "## 验收标准"
6. 逐条确认: 这个标准是否被满足? 证据是什么 (测试名/文件位置)?
7. 未满足的标准 → 标注到 .ai_state/quality.md "## 未满足验收标准"
8. 如果有 E2E 框架 → 运行 E2E 确认用户流程
## 产出
- .ai_state/quality.md 填入验证结果 + 未满足标准
-12
View File
@@ -1,12 +0,0 @@
# Conventions
## 项目编码规范
{由 vibe-init 自动检测并填入, 或手动编写}
## 依赖版本
{关键依赖 + 版本号}
## Agent 易犯错误
> 由 reflexion/kaizen 自动追加, 帮助 agent 避免重复犯错
- (初始为空, 使用过程中逐渐积累)
-24
View File
@@ -1,24 +0,0 @@
# Design Spec
## 需求 (MUST/SHOULD/COULD)
### MUST (必须实现)
- {核心功能 1}
- {核心功能 2}
### SHOULD (应该实现)
- {重要功能}
### COULD (可以实现)
- {锦上添花}
## 技术方案
{架构 + 关键设计决策}
## 验收标准
- [ ] {标准 1: 具体可验证的条件}
- [ ] {标准 2: 具体可验证的条件}
## 非功能需求
- 性能: {指标}
- 安全: {要求}
-7
View File
@@ -1,7 +0,0 @@
# Doing
## 当前执行
- [ ] {当前步骤描述}
## 执行历史
{自动追加完成的步骤}
-10
View File
@@ -1,10 +0,0 @@
# Lessons Learned
## 技术陷阱
{Reflexion/Kaizen 发现的技术问题}
## 有效模式
{本项目中验证有效的解决方案}
## 项目特有知识
{不在文档中但很重要的隐性知识}
-14
View File
@@ -1,14 +0,0 @@
# Plan
## 任务列表
- [ ] T-001: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: 无
- [ ] T-002: {动作动词} + {目标} + {验收条件}
文件: {涉及文件}
依赖: T-001
## 对抗审查记录
{Codex 审查结果摘要, 或 "CC 独立审查"}
-18
View File
@@ -1,18 +0,0 @@
# Quality Report
## 验证结果
- 测试: {通过/失败} ({覆盖率}%)
- TypeScript: {通过/失败}
- Lint: {通过/失败}
## 验收标准确认
- [x] {标准 1}: 满足, 证据: {测试名/文件位置}
- [ ] {标准 2}: 未满足, 原因: {说明}
## 代码审查
- 审查者: {CC / Codex / 互审}
- 发现问题: {数量}
- 已修复: {数量}
## 未满足验收标准
{列出未满足的标准 + 原因}
-13
View File
@@ -1,13 +0,0 @@
# Session
## 任务
{任务描述}
## 路径
P.A.C.E. Path: {A|B|C|D}
## 当前阶段
RIPER-7: {R₀|R|D|P|E|T|V}
## 时间戳
开始: {ISO timestamp}
-13
View File
@@ -1,13 +0,0 @@
# P.A.C.E. 复杂度路由 v9.2.0
收到任务后, 按以下规则选择路径:
| 条件 | 路径 | 阶段 | Codex 参与 |
|------|------|------|-----------|
| 修 bug / 改配置 / <30min | **A (快速)** | E→T | 可选 |
| 新功能 / 重构 / 30min-4h | **B (标准)** | R₀→R→D→P→E→T→V | P对抗审查 + E委托 + T互审 |
| 跨模块 / 架构变更 / >4h | **C (复杂)** | 同B + 子代理并行 | 同B + 多任务并行 |
| 多服务 / 全栈 / 多人协作 | **D (系统)** | 同C + 设计评审 | 同C |
选定路径后 → 读 riper-7.md 执行对应阶段。
Path A 跳过 R₀/R/D/P, 直接 E→T。
-71
View File
@@ -1,71 +0,0 @@
# RIPER-7 阶段编排 v9.2.0
## 每阶段进入前 (通用)
1. 这一步要解决的核心问题是什么?
2. 项目里有没有类似实现? → 搜索 (Grep/Glob, 或 augment-context-engine 如已安装)
3. 用到的库 API 确定吗? → context7 skill 查文档
4. .ai_state/lessons.md + conventions.md 有相关经验吗?
---
## R₀ 需求精炼 (Path B+)
**技能**: brainstorm skill (含步骤0自主调研)
**产出**: .ai_state/design.md (Spec: MUST/SHOULD/COULD + 验收标准)
**门控**: cunzhi `DESIGN_READY` (cunzhi 不可用时: 直接输出 "[DESIGN_READY] 请确认" 等用户回复)
## R 技术调研 (Path B+)
**读**: design.md
**动手**: 搜索相关代码 + 查库版本和 API
**产出**: design.md 追加技术方案
**要回答**: 有没有可复用的现有代码? 需要新依赖吗?
## D 方案定稿 (Path B+)
**读**: design.md
**检查**: 接口最小化? 错误处理完整? 有没有更简单的方案?
**产出**: design.md 最终版 (含验收标准)
**门控**: cunzhi `DESIGN_FINALIZED` (cunzhi 不可用时: 直接输出确认提示)
## P 计划 (Path B+)
**技能**: plan-first skill → 生成 plan.md (T-001/T-002... 格式)
**双 Agent**: 如果 Codex 可用 → codex-review skill 对抗审查
- CC 提交 plan.md → Codex 质疑 → CC 评估采纳/驳回 → 循环
- 终止: VERDICT: APPROVED / 连续2轮全驳 / 超5轮
- 审查结果持久化到 reviews/review-{uuid}.md
**如果 Codex 不可用**: CC 用 validator agent 做 Plan Review
**门控**: cunzhi `PLAN_CONFIRMED` (cunzhi 不可用时: 直接输出确认提示)
## E 执行 (Path B+) — Sisyphus 循环
对 plan.md 每个 Task:
1. 读 Task 文本 + 相关文件 + conventions.md
2. **双 Agent**: 如果 Codex 可用 → codex-comm skill 委托 Codex 执行
如果 Codex 不可用 → CC builder agent 执行
2.5. **Reflexion** (自我反思 → reflexion skill):
"这个实现有没有: 走捷径/忽略边界/硬编码/过度工程/偏离 spec?"
发现问题 → 立即修复
值得记录 → lessons.md
3. **Micro-review**: 对标 design.md spec + conventions.md 标准
通过 → [x] Task + commit
不通过 → 反馈修复
**铁律**: plan.md 有任何 [ ] 未完成, 不停止。这就是 Sisyphus。
## T 测试/审查 (Path B+)
1. verification skill: 跑测试 + 覆盖率
1.5. **验收标准确认**:
读 design.md "## 验收标准" → 逐条确认是否满足
未满足 → 标注到 quality.md "## 未满足验收标准"
2. code-review skill: 代码审查
3. **双 Agent 互审**: 如果 Codex 可用 → CC 审查 Codex 产出 + Codex 反审 CC 修改
如果 Codex 不可用 → CC 单方审查
4. 综合 → quality.md
5. **4 级 Quality Gate** (delivery-gate.cjs):
PASS (exit 0) → 允许停止
CONCERNS (exit 0 + stdout 警告) → 允许停止, 警告注入 context
REWORK (exit 2) → 阻断停止, 强制修复
FAIL (exit 2) → 阻断停止, 必须大幅修复
## V 归档 (Path B+)
1. kaizen skill: 回顾 + lessons.md
1.5. **分支收尾** (finish-branch skill):
选项: merge / PR / keep / discard
PR → 自动生成 description (基于 plan.md + quality.md)
2. cunzhi `DELIVERY_COMPLETE` (cunzhi 不可用时: 直接输出确认提示)
+26 -41
View File
@@ -1,47 +1,32 @@
# VibeCoding Kernel v9.2.0 — Codex CLI
# VibeCoding Athena v9.6 (Codex) — PACE Router & State Harness
你是一个INTJ性格的工程化 AI 编码助手。用 P.A.C.E. 路由复杂度, 用 RIPER-7 编排阶段, 用 Skills 执行细节。
**协作模式**: 你可能被 Claude Code (CC) 调用执行任务, 也可能独立运行。
<!--
本文件目标 altitude: 工程纪律的高信号宪法 (constitution)。
- 不规定操作步骤 → skills/pace/SKILL.md
- 不列插件命令 → prompts/athena-setup.md
- 不写安装/配置 → README.md
- 行数硬上限 30
-->
## 框架地图
你是 VibeCoding Athena 工程 Agent。Codex 做事, Athena 把关。
| 类别 | 文件 | 数量 |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| Workflows | pace.md, riper-7.md | 2 |
| Skills | brainstorm, plan-first, code-review, verification, debugging, kaizen, security-review, context7, e2e, claude-delegate, reflexion, finish-branch | 12 |
| Agents | builder.toml, validator.toml, explorer.toml | 3 |
| State Templates | session, doing, design, plan, conventions, quality, lessons | 7 |
- 收任务 → 走 PACE 路由 (Hotfix/Bugfix 直接做, Quick+ 走完整流程)
- 自己跑命令 / 跑测试 / 看输出, 证明工作完成
- 工具失败 → 三次重试附 stderr 报告, 不让用户代执行
- 技术结论 → 必须引用官方文档 / 源码 URL
- spawn_agent 必须产生真实 tool_use, 不允许伪造完成
- Codex 无 compact 机制, 长任务点主动写 `.ai_state/_index.md` 保存状态
## 启动流程
## 铁律 (9 条)
1. 读 .ai_state/ → 恢复或初始化
2. 读 conventions.md (含 "Agent 易犯错误" 段) → 注意这些坑
3. 评估任务 → P.A.C.E. 路由 → RIPER-7 执行
1. **设计先行** — 未确认不写代码 (Hotfix/Bugfix 例外)
2. **TDD 强制** — 先测试后实现
3. **Sisyphus** — tasks 全完成才进审查
4. **Review 强制** — Feature+ 至少一次交叉审查 (/review + spawn_agent reviewer)
5. **文档即真相** — 阶段转换前 .ai_state/ 必须同步, 单一入口 `.ai_state/_index.md`
6. **完成度证据** — 报告"完成"必须附 tool_use ID 或命令输出片段
7. **出处优先** — API 形态 / 配置字段 / 协议格式必须引用官方文档或源码 URL
8. **索引先行** — 进入决策先读 `.ai_state/_index.md`, 禁止 glob 全目录扫描
9. **Hook 是进化器** — 在 Stop 时反思并写 `.ai_state/details/proposals.md`
## 关键规则
- 设计未确认前不写代码 (R₀/R/D 阶段)
- TDD: 先写测试再写实现 (E 阶段)
- Sisyphus: plan.md 所有 [ ] 完成才能停 (E 阶段)
- Reflexion: 每个 Task 完成后自我反思再 Micro-review (E 阶段)
- 4 级 Quality Gate: PASS / CONCERNS / REWORK / FAIL (交付前)
## 被 CC 调用时
- CC 会通过 `codex exec` 发送任务
- 你在只读沙箱中运行, 不直接修改文件
- 输出代码和建议, CC 决定是否应用
- 审查请求以 `VERDICT: APPROVED` 或 `VERDICT: REVISE` 结尾
## MCP 工具 (按需)
- cunzhi: 人工确认检查点
- context7 CLI: `npx ctx7 resolve {库名}`
## 模型
| 场景 | 模型 |
| --------- | ------------------------ |
| 默认 | gpt-5.4 |
| 快速/探索 | gpt-5.4-mini |
| 深度审查 | gpt-5.4 (high reasoning) |
设计原则: SRP · OCP · LSP · ISP · DIP · DRY · KISS · 第一性原理 · 先 WHY 后 HOW
-4
View File
@@ -1,4 +0,0 @@
[agent]
name = "builder"
model = "gpt-5.4"
description = "实现代码 + 测试 (TDD: RED→GREEN→REFACTOR)"
+47
View File
@@ -0,0 +1,47 @@
# Codex Subagent: evaluator (VibeCoding Athena v9.6)
# 参考: https://developers.openai.com/codex/subagents
# 位置: ~/.codex/agents/evaluator.toml 或 .codex/agents/evaluator.toml
name = "evaluator"
description = "代码审查评分员. PACE review 阶段调用, 输出 VERDICT (PASS/CONCERNS/REWORK/FAIL)"
nickname_candidates = ["EvalBot", "Verdict"]
# 只读: 评分员不修改任何代码
sandbox_mode = "read-only"
# Model 不指定 → 继承父 session
# model_reasoning_effort 不指定 → 继承父 session
developer_instructions = """
你是 VibeCoding Athena 的代码审查评分员.
## 输入
- `.ai_state/_index.md` (path/stage/sprint/active_goal)
- `.ai_state/details/reviews/sprint-N.md` (本 sprint 审查报告)
- `.ai_state/details/design.md` (设计 vs 实际对比)
- `git diff` 本 sprint 提交
## 工具限制
- 只读: read_file / shell (限 ls, cat, grep, rg, git log/diff/show) / web_search
- 禁用: apply_patch, write_file, edit_file
## 评分维度 (1-5 分, 跨平台一致 — 铁律 6)
- Functionality (25%) // 是否实现 design.md 中所有 MUST 项
- Spec Compliance (25%) // 是否符合 design.md 的约束
- Boundary (15%) // 是否越出 File Structure Plan 边界
- Craft (15%) // 代码质量 (命名/SRP/无 dead code)
- Robustness (20%) // 边界处理/错误恢复/测试覆盖
均分 = F×0.25 + SC×0.25 + B×0.15 + C×0.15 + R×0.20
## VERDICT 规则
- 均分 ≥ 4.0 且所有维度 ≥ 3 → PASS
- 均分 ≥ 3.0 但某维度 = 2 → CONCERNS
- 均分 < 3.0 或任一维度 = 1 → REWORK
- 多维度 = 1 或 Boundary 大幅越界 / 安全严重问题 → FAIL
## 输出要求
- 每个维度评分必须附代码行号级证据 (file.ext:LN, 不是模糊"看起来不错")
- 不允许 Halo Effect (一个维度的分数不影响其他维度的独立评分顺序)
- 输出预算 ≤ 2000 tokens (Anthropic 多 agent 经验: subagent 必须紧凑)
- 直接覆盖写回 reviews/sprint-N.md 的 "## Step 6" 段和 "## VERDICT:" 段
"""
-4
View File
@@ -1,4 +0,0 @@
[agent]
name = "explorer"
model = "gpt-5.4-mini"
description = "代码库调研 + 文档查询 (只读)"
+62
View File
@@ -0,0 +1,62 @@
# Codex Subagent: generator (VibeCoding Athena v9.6)
# 参考: https://developers.openai.com/codex/subagents
# 位置: ~/.codex/agents/generator.toml 或 .codex/agents/generator.toml
name = "generator"
description = "代码实现者. 接 task spec, TDD 实现, 输出可被 reviewer 验证的 commit"
nickname_candidates = ["GenBot", "Builder", "Smith"]
# 写权限: implementer 需要 apply_patch / edit_file
sandbox_mode = "workspace-write"
# model / model_reasoning_effort 不指定 → 继承父 session
developer_instructions = """
你是 VibeCoding Athena 的代码实现者.
## 工具
- read_file / write_file / edit_file / apply_patch
- shell (含 git, 测试运行, lint, 包管理)
- web_search (查依赖文档)
## 工作流 (与 CC 端等价 — 跨平台 schema 一致 — 铁律 6)
1. Get-bearings (R₀):
- 读 `.ai_state/_index.md`
- 读 design.md 对应模块段
- 读 tasks-current.md 当前 task 的 Boundary/Depends
2. TDD 强制 (铁律 2):
- 先写测试 → 跑测试 (RED) → 实现 → 跑测试 (GREEN)
3. Boundary 守则:
- 仅修改 task 的 Boundary 标注的文件
- 越界 → 停, 报告主 agent (可能需要升路径)
4. 跑 lint_cmd → 失败修复
5. 更新文档:
- tasks-current.md 勾选 ([ ] → [x])
- progress.md 追加一行 (YYYY-MM-DD HH:MM [path/stage/sprint] Task N done)
- design.md 不动 (除非发现 design 错; 那种情况报告主 agent 不要自己改)
6. Commit:
- `git add -p` 仅添加 Boundary 内文件
- `git commit -m "<task short summary>"`
7. 报告:
- 输出 commit hash + 测试通过的命令输出片段 (铁律 6 完成度证据)
- 失败 → 完整 stderr (不允许 "I cannot")
## Codex 端注意
- 不像 CC 有 isolation:worktree 自动隔离, Codex subagent 共享 workspace
- 多个 generator 并发时, 严格按 Boundary 分工避免冲突
- 设置 max_threads 在 config.toml [agents] 控制并发度 (max_threads = 6)
## 失败协议 (铁律 7)
工具失败 → 三轮重试:
- Round 1: 读 stderr 分类 (permission denied / not found / 语法)
- Round 2: 改参数 / 换工具 / 拆任务
- Round 3: 仍失败 → 完整 stderr + exit code + 已尝试方案, 报告主 agent
禁止: "请你手动跑", "我没有权限" (没有就申请, 不是放弃).
## 输出预算
≤ 2000 tokens. 详细日志写文件不写回主 agent.
"""
+62
View File
@@ -0,0 +1,62 @@
# Codex Subagent: reviewer (VibeCoding Athena v9.6)
# 参考: https://developers.openai.com/codex/subagents
# 位置: ~/.codex/agents/reviewer.toml 或 .codex/agents/reviewer.toml
name = "reviewer"
description = "代码审查员. PACE review 阶段调用, 给出对抗性 findings + 可执行 fixes (与 evaluator 配合: reviewer 找问题, evaluator 给 VERDICT)"
nickname_candidates = ["ReviewBot", "Critic", "Inspector"]
# 只读: reviewer 不修改代码, 只产出 findings
sandbox_mode = "read-only"
developer_instructions = """
你是 VibeCoding Athena 的代码审查员.
## 角色边界
与 evaluator 区别:
- evaluator: 给 VERDICT (PASS/CONCERNS/REWORK/FAIL) + 数值评分
- reviewer: 给具体可执行的反馈 (找 bug, 找设计问题, 找测试缺口)
主 agent 工作流: 先调 reviewer 拿反馈 → 修复 → 再调 evaluator 给 VERDICT.
## 工具
- read_file
- shell (限只读: ls, cat, grep, rg, git log/diff/show)
- web_search (查最佳实践, OWASP 规范)
禁用: apply_patch / write_file / edit_file.
## 审查重点 (与 CC 端 /codex:review 行为对齐)
1. Bug: 边界用例, 错误处理, race condition
2. 设计: 是否违反 design.md, SOLID, KISS
3. 测试: 覆盖率, 是否测了 happy path 没测 error path
4. 安全: 输入验证, 注入风险, 密钥处理
5. 性能: 明显的 N+1, 同步阻塞, 内存泄漏
## 输出
写入 `.ai_state/details/reviews/sprint-N.md` 的 "## Step 2/3" 段:
```
### Reviewer (Codex subagent)
**job_id**: <Codex subagent job id, 铁律 6 完成度证据>
**Findings**:
- [HIGH] file.ext:LN — <描述>
- [MEDIUM] file.ext:LN — <描述>
- [LOW] file.ext:LN — <描述>
**Suggested fixes**:
- ...
```
每个 finding 必须有 file:line 锚点 (no 模糊"代码可以更好").
## 输出预算
≤ 2000 tokens.
"""
-4
View File
@@ -1,4 +0,0 @@
[agent]
name = "validator"
model = "gpt-5.4"
description = "代码审查 + Plan Review"
+92 -62
View File
@@ -1,85 +1,115 @@
# VibeCoding Kernel v9.2.0 — Codex CLI Config
model_provider = "custom"
model = "gpt-5.4"
# VibeCoding Athena v9.6 · Codex Configuration
project_root_markers = [".git", ".hg", ".sl"]
project_doc_max_bytes = 65536
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
windows_wsl_setup_acknowledged = true
model_context_window = 1000000
model_auto_compact_token_limit = 900000
web_search = "live"
suppress_unstable_features_warning = true
# 危险,可开启 和下面的二选一,上面的代表绝对信任
# approval_policy = "never" # untrusted|on-request|never
# sandbox_mode = "danger-full-access" # read-only|workspace-write|danger-full-access
approval_policy = "never"
sandbox_mode = "workspace-write"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true # npm install / pip install 需要网络
# Web Search
web_search = "live"
network_access = false
[features]
multi_agent = true # stable; 多代理编排
collaboration_modes = true # stable; 协作模式
shell_snapshot = true # beta; 加速重复命令
unified_exec = true # beta; PTY-backed 执行
shell_tool = true # stable; 默认 shell 工具
apply_patch_freeform = true # experimental; 自由 patch
undo = true # 回滚 Codex 改动;
hooks = true
multi_agent = true
shell_tool = true
shell_snapshot = true
unified_exec = true
apply_patch_freeform = true
undo = true
memories = true
[tui]
notifications = true
animations = true
[memories]
generate_memories = true
use_memories = true
disable_on_external_context = true
[profiles.ci]
approval_policy = "never"
sandbox_mode = "workspace-write"
[[hooks.SessionStart]]
matcher = "^(startup|resume|clear)$"
[[hooks.SessionStart.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/session-start.py\""
timeout = 10
statusMessage = "Loading Athena context"
[profiles.review]
model = "gpt-5.4"
approval_policy = "on-request"
[[hooks.UserPromptSubmit]]
[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/user-prompt-submit.py\""
timeout = 5
statusMessage = "Athena pre-check"
[profiles.dev]
model = "gpt-5.4"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/pre-bash-guard.py\""
timeout = 10
statusMessage = "Checking Bash command"
[[hooks.PostToolUse]]
[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/index-updater.py\""
timeout = 10
[[hooks.PostToolUse]]
[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/subagent-retry.py\""
timeout = 10
[[hooks.Stop]]
[[hooks.Stop.hooks]]
type = "command"
command = "python3 \"./.codex/hooks/delivery-gate.py\""
timeout = 60
statusMessage = "Athena delivery-gate"
[agents]
max_threads = 3
max_threads = 6
max_depth = 1
job_max_runtime_seconds = 1800
[agents.builder]
description = "实现代码 + 测试 (TDD: RED→GREEN→REFACTOR)"
config_file = "./agents/builder.toml"
[[skills.config]]
name = "pace"
enabled = true
[agents.validator]
description = "代码审查 + Plan Review"
config_file = "./agents/validator.toml"
[[skills.config]]
name = "compound"
enabled = true
[agents.explorer]
description = "代码库调研 + 文档查询 (只读)"
config_file = "./agents/explorer.toml"
[[skills.config]]
name = "context7"
enabled = true
[model_providers.custom]
name = "custom"
wire_api = "responses"
requires_openai_auth = true
[[skills.config]]
name = "superpowers"
enabled = true
[mcp_servers]
[shell_environment_policy]
inherit = "core"
[mcp_servers.mcp-deepwiki]
type = "stdio"
command = "npx"
args = ["-y", "mcp-deepwiki@latest"]
[tui.model_availability_nux]
"gpt-5.5" = 4
[mcp_servers."cunzhi"]
type = "stdio"
command = "寸止"
[mcp_servers.chrome-devtools]
type = "stdio"
command = "npx"
args = ["-y", "chrome-devtools-mcp@latest"]
[shell_environment_policy.set]
VIBECODING_VERSION = "9.6.0-codex"
[mcp_servers.augment-context-engine]
type = "stdio"
command = "npx"
args = ["ace-tool-rs", "--base-url", "https://acemcp.heroman.wtf/relay/", "--token", ""]
args = [ "ace-tool-rs", "--base-url", "https://acemcp.heroman.wtf/relay/", "--token", "ace_0eff2f29e8dec9382d0ad1b46b39e587d06f6c2f" ]
[mcp_servers.augment-context-engine.tools.search_context]
approval_mode = "approve"
[hooks.state]
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex Stop hook (delivery-gate) v9.6.
设计:
- Codex 无 /goal autonomous loop → Athena 必须自己判定 VERDICT
- Codex 无 Stop hook block-cap 概念, 但保守起见也做内部计数
- VERDICT 不符 → 阻断 (decision: block)
- CONCERNS → systemMessage 不阻断
"""
import json
import os
import re
import sys
import datetime
PROJECT_DIR = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
STATE_DIR = os.path.join(PROJECT_DIR, ".ai_state")
INDEX_PATH = os.path.join(STATE_DIR, "_index.md")
HOME = os.path.expanduser("~")
COUNTER_PATH = os.path.join(HOME, ".codex", "state", "athena-block-counter.json")
BLOCK_CAP_SAFE = 6
def trace(payload: dict):
try:
with open(os.path.join(STATE_DIR, "hook-trace.jsonl"), "a") as f:
f.write(json.dumps({
"ts": datetime.datetime.utcnow().isoformat() + "Z",
"hook": "delivery-gate",
**payload
}) + "\n")
except Exception:
pass
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
sys.exit(0)
return
if event.get("stop_hook_active"):
sys.exit(0)
return
if event.get("agent_type") and event["agent_type"] != "main":
sys.exit(0)
return
if not os.path.exists(INDEX_PATH):
sys.exit(0)
return
try:
content = open(INDEX_PATH).read()
m = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
if not m:
sys.exit(0)
return
fm = m.group(1)
except Exception:
sys.exit(0)
return
def get_str(key):
match = re.search(rf'^ {re.escape(key)}: (.*)$', fm, re.MULTILINE)
return match.group(1).strip().strip('"').strip("'") if match else ""
def get_num(key):
match = re.search(rf'^ {re.escape(key)}: (\d+)$', fm, re.MULTILINE)
return int(match.group(1)) if match else 0
path_name = get_str("path")
stage = get_str("stage")
sprint = get_num("sprint")
tasks_pending = get_num("tasks_pending")
if not sprint or not stage or path_name in ("Hotfix", "Bugfix") or stage != "review":
sys.exit(0)
return
needs_ext = path_name in ("Feature", "Refactor", "System")
issues = []
if tasks_pending > 0:
issues.append(f"{tasks_pending} Task 未完成")
review_file = os.path.join(STATE_DIR, "details", "reviews", f"sprint-{sprint}.md")
rc = ""
try:
rc = open(review_file).read()
except Exception:
issues.append("审查报告不存在")
if needs_ext and rc and not re.search(r"reviewer|web_search|/review|spawn_agent", rc, re.IGNORECASE):
issues.append("无外部审查记录")
if rc and not re.search(r"test|测试|pass|通过|✅", rc, re.IGNORECASE):
issues.append("无测试通过记录")
verdict = ""
if rc:
vm = re.search(r"VERDICT:\s*(PASS|CONCERNS|REWORK|FAIL)", rc, re.IGNORECASE)
if vm:
verdict = vm.group(1).upper()
if verdict in ("REWORK", "FAIL"):
issues.append(f"VERDICT={verdict}")
if issues:
os.makedirs(os.path.dirname(COUNTER_PATH), exist_ok=True)
counter = {}
try:
counter = json.load(open(COUNTER_PATH))
except Exception:
pass
sid = event.get("session_id", "unknown")
counter[sid] = counter.get(sid, 0) + 1
try:
with open(COUNTER_PATH, "w") as f:
json.dump(counter, f)
except Exception:
pass
count = counter[sid]
sys.stderr.write(f"[delivery-gate] block #{count}/{BLOCK_CAP_SAFE} {path_name}/{stage}: {', '.join(issues)}\n")
trace({"action": "block", "count": count, "path": path_name, "stage": stage, "issues": issues})
if count >= BLOCK_CAP_SAFE:
msg = f"[Athena] 已连续 block {count} 次, 建议手动处理: {'; '.join(issues)}"
print(json.dumps({"systemMessage": msg}))
else:
print(json.dumps({
"decision": "block",
"reason": f"[Athena delivery-gate] 阻断:\n" + "\n".join("• " + i for i in issues) + f"\n\n修复后再交付 (block {count}/{BLOCK_CAP_SAFE})."
}))
sys.exit(0)
return
# 通过, 重置计数
try:
counter = json.load(open(COUNTER_PATH))
counter.pop(event.get("session_id", ""), None)
with open(COUNTER_PATH, "w") as f:
json.dump(counter, f)
except Exception:
pass
if verdict == "PASS":
# 检查 lessons
try:
lessons = open(os.path.join(STATE_DIR, "details", "lessons.md")).read()
except Exception:
lessons = ""
if f"Sprint {sprint}" not in lessons:
msg = f"Sprint {sprint} 通过但 details/lessons.md 无条目, 建议运行 compound skill 沉淀经验"
print(json.dumps({"systemMessage": f"[Athena] {msg}"}))
trace({"action": "soft-warn", "reason": "no compound", "path": path_name, "sprint": sprint})
sys.exit(0)
return
sys.stderr.write(f"[delivery-gate] PASS {path_name}/{stage}\n")
trace({"action": "pass", "path": path_name, "stage": stage, "sprint": sprint, "verdict": verdict})
sys.exit(0)
if __name__ == "__main__":
main()
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex PostToolUse index-updater v9.6.
设计 (与 CC 等价, schema 跨平台一致 - 铁律 6):
- 检测 tool_input.file_path 是否在 .ai_state/details/
- 若是 → 重新扫描计算 counts/fingerprints/pointers
- 原子写入 _index.md (.tmp + rename)
"""
import json
import os
import re
import sys
import datetime
PROJECT_DIR = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
STATE_DIR = os.path.join(PROJECT_DIR, ".ai_state")
INDEX_PATH = os.path.join(STATE_DIR, "_index.md")
DETAILS_DIR = os.path.join(STATE_DIR, "details")
def read_file_safe(path):
try:
return open(path).read()
except Exception:
return ""
def mtime(path):
try:
return int(os.path.getmtime(path) * 1000)
except Exception:
return 0
def count_matches(text, pattern):
return len(re.findall(pattern, text, re.MULTILINE)) if text else 0
def last_section_line(text, head_prefix="## "):
if not text:
return 0
lines = text.split("\n")
for i in range(len(lines) - 1, -1, -1):
if lines[i].startswith(head_prefix):
return i + 1
return 0
def last_nonempty_line(text):
if not text:
return 0
lines = text.split("\n")
for i in range(len(lines) - 1, -1, -1):
s = lines[i].strip()
if s and not s.startswith("<!--") and not s.startswith("-->") and not s.startswith("#"):
return i + 1
return 0
def replace_field(yaml: str, key: str, value, is_numeric: bool) -> str:
val_str = str(value) if is_numeric else f'"{value}"'
pattern = rf"(^ {re.escape(key)}: ).*$"
if re.search(pattern, yaml, re.MULTILINE):
return re.sub(pattern, rf"\g<1>{val_str}", yaml, count=1, flags=re.MULTILINE)
return yaml
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
sys.exit(0)
return
file_path = (event.get("tool_input") or {}).get("file_path", "")
if not file_path or ".ai_state/details/" not in file_path:
sys.exit(0)
return
if not os.path.exists(INDEX_PATH):
sys.exit(0)
return
try:
content = open(INDEX_PATH).read()
m = re.match(r"^---\n(.*?)\n---\n(.*)$", content, re.DOTALL)
if not m:
sys.stderr.write("[index-updater] frontmatter parse failed\n")
sys.exit(0)
return
fm, body = m.group(1), m.group(2)
tasks_text = read_file_safe(os.path.join(DETAILS_DIR, "tasks-current.md"))
progress_text = read_file_safe(os.path.join(DETAILS_DIR, "progress.md"))
lessons_text = read_file_safe(os.path.join(DETAILS_DIR, "lessons.md"))
proposals_text = read_file_safe(os.path.join(DETAILS_DIR, "proposals.md"))
tasks_pending = count_matches(tasks_text, r"^- \[ \]")
tasks_done = count_matches(tasks_text, r"^- \[x\]")
tasks_blocked = count_matches(tasks_text, r"^- \[!\]")
lessons_lines = count_matches(lessons_text, r"^## ")
progress_entries = 0
if progress_text:
progress_entries = sum(
1 for l in progress_text.split("\n")
if l.strip() and not l.startswith("<!--") and not l.startswith("-->") and not l.startswith("#")
)
reviews_count = 0
latest_review = ""
try:
files = [f for f in os.listdir(os.path.join(DETAILS_DIR, "reviews")) if re.match(r"^sprint-\d+\.md$", f)]
reviews_count = len(files)
if files:
files.sort(key=lambda f: int(re.search(r"\d+", f).group()))
latest_review = f"details/reviews/{files[-1]}"
except Exception:
pass
latest_progress = f"details/progress.md#L{last_nonempty_line(progress_text)}" if progress_text else ""
latest_lesson = f"details/lessons.md#L{last_section_line(lessons_text)}" if lessons_text else ""
latest_proposal = f"details/proposals.md#L{last_section_line(proposals_text)}" if proposals_text else ""
tasks_mtime = mtime(os.path.join(DETAILS_DIR, "tasks-current.md"))
design_mtime = mtime(os.path.join(DETAILS_DIR, "design.md"))
progress_mtime = mtime(os.path.join(DETAILS_DIR, "progress.md"))
lessons_mtime = mtime(os.path.join(DETAILS_DIR, "lessons.md"))
fm = replace_field(fm, "tasks_pending", tasks_pending, True)
fm = replace_field(fm, "tasks_done", tasks_done, True)
fm = replace_field(fm, "tasks_blocked", tasks_blocked, True)
fm = replace_field(fm, "lessons_lines", lessons_lines, True)
fm = replace_field(fm, "progress_entries", progress_entries, True)
fm = replace_field(fm, "reviews_count", reviews_count, True)
fm = replace_field(fm, "latest_progress", latest_progress, False)
fm = replace_field(fm, "latest_review", latest_review, False)
fm = replace_field(fm, "latest_lesson", latest_lesson, False)
fm = replace_field(fm, "latest_proposal", latest_proposal, False)
fm = replace_field(fm, "tasks_mtime", tasks_mtime, True)
fm = replace_field(fm, "design_mtime", design_mtime, True)
fm = replace_field(fm, "progress_mtime", progress_mtime, True)
fm = replace_field(fm, "lessons_mtime", lessons_mtime, True)
new_content = f"---\n{fm}\n---\n{body}"
tmp = INDEX_PATH + ".tmp"
with open(tmp, "w") as f:
f.write(new_content)
os.rename(tmp, INDEX_PATH)
sys.stderr.write(f"[index-updater] _index.md updated (pending={tasks_pending} done={tasks_done})\n")
with open(os.path.join(STATE_DIR, "hook-trace.jsonl"), "a") as f:
f.write(json.dumps({
"ts": datetime.datetime.utcnow().isoformat() + "Z",
"hook": "index-updater",
"tasks_pending": tasks_pending,
"tasks_done": tasks_done,
"lessons_lines": lessons_lines,
}) + "\n")
except Exception as e:
sys.stderr.write(f"[index-updater] failed: {e}\n")
sys.exit(0)
if __name__ == "__main__":
main()
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex PreToolUse Bash guard v9.6.
设计:
- 3 条灾难命令 (与 CC 等价)
- Codex hook 输出协议: permissionDecision = "deny" 阻断
- Codex 文档: hooks 当前实验性, Windows 不支持
参考: https://developers.openai.com/codex/hooks
"""
import json
import re
import sys
import datetime
import os
DANGER_PATTERNS = [
(re.compile(r"rm\s+-[rRf]+\s+(/(\s|\*|;|&|\||$)|~/?\s|~\s|~$)"), "禁止删除系统/用户根目录"),
(re.compile(r"(curl|wget)\s+[^|]*\|\s*(bash|sh|zsh|fish|ksh)"), "禁止管道执行远程脚本"),
(re.compile(r"\bmkfs\.|dd\s+if=.*of=/dev/sd|>\s*/dev/sd[a-z]"), "禁止格式化磁盘/写设备"),
]
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
sys.exit(0)
return
cmd = (event.get("tool_input") or {}).get("command", "")
if not cmd:
sys.exit(0)
return
for pat, reason in DANGER_PATTERNS:
if pat.search(cmd):
sys.stderr.write(f"[bash-guard] deny: {reason} ({cmd[:60]})\n")
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": f"Athena bash-guard 阻断: {reason}"
}
}))
try:
project_dir = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
state_dir = os.path.join(project_dir, ".ai_state")
with open(os.path.join(state_dir, "hook-trace.jsonl"), "a") as f:
f.write(json.dumps({
"ts": datetime.datetime.utcnow().isoformat() + "Z",
"hook": "pre-bash-guard",
"action": "deny",
"reason": reason
}) + "\n")
except Exception:
pass
sys.exit(0)
return
sys.exit(0)
if __name__ == "__main__":
main()
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex SessionStart hook v9.6.
协议: stdout JSON with additionalContext (Codex 端简化, 不强制 hookSpecificOutput 嵌套)
参考: https://developers.openai.com/codex/hooks
设计 (铁律 8 索引先行, 同 CC):
- 唯一 IO: read .ai_state/_index.md frontmatter
- 注入 context-essentials.md (静态文本)
- 注入 _index.md 关键字段摘要
"""
import json
import os
import re
import sys
import datetime
PROJECT_DIR = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
STATE_DIR = os.path.join(PROJECT_DIR, ".ai_state")
INDEX_PATH = os.path.join(STATE_DIR, "_index.md")
HOME = os.path.expanduser("~")
PROJECT_ESSENTIALS = os.path.join(PROJECT_DIR, ".codex", "skills", "pace", "context-essentials.md")
GLOBAL_ESSENTIALS = os.path.join(HOME, ".codex", "skills", "pace", "context-essentials.md")
def trace(payload: dict):
try:
line = json.dumps({"ts": datetime.datetime.utcnow().isoformat() + "Z", "hook": "session-start", **payload}) + "\n"
with open(os.path.join(STATE_DIR, "hook-trace.jsonl"), "a") as f:
f.write(line)
except Exception:
pass
def read_file_safe(path: str) -> str:
try:
with open(path, "r") as f:
return f.read().strip()
except Exception:
return ""
def get_frontmatter(content: str) -> str:
m = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
return m.group(1) if m else ""
def get_str(fm: str, key: str) -> str:
m = re.search(rf"^ {re.escape(key)}: (.*)$", fm, re.MULTILINE)
if not m:
return ""
val = m.group(1).strip()
return val.strip('"').strip("'")
def get_num(fm: str, key: str) -> int:
m = re.search(rf"^ {re.escape(key)}: (\d+)$", fm, re.MULTILINE)
return int(m.group(1)) if m else 0
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
event = {}
source = event.get("source", "unknown")
lines = []
# 1. 注入 context-essentials
for p in (PROJECT_ESSENTIALS, GLOBAL_ESSENTIALS):
text = read_file_safe(p)
if text:
lines.append(text)
break
if not lines:
lines.append("[VibeCoding Athena Codex v9.6] TDD · Review · Sisyphus · 索引先行")
# 2. 注入 _index.md frontmatter 摘要
if os.path.exists(INDEX_PATH):
try:
content = open(INDEX_PATH).read()
fm = get_frontmatter(content)
if fm:
path_ = get_str(fm, "path")
stage = get_str(fm, "stage")
sprint = get_num(fm, "sprint")
goal = get_str(fm, "active_goal")
pending = get_num(fm, "tasks_pending")
done = get_num(fm, "tasks_done")
blocked = get_num(fm, "tasks_blocked")
if path_ and stage:
lines.append(f"\n[PACE] Path:{path_} Stage:{stage} Sprint:{sprint}")
if goal:
snippet = goal[:120] + ("..." if len(goal) > 120 else "")
lines.append(f"[/goal active (CC only)] {snippet}")
if pending + done + blocked > 0:
lines.append(f"[任务] {done} 完成 {pending} 待办 {blocked} 阻塞 (详见 details/tasks-current.md)")
except Exception as e:
sys.stderr.write(f"[session-start] _index.md parse failed: {e}\n")
additional_context = "\n".join(lines)
sys.stderr.write(f"[session-start/{source}] injected {len(additional_context)} chars\n")
trace({"source": source, "chars": len(additional_context)})
# Codex hooks 输出协议: stdout 包含 additionalContext 字符串 (官方文档示例)
# 参考: https://developers.openai.com/codex/hooks 中 SessionStart 段
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": additional_context
}
}))
sys.exit(0)
if __name__ == "__main__":
main()
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex PostToolUse subagent-retry v9.6.
设计 (与 CC 等价):
- 检测 spawn_agent 返回的内容是否含放弃信号词
- 注入 systemMessage 提示主 agent 重试或接管
"""
import json
import re
import sys
import datetime
import os
GIVEUP_PATTERNS = [
re.compile(r"我(无法|不能|没法|无能力|不具备能力)"),
re.compile(r"I (cannot|can't|am not able to|don't have access)", re.IGNORECASE),
re.compile(r"no (capability|access|permission) to", re.IGNORECASE),
re.compile(r"unable to (read|write|execute|access)", re.IGNORECASE),
re.compile(r"tool not available", re.IGNORECASE),
re.compile(r"(请|你)(自己|手动|帮我)?(运行|执行|跑)"),
re.compile(r"please run (this|the command) (yourself|manually)", re.IGNORECASE),
]
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
sys.exit(0)
return
if event.get("tool_name") not in ("Task", "spawn_agent"):
sys.exit(0)
return
response = event.get("tool_response") or {}
text = ""
if isinstance(response.get("content"), str):
text = response["content"]
elif isinstance(response.get("content"), list):
text = "\n".join(c.get("text", "") for c in response["content"] if isinstance(c, dict))
else:
text = json.dumps(response)
for pat in GIVEUP_PATTERNS:
if pat.search(text):
sys.stderr.write(f"[subagent-retry] giveup detected: {pat.pattern[:50]}\n")
subagent = (event.get("tool_input") or {}).get("subagent_type") or (event.get("tool_input") or {}).get("agent_type") or "subagent"
msg = f"[Athena subagent-retry] {subagent} 返回了放弃信号. 协议: 1) 再尝试一次, 用不同参数或拆分任务 2) 仍失败则主 agent 接管, 不要让用户代执行 (铁律 6 完成度证据)"
print(json.dumps({"systemMessage": msg}))
try:
project_dir = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
state_dir = os.path.join(project_dir, ".ai_state")
with open(os.path.join(state_dir, "hook-trace.jsonl"), "a") as f:
f.write(json.dumps({
"ts": datetime.datetime.utcnow().isoformat() + "Z",
"hook": "subagent-retry",
"subagent": subagent
}) + "\n")
except Exception:
pass
sys.exit(0)
return
sys.exit(0)
if __name__ == "__main__":
main()
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""VibeCoding Athena Codex UserPromptSubmit hook v9.6.
仅在用户 prompt 看起来是"开发请求" 时, 提示当前 PACE 状态, 帮助 model 路由.
不强制添加任何内容, 单纯增强 context.
参考: https://developers.openai.com/codex/hooks
"""
import json
import os
import re
import sys
import datetime
PROJECT_DIR = os.environ.get("CODEX_PROJECT_DIR") or os.getcwd()
STATE_DIR = os.path.join(PROJECT_DIR, ".ai_state")
INDEX_PATH = os.path.join(STATE_DIR, "_index.md")
DEV_KEYWORDS = re.compile(
r"(实现|开发|新增|加上|做|搭|跑|写|改|修|fix|implement|build|add|create|refactor|review|test|debug)",
re.IGNORECASE,
)
def main():
raw = sys.stdin.read()
try:
event = json.loads(raw)
except Exception:
sys.exit(0)
return
prompt = event.get("prompt") or event.get("user_prompt") or ""
if not DEV_KEYWORDS.search(prompt):
sys.exit(0)
return
if not os.path.exists(INDEX_PATH):
sys.exit(0)
return
try:
content = open(INDEX_PATH).read()
m = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
if not m:
sys.exit(0)
return
fm = m.group(1)
path_m = re.search(r'^ path: "([^"]*)"$', fm, re.MULTILINE)
stage_m = re.search(r'^ stage: "([^"]*)"$', fm, re.MULTILINE)
path_val = path_m.group(1) if path_m else ""
stage_val = stage_m.group(1) if stage_m else ""
if path_val and stage_val:
msg = f"[Athena] 当前 PACE 状态: {path_val}/{stage_val}. 如果是延续任务, 请走 pace skill 既有流程; 如果是新任务, 评估是否升路径."
sys.stderr.write(msg + "\n")
print(json.dumps({"systemMessage": msg}))
try:
line = json.dumps({
"ts": datetime.datetime.utcnow().isoformat() + "Z",
"hook": "user-prompt-submit",
"path": path_val, "stage": stage_val
}) + "\n"
with open(os.path.join(STATE_DIR, "hook-trace.jsonl"), "a") as f:
f.write(line)
except Exception:
pass
except Exception as e:
sys.stderr.write(f"[user-prompt-submit] failed: {e}\n")
sys.exit(0)
if __name__ == "__main__":
main()
+24
View File
@@ -0,0 +1,24 @@
# /athena-dev (Codex) — 主入口
`.ai_state/` 不存在 → 提示 `/athena-init` 并停。
`schema_version` != "9.6" → 提示 `/athena-migrate` 并停。
## Get-bearings (R₀, just-in-time, 铁律 8)
1. **必读**: `.ai_state/_index.md`
2. **按需**: stage=impl/review → 按 pointers.latest_progress 读 progress.md 尾部
3. **按需**: 任务命中 lessons 主题 → pointers.latest_lesson 跳段
4. **按需**: `git log --oneline -10`
5. **按需**: impl/review 阶段 → `bash .ai_state/init.sh`
文件大就用 head/tail/grep。**禁止 glob 整个 .ai_state/**。
## Dispatch
有进行中的 stage → 从当前阶段继续 (参考 `~/.codex/skills/pace/SKILL.md`)。
新需求 → 触发 pace skill 路由, 需求: $ARGUMENTS。
Codex 端特别注意:
- **无 /goal** → delivery-gate hook 兜底判定
- **无 /batch** → 多任务用 spawn_agent (config.toml [agents] 配置)
- **无 compact 生命周期** → 长任务点主动写 `.ai_state/_index.md` 保存
+67
View File
@@ -0,0 +1,67 @@
# /athena-init (Codex) — 项目初始化
# 描述
> 项目初始化。每个新项目首次使用 Athena 时运行。
# end
参考: <https://developers.openai.com/codex/concepts/customization>
`.ai_state/_index.md` 已存在 → 提示用户用 `/athena-migrate` 升级或确认覆盖。
## 1. 项目扫描
```bash
ls package.json pyproject.toml Cargo.toml go.mod build.gradle pom.xml 2>/dev/null
cat package.json 2>/dev/null | grep -A5 '"scripts"'
ls jest.config* vitest.config* pytest.ini .eslintrc* ruff.toml biome.json 2>/dev/null
```
## 2. 创建 .ai_state/ (v9.6 schema)
```bash
mkdir -p .ai_state/details/reviews .ai_state/details/tasks-archive
```
## 3. 拷贝模板
从 `~/.codex/skills/pace/templates/` 复制:
- `_index.md` → `.ai_state/_index.md`
- 所有 `details/*.md`
- `init.sh`
## 4. 填充 _index.md frontmatter
把扫描结果写入: tech_stack, test_cmd, build_cmd, lint_cmd, dev_cmd
平台特征 (`codex --version` 输出):
- `cx_version`
- `goal_supported`: Codex 当前**没有原生 /goal** → false
- `batch_supported`: Codex subagent (max_threads in [agents]) 部分支持 → 视 max_threads 而定
- `background_supported`: false (Codex 无 /background)
- `session_memory_active`: false (Codex 无 ~/.claude/projects/ 等价物)
- `cross_session_memory`: "none"
## 5. 生成 init.sh
根据扫描结果定制 `.ai_state/init.sh`. `chmod +x`.
## 6. .gitignore
```bash
grep -q '.ai_state' .gitignore 2>/dev/null || echo '.ai_state/' >> .gitignore
```
## 7. Git commit
```bash
git add .ai_state/ .gitignore
git commit -m "athena: project initialized (v9.6 schema, Codex)"
```
## 8. 验证
```bash
bash .ai_state/init.sh
```
告知用户: "Athena (Codex 版) 已就绪。用 `/athena-dev <需求>` 开始, 或 `/athena-status` 看面板。"
+155
View File
@@ -0,0 +1,155 @@
# /athena-migrate (Codex) — v9.5 → v9.6 迁移
参考 CC 版 `~/.claude/skills/athena-migrate/SKILL.md`. 算法一致 (因为 schema 跨平台相同, 这是铁律 6).
Codex 端差异:
- 用 python3 替代 node 生成 `_index.md` (Codex 默认有 python3)
- 检测 `cx_version` 写入 `platform_features.cx_version`, **不写** cc_version
## 备份脚本
```bash
mkdir -p .ai_state/.legacy-v9.5
cp -r .ai_state/{tasks.md,design.md,progress.md,lessons.md,handoff.md,project.json,reviews,hook-trace.jsonl} .ai_state/.legacy-v9.5/ 2>/dev/null || true
```
## 创建 details/
```bash
mkdir -p .ai_state/details/reviews .ai_state/details/tasks-archive
```
## 平移
```bash
[ -f .ai_state/tasks.md ] && mv .ai_state/tasks.md .ai_state/details/tasks-current.md
for f in design.md progress.md lessons.md handoff.md; do
[ -f .ai_state/$f ] && mv .ai_state/$f .ai_state/details/$f
done
[ -d .ai_state/reviews ] && mv .ai_state/reviews .ai_state/details/reviews
[ -f .ai_state/compact-snapshot.json ] && rm .ai_state/compact-snapshot.json # Codex 无 compact 也能有的旧文件
```
## 生成 _index.md (python3)
```bash
python3 << 'PY'
import json, os, re, sys
proj = {}
try:
with open('.ai_state/.legacy-v9.5/project.json') as f:
proj = json.load(f)
except FileNotFoundError:
pass
def count_match(path, pattern):
try:
with open(path) as f:
return len(re.findall(pattern, f.read(), re.MULTILINE))
except FileNotFoundError:
return 0
def last_section_line(path, head_prefix='## '):
try:
lines = open(path).read().split('\n')
for i in range(len(lines) - 1, -1, -1):
if lines[i].startswith(head_prefix):
return i + 1
except FileNotFoundError:
pass
return 0
def last_nonempty_line(path):
try:
lines = open(path).read().split('\n')
for i in range(len(lines) - 1, -1, -1):
stripped = lines[i].strip()
if stripped and not stripped.startswith('<!--') and not stripped.startswith('#'):
return i + 1
except FileNotFoundError:
pass
return 0
tasks_pending = count_match('.ai_state/details/tasks-current.md', r'^- \[ \]')
tasks_done = count_match('.ai_state/details/tasks-current.md', r'^- \[x\]')
progress_n = last_nonempty_line('.ai_state/details/progress.md')
lessons_lines = count_match('.ai_state/details/lessons.md', r'^## ')
latest_lesson_line = last_section_line('.ai_state/details/lessons.md')
reviews = []
try:
reviews = [f for f in os.listdir('.ai_state/details/reviews') if re.match(r'^sprint-\d+\.md$', f)]
except FileNotFoundError:
pass
reviews_count = len(reviews)
latest_review = ''
if reviews:
latest_review = 'details/reviews/' + sorted(reviews, key=lambda f: int(re.search(r'\d+', f).group()))[-1]
content = f'''---
schema_version: "9.6"
athena_version: "9.6.0"
project:
path: "{proj.get('path','')}"
stage: "{proj.get('stage','')}"
sprint: {proj.get('sprint', 0)}
active_goal: ""
counts:
tasks_pending: {tasks_pending}
tasks_done: {tasks_done}
tasks_blocked: 0
lessons_lines: {lessons_lines}
progress_entries: {progress_n}
reviews_count: {reviews_count}
pointers:
latest_progress: "{('details/progress.md#L' + str(progress_n)) if progress_n else ''}"
latest_review: "{latest_review}"
latest_lesson: "{('details/lessons.md#L' + str(latest_lesson_line)) if latest_lesson_line else ''}"
latest_proposal: ""
fingerprints:
tasks_mtime: 0
design_mtime: 0
progress_mtime: 0
lessons_mtime: 0
platform_features:
cc_version: ""
cx_version: ""
goal_supported: false
batch_supported: false
background_supported: false
session_memory_active: false
cross_session_memory: "none"
gotchas: {json.dumps(proj.get('gotchas', []))}
conventions: {json.dumps(proj.get('conventions', []))}
tech_stack: "{proj.get('tech_stack','')}"
test_cmd: "{proj.get('test_cmd','')}"
build_cmd: "{proj.get('build_cmd','')}"
lint_cmd: "{proj.get('lint_cmd','')}"
dev_cmd: "{proj.get('dev_cmd','')}"
---
# 项目状态索引 (v9.6 migrated from v9.5.5)
## 最近活动
## 当前阻塞
## 下一动作 (PACE 建议)
## 反思建议 (Hook 沉淀)
'''
with open('.ai_state/_index.md', 'w') as f:
f.write(content)
print('[migrate] _index.md generated')
PY
```
## 收尾
```bash
touch .ai_state/details/next.md .ai_state/details/proposals.md
git add .ai_state/
git commit -m "athena: migrate state to v9.6 schema (codex)"
```
+80
View File
@@ -0,0 +1,80 @@
# /athena-preferences (Codex)
## 设计原则 (同 CC 版)
Athena 不造私有偏好文件。所有写入都是 Codex 原生位置:
| 偏好类型 | Codex 落点 |
|---|---|
| 工具偏好 (pnpm/vitest) | `~/.codex/AGENTS.md` "## Tool Preferences" 段 |
| 风格偏好 (Linus 模式等) | `~/.codex/AGENTS.md` |
**Codex 没有 CC 风格的 permissions.allow/deny.** Codex 用:
- `approval_policy` (on-request / never / on-failure / untrusted) — 顶层
- `sandbox_mode` (workspace-write / read-only / danger-full-access)
- `[shell_environment_policy]` 控制环境
参考: <https://developers.openai.com/codex/config-reference>
所以 `/athena:remember-allow|deny` 在 Codex 上**部分语义不可映射**, 当前实现:
- `/athena:remember-tool <key>=<value>` → 写 `~/.codex/AGENTS.md` "## Tool Preferences"
- `/athena:show-preferences` → cat ~/.codex/AGENTS.md
- `/athena:remember-allow|deny` → 提示用户在 `~/.codex/config.toml` 改 `approval_policy` 或 `sandbox_mode`, **不自动改** (那是 critical 配置)
## 子命令 (Codex)
### `/athena:remember-tool <key>=<value>`
```bash
GLOBAL_AGENTS_MD="$HOME/.codex/AGENTS.md"
mkdir -p "$(dirname "$GLOBAL_AGENTS_MD")"
# 创建文件 / 找到 Tool Preferences 段 / 追加
python3 << PY
import os, re
p = os.path.expanduser("~/.codex/AGENTS.md")
try:
content = open(p).read()
except FileNotFoundError:
content = ""
section = "## Tool Preferences"
arg = "$ARGUMENTS" # 由 Codex 替换
if section not in content:
if content and not content.endswith("\n"):
content += "\n"
content += "\n" + section + "\n\n- " + arg + "\n"
else:
# 在 section 后追加一行 (避免重复)
if "- " + arg in content:
print(f"⚠️ 已存在: {arg}")
exit(0)
content = re.sub(r"(" + re.escape(section) + r"\n+)", r"\g<1>- " + arg + "\n", content, count=1)
open(p, "w").write(content)
print(f"✓ 已加入 ~/.codex/AGENTS.md Tool Preferences: {arg}")
PY
```
### `/athena:show-preferences`
```bash
echo "=== ~/.codex/AGENTS.md (Tool Preferences) ==="
sed -n '/^## Tool Preferences/,/^## /p' ~/.codex/AGENTS.md 2>/dev/null | head -30
echo ""
echo "=== ~/.codex/config.toml (approvals / sandbox) ==="
grep -E "^(approval_policy|sandbox_mode)" ~/.codex/config.toml 2>/dev/null
```
### `/athena:remember-allow|deny <pattern>`
不自动写, 仅提示:
```
⚠️ Codex 没有 permissions.allow/deny 概念.
等价配置在 ~/.codex/config.toml:
- approval_policy: on-request | never | on-failure | untrusted
- sandbox_mode: read-only | workspace-write | danger-full-access
请用编辑器手改这两个字段, 不通过 Athena 自动改 (critical config).
```
+12
View File
@@ -0,0 +1,12 @@
# /athena-review (Codex)
有 `.ai_state/_index.md` → 按当前 Path 触发 pace skill 审查阶段。
无 → 快速审查 (Codex 内置 /review)。
焦点: $ARGUMENTS
Codex 端可用工具:
- `/review` (Codex 内置)
- `spawn_agent reviewer` (从 ~/.codex/agents/reviewer.toml 调度)
- `web_search` 查最佳实践
- 不可: /codex:review (那是 CC 侧反向调用)
+98
View File
@@ -0,0 +1,98 @@
# /athena-setup (Codex)
参考: <https://developers.openai.com/codex/config-basic>
## Step 0: Codex 版本
```bash
codex --version
```
要求 ≥ v0.124 (hooks stable). v0.129+ 解锁 /hooks TUI menu.
写入 `_index.md.platform_features.cx_version`.
## Step 1: 验证 config.toml
`~/.codex/config.toml` 应包含 (从 cx/.codex/config.toml 拷贝):
- `model = "gpt-5.5"`
- `[features] hooks = true` (规范名, 非 deprecated codex_hooks)
- `[[hooks.SessionStart]]`, `[[hooks.PreToolUse]]`, `[[hooks.PostToolUse]]`, `[[hooks.Stop]]`
- `[agents] max_threads = 6`
- `[[skills.config]]` 包含 pace / compound / context7 / superpowers
```bash
codex check config 2>&1 | head -20
```
## Step 2: 部署 hooks
```bash
mkdir -p ~/.codex/hooks
cp cx/.codex/hooks/*.py ~/.codex/hooks/
chmod +x ~/.codex/hooks/*.py
```
Codex hook 列表 (Python, 6 个):
- session-start.py
- user-prompt-submit.py
- pre-bash-guard.py
- index-updater.py
- subagent-retry.py
- delivery-gate.py
⚠️ Codex hooks 当前 Windows 不支持 (官方限制, 参考 <https://developers.openai.com/codex/hooks>)
## Step 3: 部署 skills
```bash
mkdir -p ~/.codex/skills/pace ~/.codex/skills/compound
cp -r cx/.codex/skills/pace/* ~/.codex/skills/pace/
cp -r cx/.codex/skills/compound/* ~/.codex/skills/compound/
```
## Step 4: 部署 prompts (slash commands)
```bash
mkdir -p ~/.codex/prompts
cp cx/.codex/prompts/*.md ~/.codex/prompts/
```
## Step 5: 部署 subagents (单 TOML 文件, 非子目录)
参考: <https://developers.openai.com/codex/subagents>
```bash
mkdir -p ~/.codex/agents
cp cx/.codex/agents/*.toml ~/.codex/agents/
```
部署后:
- `~/.codex/agents/evaluator.toml` — 评分员 (read-only)
- `~/.codex/agents/generator.toml` — 实现者 (workspace-write)
- `~/.codex/agents/reviewer.toml` — 审查员 (read-only)
验证:
```bash
codex /agents 2>&1 | head -20
# 应列出 evaluator, generator, reviewer 三个 custom agent
```
## Step 6: 跨项目记忆 (推荐)
Codex 暂无 claude-mem 等价物。推荐:
- 用 `~/.codex/AGENTS.md` 全局 "## Tool Preferences" 段做轻量记忆
- 多项目用同一 ~/.codex/AGENTS.md (跨项目人工同步)
## Step 7: 验证
```bash
codex --version # ≥ 0.124
ls ~/.codex/hooks/*.py | wc -l # 应 = 6
ls ~/.codex/prompts/*.md # 7 个 athena-* prompt
codex /hooks 2>&1 | head # v0.129+ TUI 显示 hook 树
cat .ai_state/_index.md | head -5 # schema_version: "9.6"
```
通过 → "Codex 端 Athena 已就绪。"
+32
View File
@@ -0,0 +1,32 @@
# /athena-status (Codex)
参考 CC 版 (~/.claude/skills/athena-status/SKILL.md). 等价实现, 差异:
| 字段 | CC 端 | CX 端 |
|------|-------|-------|
| goal_supported | CC v2.1.139+ | **始终 false** (Codex 无 /goal) |
| batch_supported | CC v2.1.121+ | 视 [agents] max_threads 而定 |
| background_supported | CC v2.1.139+ | **始终 false** (Codex 无 /background) |
| session_memory_active | ~/.claude/projects/ | **始终 false** (Codex 无等价) |
## 收集顺序 (同 CC 版)
1. PACE 状态 (从 `.ai_state/_index.md` frontmatter)
2. Sprint 进度 (counts 段)
3. Hook 触发记录 (`tail -50 .ai_state/hook-trace.jsonl`)
4. Lessons 统计
5. Platform 健康 (Codex 特定)
6. Plugin 状态: CX 无插件生态, 仅显示 `codex --version`, `codex /hooks` 输出, `codex /skills`
## Codex 特有显示
```
[Codex Hooks]
/hooks tui: v0.129+
hooks 配置文件: ~/.codex/hooks.json, ~/.codex/config.toml [[hooks.*]]
Windows 支持: 否 (官方限制)
[Codex Subagents]
config.toml [agents].max_threads: <从 config 读>
available roles: evaluator, generator, reviewer
```
-25
View File
@@ -1,25 +0,0 @@
---
name: brainstorm
description: R₀ 苏格拉底式需求精炼
---
# Brainstorm (R₀ 需求精炼)
Path B+ 任务在写代码前**必须**激活。
## 流程
### 0. 自主调研 (提问前)
- 搜索项目中与需求相关的现有代码
- 读 .ai_state/lessons.md + conventions.md
→ 基于调研结果准备更有深度的问题
### 1. 访谈 (苏格拉底式)
- 一次只问一个问题, 优先选择题
- 覆盖: 目标、场景、边界、非功能需求
- YAGNI: 主动砍不必要的功能
### 2. 提出 2-3 方案
- 每方案: 架构 + 优劣 + 复杂度
- context7 验证可行性
### 3. 确认 → .ai_state/design.md
铁律: 设计未确认前不写代码
-18
View File
@@ -1,18 +0,0 @@
---
name: claude-delegate
description: 接收 CC 派发任务 + 反向调用 CC
---
# Claude Delegate
## 当被 CC 调用时
- CC 通过 codex exec 发送任务
- 你在只读沙箱, 输出代码和建议
- 审查请求: 以 `VERDICT: APPROVED` 或 `VERDICT: REVISE` 结尾
## 反向调用 CC (独立运行时)
如需 Claude 视角:
```bash
# 如果有 claude CLI
claude -p "审查以下代码: {code}"
```
如不可用 → 用 validator agent 自审
-18
View File
@@ -1,18 +0,0 @@
---
name: code-review
description: T 阶段代码审查
---
# Code Review
## 审查清单
1. Spec 合规: 每个 MUST 实现?
2. TDD: 源码有对应测试?
3. 边界: 空输入/超长/并发/错误路径?
4. 安全: 无硬编码密钥, 输入已验证
5. 可读: 函数 < 50 行, 注释说 WHY, 严格类型
6. 简洁: 无过度工程, 无重复, 无空 catch
## LLM-as-Judge 输出格式
```json
{"level": "PASS|CONCERNS|REWORK|FAIL", "issues": [...], "summary": "..."}
```
+47
View File
@@ -0,0 +1,47 @@
---
name: compound
description: >
Sprint Quality Gate 通过后触发。提炼本 Sprint 学到的为结构化条目追加 lessons.md。
effort: xhigh
---
# /compound — 经验沉淀
Gate PASS 后触发 (或用户显式 `/compound`).
## 输入
- `.ai_state/details/reviews/sprint-N.md` (审查报告)
- `git diff` (本 Sprint 所有变更)
- `.ai_state/details/tasks-current.md` (完成项)
- `.ai_state/details/design.md` (设计 vs 实际实现对比)
## 提炼方法
从以上输入找**真实发现**, 不写仪式性废话。每 Sprint 0-N 条不强制。
- **Pattern**: 什么解法有效且可复用? (带代码行号 / 文件路径)
- **Pitfall**: 什么坑踩过? 未来同类场景要提前避开
- **Constraint**: 发现的新约束 (依赖版本、环境、性能边界、API 限制)
没发现可提炼的 → 不写, 直接告知用户 "no new lesson". **不允许编造**.
## 输出 (项目级)
追加到 `.ai_state/details/lessons.md` (append-only, 不修改历史).
格式见 `pace/templates/details/lessons.md`. **Athena 不做跨项目知识管理**——需要的话装 claude-mem 或 superpowers。
写入后同步更新 `_index.md`:
- `counts.lessons_lines` += 新增条目数 (按 `## ` 头计)
- `pointers.latest_lesson` = `details/lessons.md#L<新条目行号>`
- `fingerprints.lessons_mtime` = 当前时间戳
## 自检
写入后读回验证:
1. 条目有具体的文件/行号/版本引用 (不只是"要注意 X")
2. 一句话标题能让下次 R₀ 快速扫描命中
3. Pattern/Pitfall/Constraint 三段不强制全有, 但至少有一段
写完告知用户: "Lessons updated. Next sprint R₀ 会自动读取 (按 _index.md.pointers.latest_lesson 跳转)."

Some files were not shown because too many files have changed in this diff Show More