返回

Planning-with-files 教程 9:Hooks 机制深度配置

Hooks 是 Planning-with-files 自动化的核心。本文详解四种 Hook(SessionStart、PreToolUse、PostToolUse、Stop)的工作原理、配置方法和高级定制。

教程概述

Hooks 是 Planning-with-files 自动化的核心机制。通过 Hooks,可以实现自动重读计划、提醒更新状态、验证任务完成等功能。

你将学到

  • ✅ 四种 Hook 的作用时机
  • ✅ 各平台 Hooks 配置方法
  • ✅ 自定义 Hook 行为
  • ✅ Hooks 故障排查

Hooks 机制概述

为什么需要 Hooks?

flowchart LR
    subgraph 无 Hooks
        A1[开始任务] --> B1[执行工作]
        B1 --> C1[忘记更新状态]
        C1 --> D1[目标漂移]
        D1 --> E1[任务失败]
    end

    subgraph 有 Hooks
        A2[开始任务] --> B2[执行工作]
        B2 --> C2[Hook 自动重读计划]
        C2 --> D2[Hook 提醒更新状态]
        D2 --> E2[任务完成]
        E2 --> F2[Hook 验证完成]
    end

    style E1 fill:#ffcdd2
    style E2 fill:#c8e6c9

四种 Hook 类型

Hook 触发时机 核心作用
SessionStart 会话开始时 通知技能就绪、恢复会话
PreToolUse 工具执行前 重读 task_plan.md
PostToolUse 工具执行后 提醒更新状态
Stop 尝试停止时 验证任务完成

Hooks 工作流程

sequenceDiagram
    participant User
    participant Claude
    participant Hook
    participant File as 规划文件

    Note over User,File: SessionStart
    User->>Claude: 开始会话
    Claude->>Hook: SessionStart Hook
    Hook->>File: 检查是否存在规划文件
    Hook->>User: 通知技能就绪/恢复会话

    Note over User,File: 工作循环
    User->>Claude: 执行任务
    Claude->>Hook: PreToolUse Hook
    Hook->>File: 读取 task_plan.md
    Hook->>Claude: 刷新目标到上下文
    Claude->>Claude: 执行工具
    Claude->>Hook: PostToolUse Hook
    Hook->>User: 提醒更新状态(如需要)

    Note over User,File: Stop
    User->>Claude: 停止
    Claude->>Hook: Stop Hook
    Hook->>File: 检查所有阶段状态
    alt 有未完成阶段
        Hook->>User: 警告未完成,继续工作
    else 全部完成
        Hook->>User: 验证通过,可以停止
    end

SessionStart Hook

触发时机

  • Claude Code 会话启动时
  • /clear 后重新开始时

默认行为

[planning-with-files] Ready.
Auto-activates for complex tasks, or invoke manually with /plan

Session Recovery: 检测到未完成的任务 "博客标签系统"
是否继续之前的任务?

配置示例

Claude Code (~/.claude/settings.json):

{
  "hooks": {
    "SessionStart": {
      "command": "bash ~/.claude/hooks/session-start.sh"
    }
  }
}

Cursor (.cursor/hooks.json):

{
  "hooks": {
    "SessionStart": {
      "command": "bash .cursor/hooks/session-start.sh"
    }
  }
}

SessionStart 脚本

#!/bin/bash
# session-start.sh

PLANNING_DIR=".planning"

# 检查是否存在规划文件
if [ -f "task_plan.md" ]; then
    echo "[planning-with-files] 检测到未完成任务"
    echo "任务: $(grep '^# Task Plan:' task_plan.md | sed 's/^# Task Plan: //')"

    # 获取当前阶段
    CURRENT_PHASE=$(grep -A1 '\*\*Status:\*\* in_progress' task_plan.md | head -1 | sed 's/^### //')
    echo "当前阶段: $CURRENT_PHASE"
    echo "输入 '继续' 恢复任务"
fi

# 通知技能就绪
echo "[planning-with-files] Ready. 使用 /plan 开始新任务"

Session Recovery 实现

#!/bin/bash
# session-recovery.sh

# 查找最近的规划文件
LATEST_PLAN=$(find . -name "task_plan.md" -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)

if [ -n "$LATEST_PLAN" ]; then
    # 读取任务目标
    GOAL=$(grep '^## Goal' "$LATEST_PLAN" -A1 | tail -1)

    # 获取进度
    COMPLETE=$(grep -c '\*\*Status:\*\* complete' "$LATEST_PLAN")
    IN_PROGRESS=$(grep -c '\*\*Status:\*\* in_progress' "$LATEST_PLAN")
    PENDING=$(grep -c '\*\*Status:\*\* pending' "$LATEST_PLAN")

    echo "=== Session Recovery ==="
    echo "任务: $GOAL"
    echo "进度: $COMPLETE 完成, $IN_PROGRESS 进行中, $PENDING 待开始"
    echo "========================"
fi

PreToolUse Hook

触发时机

在 Write、Edit、Bash 等工具执行之前触发。

核心作用

注意力操控原理:在长会话中,AI 容易"忘记"原始目标。强制重读 task_plan.md 确保目标始终在注意力中。

flowchart TD
    A[准备执行工具] --> B{是 Write/Edit/Bash?}
    B -->|是| C[PreToolUse Hook 触发]
    B -->|否| D[直接执行]
    C --> E[读取 task_plan.md]
    E --> F[提取 Goal 和当前 Phase]
    F --> G[注入到上下文]
    G --> H[执行工具]

    style C fill:#fff3e0
    style E fill:#e1f5ff

配置示例

Claude Code

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/pre-tool-use.sh"
          }
        ]
      }
    ]
  }
}

PreToolUse 脚本

#!/bin/bash
# pre-tool-use.sh

PLAN_FILE="task_plan.md"

if [ ! -f "$PLAN_FILE" ]; then
    exit 0
fi

# 提取目标
GOAL=$(grep '^## Goal' "$PLAN_FILE" -A1 | tail -1 | sed 's/^//')

# 提取当前阶段
CURRENT_PHASE=$(grep -B1 '\*\*Status:\*\* in_progress' "$PLAN_FILE" | grep '^###' | head -1 | sed 's/^### //')

# 提取关键决策(最近3条)
DECISIONS=$(grep '^|' "$PLAN_FILE" | grep -v '^| Decision' | grep -v '^|---' | head -3)

# 输出提醒
echo "=== 任务上下文刷新 ==="
echo "目标: $GOAL"
echo "当前阶段: $CURRENT_PHASE"
if [ -n "$DECISIONS" ]; then
    echo "最近决策:"
    echo "$DECISIONS"
fi
echo "===================="

匹配器配置

匹配器 说明
Write 写入文件时触发
Edit 编辑文件时触发
Bash 执行命令时触发
Write|Edit 写入或编辑时触发
.* 所有工具都触发

高级配置

条件触发(只对特定文件触发):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/pre-write.sh"
          }
        ]
      }
    ]
  }
}

pre-write.sh

#!/bin/bash
# 只对 src/ 目录下的文件触发

FILE_PATH=$1  # Hook 会传入文件路径

if [[ "$FILE_PATH" == src/* ]]; then
    echo "正在修改源代码,请确认符合设计..."
    # 读取相关设计
    cat findings.md | grep -A5 "API 设计"
fi

PostToolUse Hook

触发时机

在 Write、Edit 等工具执行之后触发。

核心作用

  1. 提醒更新状态:完成阶段后提醒更新 task_plan.md
  2. 检查 2-Action 规则:追踪查看操作次数
  3. 自动记录:自动更新 progress.md
flowchart TD
    A[工具执行完成] --> B{PostToolUse Hook}
    B --> C{检查操作类型}
    C -->|Write/Edit| D[检查是否完成阶段]
    D --> E{阶段完成?}
    E -->|是| F[提醒更新 Status]
    E -->|否| G[继续]
    C -->|Read/Grep| H[追踪查看次数]
    H --> I{达到 2 次?}
    I -->|是| J[提醒更新 findings.md]
    I -->|否| G

    style F fill:#fff3e0
    style J fill:#fff3e0

配置示例

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/post-tool-use.sh"
          }
        ]
      }
    ]
  }
}

PostToolUse 脚本

#!/bin/bash
# post-tool-use.sh

PLAN_FILE="task_plan.md"
PROGRESS_FILE="progress.md"

# 检查是否完成阶段
# 通过检查 task_plan.md 中的子任务完成情况

CURRENT_PHASE=$(grep -B5 '\*\*Status:\*\* in_progress' "$PLAN_FILE" | grep '^###' | head -1 | sed 's/^### //')
TASKS_TOTAL=$(grep -A10 "$CURRENT_PHASE" "$PLAN_FILE" | grep -c '^\- \[ \]')
TASKS_DONE=$(grep -A10 "$CURRENT_PHASE" "$PLAN_FILE" | grep -c '^\- \[x\]')

if [ "$TASKS_TOTAL" -eq 0 ] && [ "$TASKS_DONE" -gt 0 ]; then
    echo "=== 阶段完成提醒 ==="
    echo "阶段 '$CURRENT_PHASE' 的所有任务已完成"
    echo "请更新 task_plan.md 状态为 'complete'"
    echo "==================="
fi

# 记录到 progress.md
TIMESTAMP=$(date '+%H:%M')
ACTION="执行了文件操作"
echo "| $TIMESTAMP | $ACTION | - |" >> "$PROGRESS_FILE"

Stop Hook

触发时机

当 AI 尝试停止任务时触发。

核心作用

验证优先:只有所有阶段都标记为 complete,任务才算完成。

flowchart TD
    A[AI 尝试停止] --> B{Stop Hook}
    B --> C[检查 task_plan.md]
    C --> D{所有 Status: complete?}
    D -->|是| E[允许停止]
    D -->|否| F[阻止停止]
    F --> G[列出未完成阶段]
    G --> H[继续工作]

    style F fill:#ffcdd2
    style E fill:#c8e6c9

配置示例

{
  "hooks": {
    "Stop": {
      "command": "bash .claude/hooks/check-complete.sh"
    }
  }
}

Stop Hook 脚本

#!/bin/bash
# check-complete.sh

PLAN_FILE="task_plan.md"

if [ ! -f "$PLAN_FILE" ]; then
    echo "未找到 task_plan.md,允许停止"
    exit 0
fi

# 检查是否有未完成的阶段
IN_PROGRESS=$(grep -c '\*\*Status:\*\* in_progress' "$PLAN_FILE")
PENDING=$(grep -c '\*\*Status:\*\* pending' "$PLAN_FILE")

if [ "$IN_PROGRESS" -gt 0 ] || [ "$PENDING" -gt 0 ]; then
    echo "=== 任务未完成 ==="
    echo "进行中阶段: $IN_PROGRESS"
    echo "待开始阶段: $PENDING"

    # 列出未完成阶段
    echo ""
    echo "未完成阶段:"
    grep -B1 '\*\*Status:\*\* in_progress\|pending' "$PLAN_FILE" | grep '^###'

    echo ""
    echo "请完成所有阶段后再停止。"
    echo "如果确定要停止,请手动更新 task_plan.md 状态。"
    echo "================="

    # 返回非零阻止停止
    exit 1
fi

echo "=== 任务验证通过 ==="
echo "所有阶段已完成,任务可以停止。"
exit 0

强制停止

有时需要强制停止(如紧急情况),可以:

  1. 跳过 Hook:在配置中临时禁用
  2. 手动更新状态:将所有阶段标记为 complete
  3. 删除规划文件:删除 task_plan.md

各平台配置详解

Claude Code

配置文件~/.claude/settings.json.claude/settings.json

{
  "hooks": {
    "SessionStart": {
      "command": "bash ~/.claude/hooks/session-start.sh"
    },
    "PreToolUse": [
      {
        "matcher": "Write|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/pre-tool-use.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/post-tool-use.sh"
          }
        ]
      }
    ],
    "Stop": {
      "command": "bash ~/.claude/hooks/check-complete.sh"
    }
  }
}

Cursor

配置文件.cursor/hooks.json

{
  "hooks": {
    "PreToolUse": {
      "command": "bash .cursor/hooks/pre-tool-use.sh"
    },
    "PostToolUse": {
      "command": "bash .cursor/hooks/post-tool-use.sh"
    },
    "Stop": {
      "command": "bash .cursor/hooks/check-complete.sh"
    }
  }
}

GitHub Copilot

配置文件.github/hooks/planning-with-files.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash .github/hooks/scripts/pre-tool-use.sh"
          }
        ]
      }
    ],
    "errorOccurred": [
      {
        "type": "command",
        "command": "bash .github/hooks/scripts/on-error.sh"
      }
    ]
  }
}

Gemini CLI

配置文件.gemini/settings.json

{
  "hooks": {
    "SessionStart": {
      "command": "bash .gemini/hooks/session-start.sh"
    },
    "PreToolUse": {
      "command": "bash .gemini/hooks/pre-tool-use.sh"
    },
    "PostToolUse": {
      "command": "bash .gemini/hooks/post-tool-use.sh"
    },
    "Stop": {
      "command": "bash .gemini/hooks/check-complete.sh"
    }
  }
}

高级配置

条件触发

#!/bin/bash
# 只在特定条件下触发

# 获取当前时间
HOUR=$(date +%H)

# 只在工作时间提醒(9-18点)
if [ "$HOUR" -ge 9 ] && [ "$HOUR" -le 18 ]; then
    echo "工作时间提醒:请更新进度"
fi

自定义脚本

集成 Git

#!/bin/bash
# 在每次写入后检查是否需要提交

CHANGED_FILES=$(git status --porcelain | wc -l)

if [ "$CHANGED_FILES" -gt 5 ]; then
    echo "已修改 $CHANGED_FILES 个文件,建议提交一次"
fi

集成测试

#!/bin/bash
# 在完成阶段后自动运行测试

PHASE=$(grep -B1 '\*\*Status:\*\* in_progress' task_plan.md | grep '^###')

if [[ "$PHASE" == *"后端"* ]]; then
    echo "后端阶段完成,运行测试..."
    npm test
fi

故障排查

Hook 不触发

检查清单

  1. 配置文件格式是否正确
  2. 脚本是否有执行权限
  3. 脚本路径是否正确
  4. 匹配器是否正确
# 检查权限
chmod +x .claude/hooks/*.sh

# 检查语法
bash -n .claude/hooks/pre-tool-use.sh

脚本执行错误

调试方法

# 添加调试输出
#!/bin/bash
exec 2>&1
set -x

echo "Hook 执行开始"
# ... 脚本内容
echo "Hook 执行结束"

权限问题

# Windows 上可能需要
"command": "powershell -File .claude/hooks/pre-tool-use.ps1"

小结

Hooks 核心要点

  1. 四种 Hook:SessionStart、PreToolUse、PostToolUse、Stop
  2. 自动化工作流:重读计划、提醒更新、验证完成
  3. 平台适配:各平台配置略有不同
  4. 可定制:通过脚本自定义行为

检查清单

  • SessionStart Hook 配置完成
  • PreToolUse Hook 能重读 task_plan.md
  • PostToolUse Hook 能提醒更新状态
  • Stop Hook 能验证任务完成
  • 脚本有执行权限

系列导航