我如何为 Claude Code 构建移动审批系统,让我终于可以离开办公桌
I’m happy to translate the article for you, but I need the actual text of the post. Could you please paste the content you’d like translated (excluding any code blocks or URLs you want to keep unchanged)? Once I have the text, I’ll provide a Simplified‑Chinese translation while preserving the original formatting and markdown.
每个 AI‑Coding‑Agent 用户都会遇到的问题
我端着咖啡回来,发现 Claude Code 已经卡死了 15 分钟。
随着 AI 编码代理获得更高的自主性——编写代码、执行构建、修改文件——人工监督变得至关重要。你希望代理持续工作,但也想知道它在做什么。权限提示是检查点,却也是瓶颈。
- 将命令加入 allowlist 可以减少提示,但对未知命令和文件写入进行一刀切的批准风险很大。
- 一直盯着终端也不现实。
于是我构建了 claude‑push —— 一个用于 Claude Code 的异步“人在回路中”批准层。它利用 PermissionRequest 钩子和 ntfy.sh 将 “允许/拒绝” 推送通知直接发送到你的手机。开源,3 分钟即可完成设置。
两难:留在桌前还是全部放行
When you delegate code generation and refactoring to Claude Code, you’ll inevitably see prompts like this:
Claude wants to run: rm -rf dist && npm run build
Allow? (y/n)
每次弹出此提示时,你必须返回终端并按 y。如果你正专注工作(或只是去喝咖啡),可能会错过,导致 Claude Code 处于空闲状态。
| 方法 | 优点 | 缺点 |
|---|---|---|
| 手动在终端批准 | 安全 | 不能离开座位 |
| 允许全部 | 方便 | 未知命令仍会通过 |
| 移动推送通知 | 离开桌面 + 安全 | 需要初始设置 |
claude‑push 让选项 3 成为现实。
Source: …
先前技术
konsti‑web/claude_push 解决了相同的问题,但它依赖 Windows + PowerShell + 按键注入——在 macOS 或 Linux 上无法工作。我也遇到了同样的痛点,于是我从头重新实现了该概念,使用 Bash + PermissionRequest hooks。
工作原理:PermissionRequest Hook + ntfy.sh
Claude Code 有一个 Hooks 系统,允许你在特定事件上运行外部脚本。通过在 PermissionRequest 事件上注册 hook,你可以拦截权限提示并返回自己的决定。
Claude Code requests permission
→ Hook script fires
→ Sends notification with Allow/Deny buttons to ntfy.sh
→ Phone receives the push notification
→ You tap Allow or Deny
→ Response received via ntfy.sh SSE
→ Hook returns allow/deny JSON
→ Claude Code continues or stops
ntfy.sh 是一个免费、基于 HTTP 的推送通知服务。无需账号——只要知道主题名称,就可以发送和接收通知。不同于 Pushover 或 LINE Notify,你只需使用一条 curl 命令即可发送通知,这使它非常适合作为 hook 脚本的实现方式。
实现细节
该钩子脚本约有 60 行 Bash。下面是三个关键设计决策。
1. 使用 ntfy.sh HTTP Actions 实现按钮
ntfy.sh 支持 Action Buttons。我使用 http 动作,使点击按钮时向单独的响应主题发送 POST 请求。
curl -s -H "Content-Type: application/json" \
-d "$(jq -n \
--arg topic "$TOPIC" \
--arg title "[$PROJECT] $TOOL_NAME" \
--arg message "$TOOL_INPUT" \
--arg allow_url "https://ntfy.sh/${RESPONSE_TOPIC}" \
--arg allow_body "allow|$REQ_ID" \
--arg deny_url "https://ntfy.sh/${RESPONSE_TOPIC}" \
--arg deny_body "deny|$REQ_ID" \
'{
topic: $topic,
title: $title,
message: $message,
priority: 4,
tags: ["lock"],
actions: [
{action:"http", label:"Allow", url:$allow_url, method:"POST", body:$allow_body},
{action:"http", label:"Deny", url:$deny_url, method:"POST", body:$deny_body}
]
}')" "https://ntfy.sh/"
关键细节: 通知主题和响应主题是不同的通道。这可以防止 SSE 流被你自己的外发通知污染。
2. SSE + 请求 ID 用于响应匹配
发送通知后,钩子会在 ntfy.sh SSE 端点上等待响应。
REQ_ID="$(date +%s)-$$"
while IFS= read -r line; do
if [[ "$line" == data:* ]]; then
DATA="${line#data: }"
MSG=$(echo "$DATA" | jq -r '.message // empty' 2>/dev/null)
if [[ "$MSG" == *"|$REQ_ID" ]]; then
DECISION="${MSG%%|*}"
break
fi
fi
done < <(curl -s -N --max-time "$WAIT_TIMEOUT" \
-H "Accept: text/event-stream" \
"https://ntfy.sh/${RESPONSE_TOPIC}/sse")
REQ_ID(时间戳 + PID)嵌入在通知正文中,并与响应进行匹配。这确保 即使多个权限请求同时触发,每个响应也能匹配到正确的请求。若没有此机制,之前通知的响应可能会被错误地应用到新请求上。
3. 超时回退到终端
如果在超时时间窗口内未收到响应,脚本不输出任何内容并以代码 0 退出。
if [ "$DECISION" = "allow" ]; then
jq -n '{hookSpecificOutput:{decision:{behavior:"allow"}}}'
elif [ "$DECISION" = "deny" ]; then
jq -n '{hookSpecificOutput:{decision:{behavior:"deny"}}}'
fi
# Timeout: no output → falls back to interactive prompt
在 Claude Code 的钩子规范中,无输出 + 退出码 0 表示“钩子未作出决定”,此时会回退到标准终端提示。
快速入门(≈ 3 分钟)
- 创建一个 ntfy.sh 主题(例如
myproject-perm)。 - 将钩子脚本 添加到
~/.config/claude-code/hooks/PermissionRequest.sh(并设为可执行)。 - 设置环境变量(或编辑脚本)以指定:
TOPIC– 你创建的通知主题。RESPONSE_TOPIC– 用于响应的第二个主题(例如myproject-perm-resp)。WAIT_TIMEOUT– 等待响应的秒数(默认 30)。
- 重启 Claude Code – 下一次权限请求将向你的手机发送推送通知。
就这样!现在你可以随时在任何地方批准或拒绝 Claude Code 的操作,而无需一直盯着终端。 🎉
Claude‑Push – Claude Code 的移动批准
即使您没有查看手机,也可以在超时后从终端处理批准。不会静默授予任何权限。
设置
先决条件
- macOS 或 Linux
- 已安装
bash、jq、curl - 手机上已安装 ntfy 应用(ntfy.sh)
安装
git clone https://github.com/coa00/claude-push.git
cd claude-push
bash install.sh
安装程序会引导您完成以下步骤:
| 步骤 | 功能说明 |
|---|---|
| 依赖检查 | 验证 jq 和 curl 是否可用 |
| 主题名称输入 | 如果留空则生成随机名称(例如 claude-push-a1b2c3d4) |
| 配置文件创建 | 写入 ~/.config/claude-push/config |
| 钩子部署 | 将脚本放置在 ~/.local/share/claude-push/hooks/claude-push.sh |
| Claude 设置注册 | 使用 jq 安全地将钩子合并到 ~/.claude/settings.json 中 |
| 测试通知 | 发送测试推送以验证一切正常 |
安装完成后,在 ntfy 应用中订阅您的主题,即可使用。
配置
编辑 ~/.config/claude-push/config。无需重新安装。
# 主题名称(充当 ntfy.sh 频道的共享密钥)
CLAUDE_PUSH_TOPIC="my-unique-topic"
# 超时时间(秒),超时后回退到终端提示
CLAUDE_PUSH_TIMEOUT=90
验证
# 发送带有“允许/拒绝”按钮的测试通知
bash scripts/test.sh test-notify
# 检查安装状态
bash scripts/test.sh status
status 的示例输出:
=== claude-push status ===
[OK] Config: ~/.config/claude-push/config
Topic: my-unique-topic
Timeout: 90s
[OK] Hook: ~/.local/share/claude-push/hooks/claude-push.sh
[OK] Settings: hook registered in ~/.claude/settings.json
[OK] Dependency: jq
[OK] Dependency: curl
卸载
bash uninstall.sh
脚本会从 Claude 设置中移除钩子并清理所有已安装的文件。
实际操作示例
-
Ask Claude Code 重构某些内容,然后离开你的桌子。
-
几分钟后你的手机震动:
[myproject] Bash: npm run build -
在手机上点击 Allow。
-
当你回来时,构建已经完成。
你可以在会议中、散步时或喝咖啡时批准或拒绝命令——前提是你带着手机。
前后比较
| 功能 | 之前(仅终端) | 之后(移动推送) |
|---|---|---|
| 批准方式 | y / n in terminal | 手机上的 Allow / Deny 按钮 |
| 离开时 | Claude stops and waits | 通过推送通知处理 |
| 超时 | None (waits forever) | 90 s 后回退到终端 |
| 安全性 | Allowlist or manual check | 每条通知逐案批准 |
| 设置成本 | — | bash install.sh 大约 3 min 完成 |
安全考虑
- ntfy.sh 主题名称 是一个 共享密钥。任何知道它的人都可以发送通知或伪造响应。
- 为主题名称使用随机、难以猜测的字符串(安装程序默认会生成一个)。
- 如需更严格的控制,请配置 ntfy.sh access control。
- 在允许列表中显式阻止危险命令(例如
rm -rf …),以提供额外的安全层。
总结
Claude Code 最初的权限系统要么让你一直盯着终端,要么把所有东西都加入白名单。claude-push 增加了 第三种选择——移动端批准。
- 实现方式:Bash + ntfy.sh HTTP 动作 + 服务器发送事件(Server‑Sent Events)。
- Hook 本身只有约 60 行。
- 它之所以能工作,是因为 Claude Code 的 Hooks API 只需要一个包含
allow或deny的 JSON 对象。
这一模式适用于任何 AI 编码代理:随着代理能力的提升,我们需要轻量级、异步的批准机制,而不必一直盯着屏幕。移动端推送通知正好满足这一需求——足够快以保持代理运行,又足够可见以便监督。
最好的开发者工具就是让你可以把视线从屏幕上移开五分钟的工具。claude-push 就是这样的工具。
你是如何处理 AI 代理权限的? 无论你是白名单拥护者还是手动检查倡导者,试试 claude-push 并告诉我你的感受。
https://github.com/coa00/claude-push
References
- Claude Code Hooks Documentation – Claude 代码钩子文档
- ntfy.sh – HTTP‑based push notification service – ntfy.sh – 基于 HTTP 的推送通知服务
- ntfy.sh Action Buttons – ntfy.sh 动作按钮
- konsti‑web/claude_push – Original inspiration (Windows/PowerShell version) – konsti‑web/claude_push – 原始灵感(Windows/PowerShell 版)