All Tags
On this page

AI 帮我盯飞书、修 Bug,我负责喝咖啡:DM-Watch 搭建全拆解

#frontend #AI #skills #cursor #agent #claudecode
avatar
jerrywu001
创建时间:2026-06-23 06:06:46

同事在飞书私信问我问题,我人不在电脑前,AI 自动帮我读消息、改代码、回复对方。TAPD 派了 Bug 给我,AI 自动去看描述、找到出问题的代码、修完提交。

我知道这听起来像吹牛。但这套东西我确实每天在用,而且踩了一堆坑才跑稳。


这套东西长什么样

两个后台监听,一键启动:

监听 干什么
DM-Watch(飞书私信) 盯着指定同事发给我的私信,Claude 自动分诊处理,能答的答,能改的改,以我的名义回复对方
TAPD-Watch(Bug 派单) 盯着派给我的 new/reopened Bug,Claude 拉详情、定位代码、修、提交、标已解决

脚本负责"盯"和"喊",Claude 负责干活。脚本每隔几秒轮询飞书 API 或 TAPD API,发现新消息就往终端吐一行事件,比如 DM-NEW name=李四 count=1。Claude Code 的 Monitor 接住这行事件,开始分析消息、决定怎么处理。

我可以完全不看电脑。

DM-Watch 整体流程


搭建过程

需要装什么

组件 干什么 怎么装
Claude Code AI 大脑 Anthropic 官方 CLI
lark-cli 飞书命令行,拉消息发消息 装好后 lark-cli auth login 登你的飞书号
jq JSON 解析,脚本里大量用 brew install jq
TAPD Access Token 调 TAPD API TAPD 个人设置里生成
GitLab PAT(可选) 查 CI 流水线 GitLab 个人设置 → Access Tokens

文件就一个文件夹

放在 ~/.claude/skills/dm-watch/,里面这些东西:

├── SKILL.md              ← 告诉 Claude 怎么处理事件的"操作手册"
├── config.json           ← 你的配置(监听谁、TAPD 项目等)
├── config.example.json   ← 配置模板
├── monitor-loop.sh       ← 飞书私信轮询脚本
├── tapd-watch.shTAPD Bug 轮询脚本
├── ci-watch.shCI 失败监听(可选)
├── .seen-ou_xxx.txt      ← 每个监听对象的"已读水位线"
├── .tapd-notified.txt    ← 已通知过的 Bug ID
└── pending-ou_xxx.json   ← 待处理的新消息

填配置

config.example.json 复制成 config.json,填四样东西:

{
  "selfOpenId": "ou_你自己的飞书open_id",

  "watched": [
    { "name": "张三", "openId": "ou_张三的open_id" },
    { "name": "李四", "openId": "ou_李四的open_id" }
  ],

  "botChat": {
    "chatId": "xxx",
    "name": "my-bug-agent"
  },

  "tapd": {
    "workspaceId": "44192340",
    "ownerName": "你在TAPD的显示名"
  },

  "gitlab": {
    "host": "gitlab.your-company.cn",
    "projectPaths": [
      "your-org/app/mobile-app",
      "your-org/web/admin-panel",
      "your-org/system/backend-service"
    ],
    "projectDescriptions": {
      "your-org/app/mobile-app": "移动端前端项目",
      "your-org/web/admin-panel": "管理后台前端项目",
      "your-org/system/backend-service": "后端服务项目"
    },
    "projectLocalPaths": {
      "your-org/app/mobile-app": "/Users/你的用户名/projects/mobile-app",
      "your-org/web/admin-panel": "/Users/你的用户名/projects/admin-panel",
      "your-org/system/backend-service": "/Users/你的用户名/projects/backend-service"
    }
  },

  "quietHours": { "start": 23, "end": 8 },
  "pollSeconds": { "dm": 10, "tapd": 180 }
}

逐个说一下:

  • watched 是你要监听谁的私信。open_id 用这个命令查:lark-cli contact +search-user --as user --queries '张三' --has-chatted

  • tapd.workspaceId 是 TAPD 项目 ID。打开 TAPD 任意项目页面看地址栏,https://www.tapd.cn/44192340/... 里的那串数字就是。ownerName 填你在 TAPD 上的显示名,脚本按这个名字筛"派给我的 Bug"。

  • botChat 是需要监听的飞书机器人。通过:飞书机器人 创建一个机器人,填 chatIdnameconfig.json

  • gitlab 支持多项目。projectPaths 是 GitLab 项目路径数组,projectDescriptions 给每个项目加一句中文描述方便 Claude 判断消息该归哪个仓库,projectLocalPaths 是对应的本地目录。收到同事消息时,如果 Claude 拿不准该改哪个项目,会先飞书列出选项问你再动手。

  • quietHours 是深夜不轮询的时段。pollSeconds.dm 设 10 秒是因为聊天要快,pollSeconds.tapd 设 3 分钟是因为 Bug 不急这几分钟。

  • TAPD 的 Access Token 不放 config.json 里,放在 ~/.claude.json 的 MCP 配置中:

{
  "mcpServers": {
    "tapd": {
      "env": {
        "TAPD_ACCESS_TOKEN": "你的token"
      }
    }
  }
}

Token 在这里生成:https://www.tapd.cn/personal_settings/index?tab=personal_token 。tapd-watch.sh 启动时从 ~/.claude.json 读这个值,读不到直接报错退出。

tapd-token

两个脚本在干什么

monitor-loop.sh

伪代码:

死循环:
    如果深夜 → 睡 5 分钟,跳过

    遍历每个被监听的人:
        调 lark-cli 拉最近 50 条私信
        过滤掉自己发的
        和 .seen 文件比对
        有新消息 → 写 pending json + 吐事件行 + 更新 seen

    睡 N

首次启动时,脚本会把当前所有消息 ID 直接写进 .seen 文件,不处理任何历史消息。这个必须有,否则一启动就回放过去所有聊天记录,Claude 试图回复几十条历史消息,场面很难看。

已读水位线用 message_id 集合(平面文本,一行一个 ID),不用时间戳。消息乱序到达也不会漏。文件超 200 行自动裁剪。

tapd-watch.sh

启动先鉴权探测(limit=1 请求)
token 无效 → 报错退出

死循环:TAPD API "派给我的 new/reopened Bug"
    遍历每个 Bug:
        bug_id:status 没通知过 → 吐事件行 + 记录

    睡 3 分钟

去重用 bug_id:status 做 key。同一个 Bug 从 new 变成 reopened 会再次触发(key 变了),同状态不重复。

SKILL.md:Claude 的操作手册

脚本只管发现事件。怎么处理,写在 SKILL.md 里。这个文件是给 Claude 看的,定义了收到不同事件后的处理流程:

收到 DM-NEW:读 pending json → 分诊(问题?Bug?需求?)→ 执行 → 飞书回复对方 → 飞书通知我。

收到 TAPD-BUG:调 TAPD API 拉 Bug 详情 → 分析定位 → 修代码 → 提交 → 更新 Bug 状态 → 飞书通知我。

SKILL.md 里写得最醒目的一条规则:

用户不看终端,飞书是唯一通道。

这条是被我反复纠正后才定下来的。Claude 一开始总把确认问题写在终端里,我根本看不到。后来加了一句自检口诀:"写终端之前先问自己——这条飞书发了没有?"

一键启动

Claude Code 里输入 /dm-watch,Claude 检查配置和凭证,启动两个 Monitor 后台任务,报告状态。之后去忙别的就行。


实际在用的几个场景

同事发消息说改接口

后端同事在飞书私聊发了一张截图加一段话:"原来批量接口现在改单个接口,改下对应的前端调用"。

我当时在开会。10 秒后 monitor-loop.sh 发现新消息,Claude 读了 pending json,判断这是接口变更需求,找到前端调用点,改了 API 调用方式,飞书回复对方"已改完,批量接口调用改为单个调用",飞书通知我"后端同事说要改接口,已处理"。

等我开完会打开飞书,事情已经办完了。

application

TAPD 派了 Bug

有人提了个 Bug:"订单详情页,标签显示异常,每个标签独占一整行"。

tapd-watch.sh 3 分钟内发现,Claude 拉 Bug 描述,分析出标签组件用了错误的布局方式导致排版异常,改成正确的换行布局,提交代码,等 CI 过了,更新 TAPD 状态为已解决并加评论,飞书通知我。

auto-fix-bug

同事问技术问题

有时候同事不是报 Bug,就是问"那个接口入参格式是什么"或者"那个页面路由路径是多少"。Claude 在项目代码里搜到答案后,以我的飞书身份回复对方,同时通知我"xxx 问了这个问题,我这样回复的"。

lark-cli im +messages-send --as user 是以我的身份发消息,对方看到的就是"我"在回复。

需要我拍板的事

不是所有事 Claude 都能自己定。涉及后端改动要我确认,修复方案有多种要我选,需求描述不清楚要不要问回去。

Claude 会飞书问我。然后通过 DM-Watch 监听我的回复,我在飞书里回一句"用方案一",Claude 收到后继续干。

这是个闭环:监听别人消息 → Claude 处理 → 不确定的飞书问我 → 监听我的回复 → 继续。

confirm

整理需求

后端同事有时在飞书里丢一大段需求描述,比如"列表接口联调改动,请求体新增 xxx 字段"洋洋洒洒几百字。Claude 读完之后飞书给我发一份精炼的分析:需要改哪些文件、涉及哪些接口。我回一句"改吧"就直接开始。


踩过的坑

终端写了一堆,飞书没发。 早期最大的问题。Claude 处理完事情在终端写一大段总结,我根本不看终端。纠正了两次之后把"飞书铁律"写进 SKILL.md 最醒目的位置。

首次启动回放历史消息。 第一版脚本没做水位线种子,启动后把过去所有聊天记录全当新消息,Claude 一口气试图回复几十条。加了首次种子逻辑才消停。

自己发的消息触发了自己。 没过滤发送者。我回复别人的消息也被当成"新消息"反复触发。加了 selfOpenId 和 sender 过滤。

Claude 直接改了后端代码。 收到同事说后端有 Bug,Claude 改了代码直接提交了。后端改动影响面太大,从此定了铁律:后端必须先飞书问我确认再动手,前端不限制。

lark-cli token 过期没人知道。 飞书 user token 大约一周过期,过期后脚本默默地什么都拉不到。加了静默失败检测:连续 3 轮全部请求失败就吐 DM-WATCH-AUTH-LOST,Claude 提醒我重新登录。


整体怎么串起来的

┌───────────────────────────────────────────┐
│              Claude Code 会话              │
│                                            │
│  monitor-loop.sh        tapd-watch.sh  (10秒轮询飞书)          (3分钟轮询TAPD)    │
│       │                       │            │
│   DM-NEW ...             TAPD-BUG ...      │
│       │                       │            │
│       └──────────┬────────────┘            │
│                  ▼                         │
│            Claude 接住事件                  │
│            读消息 / 拉Bug详情               │
│            分诊 → 执行 → 回复               │
│                  │                         │
│          lark-cli 发飞书                    │
│          git commit/push                   │
└──────────────────┼─────────────────────────┘
                   ▼
          飞书(回复+通知)
          GitLab(代码仓库)

一句话:脚本轮询 → 吐事件 → Claude 接住 → 分诊执行 → 飞书闭环。


给同事用

这个文件夹可以直接拷给别人。装 lark-cli 登自己飞书号,复制 config.example.json 填自己的值,在 Claude Code 里敲 /dm-watch 就能跑。

想加监听的人也不用手动改 config.json,直接在 Claude Code 里说"帮我监听张三"就行,Claude 会自动查 open_id、更新配置、重启监听。

不需要飞书机器人,不需要服务器,不需要数据库。

有一个限制:Claude Code 会话开着才活。电脑睡了或者会话关了,监听就停了。7x24 无人值守要做成独立服务,目前工作时间段用够了。


为什么搞这个

飞书一会儿弹一个消息,TAPD 一会儿派一个 Bug,每次被打断都要几分钟恢复上下文。同事问的很多问题查一下代码就知道答案,不需要我亲自处理。

DM-Watch 把"被打断"变成"被代理"。同事照样得到及时回复,Bug 照样被修,但我的时间没有被切碎。遇到真正需要我判断的事,飞书通知加回环确保不会漏掉。

从第一行脚本到跑稳,迭代了十几个版本。去重、水位线、静默期、auth 过期检测全是踩坑后补的。如果你也想搞一套,先跑最小版本再说——一个 watched 对象加一个轮询脚本,能跑了再往上加。