agentleFS
castle-xcastle-x/skills-x/skills/feishu-notify/SKILL.md

feishu-notify

Skill18 starsChanged 7 months agoMITView on GitHub

帮助用户将飞书群机器人 Webhook 通知接入 Claude Code,使得每次任务完成后自动发送飞书消息卡片通知。

  • Installs packages
  • Sends data out

5 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use figure-spec, figure-description and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • raja21068Skill

    figure-spec

    Generate deterministic publication-quality architecture, workflow, and pipeline diagrams from structured JSON (FigureSpec) into editable SVG. Use when user says \"架构图\", \"workflow 图\", \"pipeline 图\", \"确定性矢量图\", \"figure spec\", \"draw architecture\", or needs precise, editable, publication-ready vector diagrams. Preferred over AI illustration for formal architecture/workflow figures.

    Also in 3 projects that use this

  • raja21068Skill

    figure-description

    Process user-provided patent figures and generate formal drawing descriptions. Use when user says \"附图处理\", \"figure description\", \"附图说明\", \"drawings description\", or wants to describe patent figures with reference numerals.

    Also in 3 projects that use this

  • gsooskSkill

    overleaf-sync

    This skill should be used when the user wants Claude to write, edit, or co-author LaTeX files on an Overleaf project. Triggers on phrases like "edit my Overleaf paper", "write the introduction for my paper", "help me write my LaTeX paper", "co-author my Overleaf project", "I want you to edit my tex files", or any request to write/modify content in a paper that lives on Overleaf. Claude handles all git pull/push/sync automatically — the user only needs to provide the repo and describe what they want written.

    Also in 3 projects that use this

  • rongaredeSkill

    semantic-scholar

    使用 Semantic Scholar API 检索和验证学术论文。支持并发多关键词搜索、批量 ID/DOI 查询、引用分析、批量补全摘要、统一 Markdown 导出。覆盖 2.14 亿+ 学术论文,无需 API Key 即可使用。触发词:论文检索、论文验证、Semantic Scholar、S2 搜索、查论文、补全摘要、导出MD

    Also in 3 projects that use this

  • Mathews-TomSkill

    citation-audit

    Verify that every citation in a manuscript is real, correctly attributed, and accurately described. Detects ghost papers, wrong arXiv IDs, inverted claims, and dead links by fetching each cited work. Optional fix mode applies bib metadata corrections and surfaces prose rewrites for claim errors. Triggers on: "check my citations", "verify references", "citation audit", "are my references real", "check bib", "reference check", "bib audit", "citation verification". Companion to manuscript-review (Pass 5 hygiene); this skill audits factual truth.

    Also in 3 projects that use this

  • mjunaidcaSkill

    mermaid-diagram

    Generate Mermaid diagrams for educational content. Use when visualizing concepts, architectures, or workflows.

    Also in 3 projects that use this

  • +6 more from raja21068

The file

Files
SKILL.md

Feishu Notify — Claude Code 飞书通知 Skill

每当 Claude Code 完成任务(触发 Stop Hook)时,自动向飞书群发送一条消息卡片通知,内容包含会话 ID、完成时间、停止原因、最后使用的工具、工作目录、主机名、系统运行时间,以及 Claude 最后一条回复的摘要(前 300 字符)。


执行流程

Step 1:引导用户获取飞书群机器人 Webhook 地址

首先询问用户是否已有飞书群机器人 Webhook 地址。如果没有,引导用户按以下步骤操作:

1. 打开飞书,进入任意群组(或新建一个专用的「Claude 通知」群)
2. 点击右上角「群设置」图标 → 「群机器人」→ 「添加机器人」
3. 选择「自定义机器人」
4. 填写机器人名称(如:Claude Code 助手)
5. 点击「添加」,复制生成的 Webhook 地址
   格式示例:https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

获取到 Webhook 地址后,继续执行 Step 2。


Step 2:创建目录并写入通知脚本

创建 ~/.claude/ 目录,并将以下脚本写入 ~/.claude/notify-feishu.sh。

将脚本中的 __WEBHOOK_URL__ 替换为用户提供的真实 Webhook 地址。

#!/usr/bin/env bash
# 飞书通知脚本 - Claude Code Stop Hook
# 保存路径:~/.claude/notify-feishu.sh

WEBHOOK_URL="__WEBHOOK_URL__"

# 从 stdin 读取 Claude Code Hook 传入的 JSON
INPUT=$(cat)

# 提取 Hook 字段
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
STOP_HOOK_REASON=$(echo "$INPUT" | jq -r '.stop_hook_reason // empty')
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')

# 提取环境信息
HOSTNAME=$(hostname 2>/dev/null || echo "unknown")
WORK_DIR=$(pwd)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
UPTIME=$(uptime -p 2>/dev/null || uptime | sed 's/.*up/up/')

SHORT_SESSION="${SESSION_ID:0:12}"

# 提取最后一条 assistant 文本回复(截取前 300 字符)
LAST_REPLY=""
if [[ -n "$TRANSCRIPT_PATH" && -f "$TRANSCRIPT_PATH" ]]; then
  LAST_REPLY=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" \
    | while IFS= read -r line; do
        echo "$line" | jq -r '
          select(.message.content[]?.type == "text")
          | [.message.content[] | select(.type == "text") | .text]
          | join("")' 2>/dev/null
      done \
    | tail -1 \
    | cut -c1-300)
  ORIGINAL_LEN=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" \
    | while IFS= read -r line; do
        echo "$line" | jq -r '
          select(.message.content[]?.type == "text")
          | [.message.content[] | select(.type == "text") | .text]
          | join("")' 2>/dev/null
      done | tail -1 | wc -c)
  [[ "$ORIGINAL_LEN" -gt 300 ]] && LAST_REPLY="${LAST_REPLY}..."
fi

# ⚠️ 关键:用数组 + printf '%s\n' 产生真实换行符
# 不能用 "\n" 字符串拼接,否则飞书会渲染为字面 \n 而不是换行
LINES=()
LINES+=("📋 **会话 ID**:\`${SHORT_SESSION}...\`")
LINES+=("⏰ **完成时间**:${TIMESTAMP}")
[[ -n "$STOP_HOOK_REASON" ]] && LINES+=("📝 **停止原因**:${STOP_HOOK_REASON}")
[[ -n "$TOOL_NAME" ]] && LINES+=("🔧 **最后工具**:${TOOL_NAME}")
LINES+=("📂 **工作目录**:\`${WORK_DIR}\`")
LINES+=("🖥️ **主机名称**:${HOSTNAME}")
LINES+=("🔌 **系统运行**:${UPTIME}")
if [[ -n "$LAST_REPLY" ]]; then
  LINES+=("")
  LINES+=("💬 **最后回复**:")
  LINES+=("${LAST_REPLY}")
fi

# printf '%s\n' 将数组每个元素转为真实换行的多行字符串
MD_CONTENT=$(printf '%s\n' "${LINES[@]}")

# ⚠️ 关键:用 jq -n --arg 传入多行字符串,jq 会正确转义为合法 JSON
# 不能用 echo/printf 手动拼接 JSON,否则换行符会破坏 JSON 结构
CARD_JSON=$(jq -n \
  --arg md "$MD_CONTENT" \
  '{
    msg_type: "interactive",
    card: {
      schema: "2.0",
      config: { wide_screen_mode: true },
      header: {
        template: "green",
        title: { tag: "plain_text", content: "✅ Claude Code 任务完成" }
      },
      body: {
        elements: [{ tag: "markdown", content: $md }]
      }
    }
  }')

# 发送通知,静默失败不影响 Claude Code 正常运行
curl -s -X POST "$WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d "$CARD_JSON" \
  > /dev/null 2>&1 || true

执行以下命令创建目录并写入脚本(替换 <YOUR_WEBHOOK_URL> 为真实地址):

mkdir -p ~/.claude
# 写入脚本后赋予执行权限
chmod +x ~/.claude/notify-feishu.sh

Step 3:配置 Claude Code settings.json

配置文件路径:~/.claude/settings.json(全局生效,对所有项目有效)。

⚠️ 合并注意:如果该文件已存在,必须只追加 hooks.Stop 字段,不能覆盖文件中已有的其他配置(如 mcpServers、permissions 等)。

如果文件不存在,直接写入:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/notify-feishu.sh",
            "timeout": 15,
            "statusMessage": "发送飞书通知..."
          }
        ]
      }
    ]
  }
}

如果文件已存在,使用 jq 合并(安全方式,不丢失已有配置):

# 备份原文件
cp ~/.claude/settings.json ~/.claude/settings.json.bak

# 用 jq 合并,追加 Stop hook(不覆盖其他字段)
jq '.hooks.Stop += [{"hooks": [{"type": "command", "command": "bash ~/.claude/notify-feishu.sh", "timeout": 15, "statusMessage": "发送飞书通知..."}]}]' \
  ~/.claude/settings.json > /tmp/settings_merged.json \
  && mv /tmp/settings_merged.json ~/.claude/settings.json

Step 4:测试发送通知

写入配置后,立即发送一条测试通知,验证 Webhook 是否有效:

echo '{"session_id":"test-session-abcdefg","stop_hook_reason":"task_complete","tool_name":"Bash","transcript_path":""}' \
  | bash ~/.claude/notify-feishu.sh

如果飞书群收到一条绿色标题的消息卡片,则说明配置成功。

如果没有收到,检查:

  1. Webhook 地址是否正确粘贴(注意末尾不要有多余空格)
  2. jq 和 curl 是否已安装(which jq && which curl)
  3. 网络是否可以访问 open.feishu.cn

Step 5:向用户确认完成

配置完成后,告知用户:

✅ 飞书通知配置完成!

从现在起,每次 Claude Code 完成任务时,飞书群将自动收到通知卡片,包含:
- 会话 ID(前12位)
- 完成时间
- 停止原因
- 最后使用的工具
- 工作目录 / 主机名 / 系统运行时间
- Claude 最后一条回复摘要(前 300 字符)

配置文件位置:
- 通知脚本:~/.claude/notify-feishu.sh
- Hook 配置:~/.claude/settings.json

注意事项

⚠️ 换行符问题(最常见的坑)

飞书消息卡片的 Markdown 内容必须包含真实换行符(\n 字节),不能是字面字符串 \n。

正确做法:

# 1. 用数组收集每行内容
LINES=()
LINES+=("第一行内容")
LINES+=("第二行内容")

# 2. 用 printf '%s\n' 将数组转为真实多行字符串
MD_CONTENT=$(printf '%s\n' "${LINES[@]}")

# 3. 用 jq --arg 传入,jq 会将真实换行转义为合法 JSON 中的 \n
CARD_JSON=$(jq -n --arg md "$MD_CONTENT" '{ ..., content: $md }')

错误做法(会导致飞书渲染出字面 \n):

# ❌ 不要用字符串拼接
MD_CONTENT="第一行\n第二行"

# ❌ 不要手动拼接 JSON 字符串
CARD_JSON='{"content": "第一行\n第二行"}'

⚠️ settings.json 配置位置说明

位置路径作用范围
全局配置~/.claude/settings.json对所有项目生效(推荐)
项目配置.claude/settings.json(项目根目录)仅对当前项目生效

注意:Claude Code 官方全局配置路径可能因版本而异,也可能在 ~/.claude/settings.json。请以实际环境为准,通过 claude config 或文档确认。

⚠️ settings.json 合并方式

  • 不要直接覆盖已有的 settings.json
  • 使用 jq 合并,确保 mcpServers、permissions、其他 hooks 等已有配置不丢失
  • 合并前务必备份(.bak 文件)

⚠️ 脚本依赖

脚本依赖以下工具,配置前请确认已安装:

  • jq:JSON 处理(apt install jq / brew install jq)
  • curl:HTTP 请求(通常系统自带)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.