用户从界面上看出来的两个问题,都是真的。 ## 上次追问显示的是别的项目 取的是 history.first(全局最近一条),于是 agentx 的页面上显示着发给 demo-android 会话的追问。NudgeRecord 加 projectPath,按项目过滤。 ## 手改的清单被盖回去 我往 watchdog.json 写了 47 条,app 用内存里的 25 条盖了回去。 **这个 bug 我今天早上在 AcceptanceStore 上修过一次**(写盘前先重读), 当时没想到 SessionWatchdog 有一模一样的一份。 merge 只捡清单不捡 watching:watching 是界面开关,内存里的才是用户最新 意图,合并的话「关掉盯梢」会被盘上的旧值又打开 —— 开关静默失灵。 这一条是 testCanStopWatching 抓到的,不是我想到的。 455 个测试。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude Hub
Claude Code 本地开发调度中心。用一个 Claude 窗口管理所有项目。
功能
- 灵动岛 — MacBook 刘海变成 agent 控制中心,Liquid Glass + 状态驱动的像素小人
- 实时会话监控 — 每个 Claude 会话的
busy / waiting / shell / idle状态一眼可见 - 精准跳转 — 点通知或点会话,直接跳到那个会话所在的终端 tab(不是"跳到 iTerm 然后自己找")
- 高风险审批 — 不可逆操作(
rm -rf /、force push 到 main 等)在岛上拦截确认 - tmux 多项目管理 — 每个项目一个 tmux 窗口,iTerm2 标签页体验
- 用量统计 — 按项目查看 token 消耗、会话数、模型分布
- 项目发现 — 扫描目录自动生成项目清单
- 浏览器自动化 — Claude in Chrome + DevTools 双引擎协同
新电脑完整安装
1. 安装前置依赖
# Homebrew(如果没有)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 必需
brew install tmux
brew install terminal-notifier
xcode-select --install
# Claude Code CLI(需要 Node.js)
brew install node
npm install -g @anthropic-ai/claude-code
2. iTerm2 tmux 集成(setup.sh 自动配置)
项目使用 tmux -CC 模式(iTerm2 专属),让 tmux 窗口显示为原生标签页。
setup.sh 会自动执行以下配置,无需手动去 GUI 里勾选:
# tmux 窗口显示为 iTerm2 标签页(而非独立窗口)
defaults write com.googlecode.iterm2 OpenTmuxWindowsIn -int 2
# 连接后自动隐藏 tmux 控制会话(避免多余的空白标签)
defaults write com.googlecode.iterm2 AutoHideTmuxClientSession -bool true
如果需要手动验证,可以打开 iTerm2 → Settings (⌘,) → General → tmux 查看这两项是否已勾选。
3. macOS 权限授权
Hub 使用 AppleScript(osascript)自动控制 iTerm2 创建标签页、切换窗口。macOS 需要你授权:
首次运行时,系统会弹窗询问"XXX 想要控制 iTerm2",必须点允许。
如果错过了弹窗或不小心拒绝了:
- 打开 系统设置 → 隐私与安全性 → 自动化
- 找到 Terminal(或 iTerm2),勾选允许控制 iTerm2
- 如果列表里没有,运行一次
osascript -e 'tell application "iTerm2" to activate'触发弹窗
4. 克隆并初始化
git clone https://github.com/hengjun-dev/claude-hub.git ~/Documents/code/claude-hub
cd ~/Documents/code/claude-hub
# 一键初始化:注入全局 hooks + 生成语音文件 + 自动编译托盘 app
# Rust 环境不存在会自动安装,首次编译约 2-3 分钟,需下载约 2GB 依赖
bash scripts/setup.sh
路径说明:
cc.sh启动脚本中硬编码了~/Documents/code/claude-hub路径。如果你克隆到其他位置,需要修改scripts/cc.sh第 9 行的HUB_DIR变量。
5. 添加项目
# 自动扫描目录下所有 git 仓库
bash scripts/scan-projects.sh ~/Documents/code
# 或手动编辑
cp projects.yaml.example projects.yaml
vim projects.yaml
6. 配置启动别名(推荐)
echo 'alias cc="bash ~/Documents/code/claude-hub/scripts/cc.sh"' >> ~/.zshrc
source ~/.zshrc
之后只需输入 cc 即可一键启动调度中心(自动拉起托盘 app + 启动 Claude)。
7. 浏览器自动化(可选)
bash scripts/setup-browser.sh
前置要求:
- Chrome >= 144(支持 autoConnect 模式)
- Claude in Chrome 扩展已安装
配置完成后还需在 Chrome 地址栏输入 chrome://inspect/#remote-debugging,点击 Enable,然后重启 Claude Code 会话。
8. 启动
cc # 如果配了别名
# 或
claude # 在 claude-hub 目录直接启动
启动后 Claude 会根据 CLAUDE.md 的启动序列自动执行:拉起通知面板 → 显示项目列表 → 检查 tmux → 报告就绪。
前置条件汇总
| 依赖 | 用途 | 安装方式 |
|---|---|---|
| macOS + iTerm2 | 终端环境 | 手动安装 |
| tmux >= 3.0 | 多窗口管理 + -CC 模式 |
brew install tmux |
| terminal-notifier | 桌面通知弹窗(点击可跳转) | brew install terminal-notifier |
| Node.js | Claude Code CLI + MCP 工具 | brew install node |
| Claude Code CLI | Claude 命令行 | npm i -g @anthropic-ai/claude-code |
| Xcode CLT | 编译 Rust 代码 | xcode-select --install |
| Rust | 编译托盘 app | setup.sh 自动安装 |
Apple Silicon(M1/M2/M3/M4)和 Intel Mac 均支持,托盘 app 在本机编译,无架构兼容问题。
以下工具为 macOS 内置,无需安装:
say(语音合成)、afplay(音频播放)、osascript(AppleScript 执行)、python3(JSON 处理)。
工作原理
你 ← 桌面通知 + 语音 + 托盘面板 ← 全局 Hook
↓
Hub Claude(调度中心窗口)
├── tmux 窗口: acme-erp → Claude / 终端
├── tmux 窗口: my-api → Claude / 终端
└── tmux 窗口: my-frontend → Claude / 终端
Hub 是你和所有项目 Claude 之间的调度层:
- 你说"开发 xxx" → Hub 自动创建 tmux 窗口
- 你说"在 xxx 跑构建" → Hub 发送命令到对应窗口
- 任何窗口的 Claude 做完事 → 你收到通知
灵动岛(Claude Hub.app)
原生 SwiftUI 应用,把 MacBook 刘海变成 AI agent 的控制中心。要求 macOS 26+,自己编译还需要 Xcode 26。
bash scripts/build-swift-app.sh # 编译 + 签名 + 安装到 /Applications
bash scripts/setup-swift-hooks.sh # 安装 hook 到 ~/.claude/settings.json
open -a "Claude Hub"
打发布包
bash scripts/release.sh # 跑测试 → universal 编译 → 签名 → dmg
产物在 release/Claude-Hub-<版本>.dmg,arm64 + x86_64 双架构。
和日常构建的分工:build-swift-app.sh 只编当前架构、装进 /Applications,几秒钟;
release.sh 打完整发布包,不碰你正在用的那个实例。
包是自签名、未公证的。自己的机器没问题,别人下载后首次打开会被 Gatekeeper 拦,
需要右键 → 打开,或者 xattr -dr com.apple.quarantine "/Applications/Claude Hub.app"。
要做到双击即用得有 Apple Developer Program 的 Developer ID 证书 + 公证。
同一个 bundle identifier 只允许对应 /Applications 里那一个 .app。 留第二份副本 (哪怕只是"调试用")会让 LaunchServices 注册出多条记录,通知授权和 TCC 授权互相抢, 存活判断也会误匹配 —— 构建脚本因此装完就删掉暂存副本。
五种形态
| 形态 | 触发 | 内容 |
|---|---|---|
| 折叠 | 常驻 | 贴刘海挤出一条 14pt 的"下唇":会话数 + 状态点阵 + 待办徽章 |
| 悬停 | 鼠标靠近 | 每个会话一个 32pt 像素小人,状态驱动动作 + 一行统计 |
| 展开 | 点击 | 完整会话列表,点一行精准跳回对应终端 tab |
| 闯入 | 会话完成 / 需要输入 | 主动膨胀提示,2–2.6 秒后回落 |
| 审批 | 拦截到不可逆操作 | 命令内容 + 拒绝/按住确认,不会自动消失 |
无刘海的外接显示器上,折叠态自动退化为屏幕顶部的悬浮胶囊。
像素小人
每个运行中的会话配一个,动作由状态驱动:busy 敲键盘、waiting 抬头挥手、shell 敲命令行、idle 呼吸 + 偶发打哈欠(按 sessionId 错峰,避免所有人同时打哈欠)。
全部小人共用一个 12fps 主时钟,折叠态 / 窗口被遮挡 / 锁屏 / 显示器休眠时整体冻结。
实时会话监控
状态来自 Claude Code 自己维护的 ~/.claude/sessions/<PID>.json,是权威数据而非推断:
| 状态 | 含义 |
|---|---|
busy |
正在干活 |
waiting |
等你输入或授权(附带 waitingFor 说明原因) |
shell |
正在跑 shell 命令 |
idle |
空闲 |
同时区分 interactive(前台会话)和 bg(后台任务)。
精准跳转
点通知、点岛上的会话行,都会跳到那个会话所在的具体终端 tab。
实现方式是从 iTerm 的 jobPid 向上遍历进程树,第一个存在 sessions/<PID>.json 的祖先就是该 tab 承载的会话 —— 全程只用整数 PID 和 UUID,不做任何字符串匹配。tmux -CC 会话和非 tmux 的原生会话用同一套算法。
kind: bg 的会话跑在 daemon 下、不在任何终端里,改为定位到显示它的 claude agents 查看器 tab。
高风险操作审批
PreToolUse hook 会拦截不可逆操作,在岛上弹出审批:
| 级别 | 例子 | 默认行为 |
|---|---|---|
| 普通 | npm install、git commit |
直接放行 |
| 危险 | rm -rf node_modules、git reset --hard、sudo |
只记进审批日志,不拦截 |
| 不可逆 | rm -rf /、force push 到 main、DROP DATABASE |
拦截,需按住 900ms 确认 |
默认只拦最后一档,把日常摩擦压到接近零。想更严格可以在设置里把「危险」一档也打开 —— 建议先看一周审批日志再决定。
防误点做了六重保护:按钮间距 24pt 不融合、出现后 700ms 时间锁、指针进入 120ms 冷却、不可逆操作必须长按、默认焦点在拒绝(⏎ 和 ⎋ 都是拒绝,允许必须 ⌘⏎)、60 秒超时自动拒绝。
主窗口
托盘菜单 → 打开主窗口。五个分区:会话 / 项目 / 用量 / 审批日志 / 设置。
和岛的分工:岛是一瞥(零点击获取状态),主窗口是深挖(用量趋势、项目管理、审批历史)。两者共享同一套数据和组件。
项目管理
# 扫描目录下所有 git 仓库
bash scripts/scan-projects.sh ~/Documents/code
# 手动添加项目
bash scripts/add-project.sh my-app ~/code/my-app app 前端
# 查看项目列表
bash scripts/welcome.sh
主窗口的「项目」页也能直接扫描、搜索、按 8 种模式启动(Claude Code / 跳过权限 / 纯终端 / 继续上次会话 / 选择历史会话 / Finder / VS Code)。
开发
cd HubKit
swift build # 编译
swift test # 87 个测试
swift run hubprobe list # 命令行查看会话与终端绑定
swift run hubprobe jump 3 # 跳到第 3 个会话
工程结构见 HubKit/,实测踩过的坑记在 HubKit/NOTES.md。
浏览器自动化
Claude in Chrome(视觉引擎)+ chrome-devtools-mcp(数据引擎)双引擎协同,连接同一个 Chrome 浏览器。
前置要求:
- Chrome >= 144(支持 autoConnect 模式)
- Claude in Chrome 扩展已安装
- Chrome remote debugging 已启用
# 一键配置(安装 skill + 配置 MCP + 检查 Chrome 环境)
bash scripts/setup-browser.sh
配置完成后:
- Chrome 地址栏输入
chrome://inspect/#remote-debugging,点击 Enable(一次性操作) - 重启 Claude Code 会话
故障排查
通知不工作
# 1. 检查 hook 是否已注入
cat ~/.claude/settings.json | python3 -m json.tool | grep -A5 hub-hook
# 2. 手动触发测试(应该听到语音 + 看到桌面通知)
bash scripts/hub-hook-stop.sh
# 3. 检查 terminal-notifier
which terminal-notifier || echo "未安装,运行: brew install terminal-notifier"
iTerm2 标签页不显示
- 确认 iTerm2 设置:Settings → General → tmux → 两个选项都勾选(见上方 "配置 iTerm2" 章节)
- 确认 tmux 版本:
tmux -V(需要 >= 3.0) - 手动测试:在 iTerm2 中执行
tmux -CC new -s test,应该弹出新的原生标签页
osascript 权限报错
Not authorized to send Apple events to iTerm2
- 打开 系统设置 → 隐私与安全性 → 自动化
- 找到 Terminal(或 iTerm2),勾选允许控制
- 手动验证:
osascript -e 'tell application "iTerm2" to activate'
灵动岛不出现 / 点不动
# 1. 确认跑的是新版(可执行文件名叫 ClaudeHub)
pgrep -x ClaudeHub || open -a "Claude Hub"
# 2. 重新编译安装
bash scripts/build-swift-app.sh
# 3. 确认 hook 链路通
~/.local/bin/hubctl doctor
判断是否在运行必须用 pgrep -x ClaudeHub。用 pgrep -f "Claude Hub"
会匹配到任何路径里含这个串的进程,历史上仓库里同时存在过三个同名 bundle,
导致明明没在跑也被判成"已运行"。
app 编译失败
# 需要 Xcode 26(macOS 26 SDK)——灵动岛依赖 Liquid Glass API
xcrun --show-sdk-version # 应 >= 26
sudo xcodebuild -runFirstLaunch
浏览器双引擎连不上
# 检查 Chrome 版本(需要 >= 144)
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
# 检查远程调试端口
curl -s localhost:9222/json/version
# 检查 MCP 配置(应包含 --autoConnect)
claude mcp get chrome-devtools
目录结构
claude-hub/
├── CLAUDE.md # Hub 行为规范(Claude 读取此文件决定行为)
├── projects.yaml.example # 项目配置模板
├── HubKit/ # 全部业务逻辑(SwiftPM package,可 swift test)
│ ├── NOTES.md # 实测踩到的坑(值得先读一遍)
│ └── Sources/
│ ├── HubCore/ # 数据模型(AgentSession 等)
│ ├── HubProbe/ # 会话探测:sessions/*.json + tmux + 进程树
│ ├── HubJump/ # 跳转引擎:iTerm jobPid 祖先链
│ ├── HubIPC/ # Unix socket + hook 协议 + 风险分级
│ ├── HubProjects/ # projects.yaml + git 状态 + 终端派发
│ ├── HubUI/ # 灵动岛 + 主窗口(SwiftUI)
│ ├── hubctl/ # hook 可执行文件
│ └── ClaudeHubApp/ # 薄壳:@main + 窗口装配
├── Resources/AppIcon.icns
├── scripts/
│ ├── setup.sh # 一键初始化(hook + 编译安装)
│ ├── setup-swift-hooks.sh # 装 hubctl 并改写 ~/.claude/settings.json
│ ├── build-swift-app.sh # 编译 + 签名 + 安装到 /Applications
│ ├── setup-browser.sh # 浏览器环境配置
│ ├── cc.sh # 一键启动(app + 调度中心)
│ ├── scan-projects.sh # 扫描目录发现项目
│ ├── add-project.sh # 添加项目
│ ├── welcome.sh # 项目列表展示
│ ├── project-menu.sh # tmux 窗口菜单
│ ├── hub-run.sh # 命令包装(带信号)
│ └── hub-notify.sh # 手动通知
├── skills/
│ ├── tmux-hub/ # 终端调度 skill
│ ├── browser-auto/ # 浏览器自动化 skill
│ └── lanhu-design-viewer/ # 设计稿查看 skill
└── sounds/ # 语音文件(setup.sh 自动生成)
├── done1~5.aiff # "搞定了" 等 5 种完成语音
└── auth1~3.aiff # "需要授权" 等 3 种提示语音
License
MIT