背景痛点 · Why this exists
5 月之前派 CC 干活,踩坑按出现顺序排列 — 不是想象,是真出过事。
- CC 子进程没爹 — 手敲 claude -p "..." 跑长任务,关 terminal 就死,没有统一会话台账。
- 跨项目切换昂贵 — 6 个项目各自 cwd / env / .env,每次都要重切。
- 任务结果靠人盯 — 跑 5 分钟出错你不在场就白跑;跑完没有"回吐结果"机制。
- 环境污染连环坑 — DevHub 自己是 systemd NODE_ENV=production 起的,spawn 子进程把这个 env 透传下去,prisma migrate dev 当 prod 跑(PR #11 才解决)。
- CC 自杀 bug 找不到 — CC 跑着跑着 exit 143,绕了 4 天才定位根因(PR #56~#58)。
- 手机端发不了任务 — 在飞书里看到 bug,掏手机想立刻派个修复任务 → 没入口。
DevHub 一句话:让"派单 → 跑 → 看结果 → 复盘"这条链跟项目数量、设备形态、环境差异解耦。
5 个核心抽象 · Five abstractions
架构 · System architecture
三端入口(桌面 Web / 手机 PWA / 飞书 Hermes Agent)→ tRPC over HTTPS → server.ts (Next.js 16 + tRPC + WebSocket /pty) → MCP/systemd-run 调度执行层 → Postgres + 项目本地 .devhub/。
入口层(三选一发起任务)
┌─ 桌面 Web /workspace/<projectId> (Tasks/Chat/Files/Git/Env/Terminal/Snapshot)
├─ 手机 Web (PWA) /m/projects, /m/tasks, /m/chat (bottom-tab + 下拉刷新)
└─ Hermes Agent 飞书机器人 通过 DevHub MCP server 派单(dispatch_task)
↓ tRPC over HTTPS (subscriptions + live polling 3s)
业务层 server.ts (Next.js 16 + tRPC + WebSocket /pty)
├─ Task Dispatcher + reconcile 状态机 / 取消 / 孤儿接管
├─ Env Manager (W1/W2/v2) ai-managed 自动 probe
├─ Snapshot Preview 起项目 dev server + 预览子域名反代
├─ Health Monitor 健康分=成功率,<0.7 或连击≥3 触发告警
├─ MCP Server (16 个工具) 给 Hermes / Claude Code 反向回调
└─ Authz (审批 + 项目成员绑定) admin / member / owner 三档兜底
↓ MCP stdio ↓ systemd-run --user --scope
执行层
├─ lark-channel-bridge (cc-bridge) 每个任务独立 cgroup unit
└─ claude CLI (Anthropic) cwd=项目本地路径
↓ ↓
数据层
├─ Postgres (schema=claude) User / Project / Task / Snapshot / PortLease / ...
├─ 项目本地仓库 .devhub/ recipe + 任务 stdout/jsonl
└─ Hermes state.db 会话 / 记忆 / 技能(独立进程)
关键数据流(一次"飞书派任务"完整链路):飞书消息 → Hermes Agent → DevHub MCP dispatch_task → Task DB 入库(pending)→ Dispatcher 起 cc-bridge → systemd-run 起 claude 进程 → claude 在项目目录跑 → stdout/jsonl 实时回写 → 前端三端 live polling 3s 刷新 → 完成回写 status + cost + memory_patches → 飞书回包"✅ 任务完成"。
11 条关键里程碑 · Milestones
- 05-08立项首个 commit Initial commit: nexora-devhub project(6ffd9ea),项目开张
- ★05-15主入口从 Mattermost/Clawline 切到 Hermes Agent + 飞书;同日 env-mgmt step1/2 上线(DB schema + EnvChips UI)
- 05-16单日 55+ commits 爆发:env-W1(SSRF/XSS/越权一锅端)+ env-W2 状态机 + settings-v2 W1.5→W1.16 + mcp-W1.11 加 16 个 Hermes MCP 工具
- 05-19CC 首次在 PackHorizon 和 Agent Portal 上跑探测任务(DevHub recipe 协议跑通)
- 05-20DevHub 本地化生产部署(nexora-devhub.service systemd 单元上线),task assignment JSON 派单协议稳定
- ★05-21一天合 13 PR:Snapshot Phase 1 PR-1.1→1.7 串发 + strip-polluted-env-from-child-procs(PR #11)+ release v0.2.1
- 05-253 个 worktree 同时跑 issue #14/#15/#16,DevHub MCP server (PR #17) + routingNotes (PR #18) + 健康分 (PR #19) 三连合
- 05-28多用户接入:用户审批 + 项目成员绑定(PR #26),admin/member 兜底(PR #27/#28)
- 05-29越权审计 4 处修复(PR #33 IDOR / #34 snapshot+task authz / #32 ProjectEnv 对账 / #35 Task 索引反规范化)
- ★05-3018 个 PR (#30~#48) 一日合:dispatcher 本机 spawn → MCP 客户端、IDOR 4 处修、健康分=成功率重定义、port-pool 退役 → PortLease 唯一账本、手机端项目卡片页
截图位 · 手机 PWA 任务页 移动端 running 任务彩虹呼吸边 + 通知红点 必截
- ★05-31SIGTERM 143 三连发修复(PR #56 cgroup 隔离 / #57 singleton pin globalThis / #58 ANTHROPIC env 透传)+ 任务卡片 inline live 状态(PR #59)+ DEPLOY.md 全套写完
截图位 · 任务卡片 live 状态(最好录 GIF) running 任务行内联显示 CC 当前 tool / 最后一行输出 + 呼吸彩虹边 必截
12 条关键 PR · Top commits
从 318 commits / 56 PR 里挑出"架构改动 / 安全修复 / 性能优化 / 大爆发日"四个维度的代表。
| PR #11 | 安全 | fix(aiManagedDev): env 隔离 + 三段 envHints 合并 — 子进程 NODE_ENV 污染彻底根治,prisma migrate dev 不再当 prod 跑 |
| PR #13 | 发版 | release: v0.2.1 — decouple probe + strip polluted env · 第一个稳定 release tag |
| PR #14→#17 | 架构 | feat(mcp): DevHub MCP server — 反向暴露 16 个工具给 Hermes / CC 调用,闭环关键 |
| PR #19 | 优化 | feat(health): project health score + alerts — 健康分模型上线,给 #44 重定义为"成功率"打底 |
| PR #26 | 架构 | feat(auth): user approval + project member binding — 单用户 → 多用户演进的分水岭 |
| PR #33 | 安全 | fix(authz): 修复越权/IDOR 四处 — 多用户上线后必须打掉的 P0 越权 |
| PR #31 | 架构 | refactor(port): 退役 port-pool, PortLease 成为唯一端口账本 — 双账本合一,符合"不留新老共存"铁律 |
| PR #49 | 架构 | feat(cc): 用 MCP 替代本机 spawn(e36d4ce)— 从孤儿子进程 → 受 cgroup 管的命名 unit |
| PR #56 | 修复 | fix: 用 systemd-run --scope 隔离 cc-bridge cgroup 防自杀 — SIGTERM 143 真凶第一刀 |
| PR #57 | 修复 | fix(mcp): pin ClaudeCodeMcp singleton to globalThis — 防 Next.js 模块复制造双 bridge(4 天误判 5 方向的最大坑) |
| PR #58 | 修复 | fix(mcp): pass ANTHROPIC_* env into systemd-run user scope — cc-bridge 终于能拿到 API key |
| PR #59 | 爆发 | feat(tasks): inline live status — 任务卡片行内实时显示 CC 当前工具 / 最后一行输出,3s 刷新,桌面+手机统一 |
| PR #50+#51 | 爆发 | feat: 手机端 MCP UI 对齐 + 任务闭环通知 — 移动办公闭环 |
名场面 · Hall of Fame
PR #57 · globalThis singleton 误判史诗
现象
派 CC 单子,跑着跑着 claude 子进程突然 exit 143(SIGTERM),但谁也没 kill 它。CC 自己日志 ~/.claude/projects/*/jsonl 最后一行还在好好写 tool call,下一秒就没了。手动 claude -p "ping" 一切正常。
4 天里误判的 5 个方向
-
✗pkill -f 自杀怀疑 dispatch 脚本里 pkill -f claude 把自己 prompt 里出现的 "claude" 匹配上自杀。查 ps -ef 看父子关系。pkill 那条根本没跑。
-
✗systemd OOM看 journalctl -k | grep -i oom,再 systemd-cgtop 看 cc-bridge scope 内存。没 OOM 记录,内存才几十 M。
-
✗ANTHROPIC env 没透传因为 PR #58 刚修过 env 透传,以为没修干净。在子进程里 claude -p "ping"。跑通了,env 确实在。
-
✗MCP transport 心跳超时主动断改 SDK 心跳间隔、加 reconnect。没用;断完 CC 还是 143。
-
✗Next.js HMR 重载怀疑 dev 模式热重载把 module 重新求值,dispose 老 client。关 HMR 跑 prod build。还是复现 — 但这里其实摸到了边。
定位的关键一击
根因
修复一句话
沉淀到 memory 的教训
子进程启动就死,先 claude -p "ping" 验环境,再查架构 + 看任务实际跑了什么命令(~/.claude/projects/*/jsonl 最后一行),再扣机制。pkill -f <pat> 若 <pat> 出现在自己 prompt 参数里会自杀。
衍生:Next.js 里所有"全进程应当只有一个"的对象(DB client / MCP bridge / 后台 worker),都要 pin 到 globalThis,别信 module-local const。
技术栈 · Tech stack
代码规模:235 个 .ts/.tsx 文件,src 下分 app(路由)/ components / lib / server(tRPC routers 19 个 + 业务 lib)。
现状 + 未结清债务 · Status & debt
现状(2026-06-01 实测)
- 部署 · 本机 systemd nexora-devhub.service,监听 6006,Caddy 反代到 devhub.dora.restry.cn(仅内网可达,未对公网)
- 数据规模 · 6 个项目 · 78 历史任务(成功率 65%)· 2 个用户
- 代码体量 · 318 commits · 56 merged PR · 33 model/enum · 19 tRPC routers
- 里程碑版本 · v0.2.1(5/21 发布;之后未再打 tag,算技术债)
- CI/CD · 暂无 GitHub Actions · merge → 本地 npm run build && systemctl restart 手动部署
- 跨机部署 · DEPLOY.md 已写完(5/31)· subagent dry-run 验证 A 级 · 另一台机器部署 500 排障未完
未结清债务(按优先级)
- P0部署机 500 根因未定位(缺 journalctl 日志,等回包)
- P0没有自动备份策略(DB 改动前手动 pg_dump 是铁律,但没自动化)
- P0没有 CI(test / lint / typecheck 都在本地跑,依赖人)
- P1/m/* 手机端跟桌面端 UI 双套(~2800 行重复),REFACTOR_PLAN.md 已有未执行
- P1v0.2.1 之后没打 tag,发版规范断了
- P1chat 路由 / 任务详情仍有少量 N+1 风险(PR #35/#36/#39 砍了一批,有死角)
- P2没有 Sentry / 错误聚合,前端报错只在浏览器 console
- P2Snapshot 模板 AI probe 偶发漏字段(envHints),需要人工补
- P2健康分定义稳定了,但还没做"按 owner / 按时间段"维度筛选