Coding 工具 · 01

Claude Code

使用 Claude Code 的 Stop hook 把“主 Agent 完成一轮响应”转换为 bluebell completed 事件。先仅本机验证,再打开远程路径。

当前官方生命周期

为什么选择 Stop

Claude Code 将 Stop 定义为主 Agent 完成响应时触发的 hook。它没有 matcher;回调 JSON 通过 stdin 传给命令,并包含会话、工作目录与 transcript 路径等字段。

步骤 1

创建本机转换脚本

把下面脚本保存为你自己的固定路径,例如 ~/.local/bin/claude-bluebell.py。它不读取 transcript 内容,只使用文件大小与会话 ID 生成本轮稳定身份。

claude-bluebell.py
#!/usr/bin/env python3
import hashlib, json, os, subprocess, sys

CLI = "/Applications/bluebellMac.app/Contents/Helpers/bluebellctl"

try:
    payload = json.load(sys.stdin)
except Exception:
    sys.exit(0)

if payload.get("hook_event_name") != "Stop" or payload.get("stop_hook_active"):
    sys.exit(0)

session_id = str(payload.get("session_id") or "")
transcript = str(payload.get("transcript_path") or "")
cwd = str(payload.get("cwd") or "")
if not session_id or not transcript:
    sys.exit(0)

try:
    transcript_size = os.path.getsize(transcript)
except OSError:
    sys.exit(0)

signature = f"{session_id}\0{transcript}\0{transcript_size}"
turn_id = hashlib.sha256(signature.encode()).hexdigest()[:24]
workspace_name = os.path.basename(cwd) or "Claude Code"

subprocess.run([
    CLI, "emit",
    "--source", "Claude Code",
    "--workspace-name", workspace_name,
    "--session-id", session_id,
    "--turn-id", turn_id,
    "--dedupe-key", f"claude-code:{session_id}:{turn_id}",
    "--local",
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=3, check=False)

示例保留 --local,先验证本机链路。脚本故意丢弃 bluebell 输出并始终不让通知问题阻塞 Claude Code。

步骤 2

合并到 Claude Code 设置

用户级设置通常位于 ~/.claude/settings.json。将以下对象合并到现有 hooks.Stop;不要覆盖其他 hooks,也不要照抄示例绝对路径。

settings.json fragment
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 /absolute/path/claude-bluebell.py"
          }
        ]
      }
    ]
  }
}

步骤 3

确认一次可见完成只产生一条记录

  1. 保持 bluebell Mac 运行,并执行一轮简短 Claude Code 任务。
  2. 约 2 秒后检查“最近提醒”,确认来源、项目名与一条记录。
  3. 测试一次继续执行、一次带子任务的工作流,确认没有错误的额外完成。
  4. 确认稳定后,从脚本删除 --local,开启 Mac 总推送,再做真实设备验证。

如果你的 Claude Code 版本没有 transcript_path,不要把此示例直接用于正式去重;请根据该版本官方 payload 改用稳定的轮次身份。

来源

Claude Code 官方资料