AI AGENT SKILLS

飞书文档权限自动添加

一个面向 Automation 场景的 Agent 技能。原始说明:自动为飞书文档添加用户权限。每次创建飞书文档(多维表格/文档/电子表格/文件夹/云空间文件/知识库节点等)后自动添加用户权限,或用户反馈文档无权限时补充添加权限。适用于 OpenClaw Agent。

SKILL.md

SKILL.md


name: openclaw-feishu-docs-perm-auto
description: 自动为飞书文档添加用户权限。每次创建飞书文档(多维表格/文档/电子表格/文件夹/云空间文件/知识库节点等)后自动添加用户权限,或用户反馈文档无权限时补充添加权限。适用于 OpenClaw Agent。
license: MIT
metadata:
openclaw:
emoji: 🔐
author: sadjjk
version: "1.0.0"


飞书文档权限自动添加

🎯 一句话总结:飞书应用创建的文档,用户默认无权限。这个 skill 帮你自动添加权限。


前置条件

| 条件 | 说明 |
|------|------|
| 飞书开发者账号 | 需要有飞书开放平台的开发者权限 |
| 企业自建应用 | 已创建或有权创建飞书应用 |
| 应用权限 | 应用需开通 docs:permission.member:create 权限 |


变量速查表

| 变量名 | 来源 | 用途 |
|--------|------|------|
| $APP_ID | 配置文件 channels.feishu.appId | 应用标识 |
| $APP_SECRET | 配置文件 channels.feishu.appSecret | 应用密钥 |
| $OWNER_OPEN_ID | 配置文件或会话上下文 | 权限接收者 |
| $TENANT_TOKEN | API 获取 | 请求鉴权 |
| $FILE_TOKEN | 创建返回或 URL 解析 | 文档标识 |
| $DOC_TYPE | URL 路径识别 | 文档类型 |


第一步:检查配置 ⚠️

1.1 读取配置文件

配置文件位置:~/.openclaw/openclaw.json

1.2 检查必需字段

channels.feishu 下查找:

| 字段名 | 说明 | 示例值 | 必需性 |
|--------|------|--------|--------|
| appId | 飞书应用 ID | cli_xxxxxxxx | ✅ 必需 |
| appSecret | 飞书应用密钥 | xxxxxxxx | ✅ 必需 |
| ownerOpenId | 用户的 open_id | ou_xxx | ⚪ 可选* |

*ownerOpenId 在配置文件中可选,但执行时必须有值。若配置文件缺失,从会话上下文提取(格式 user:ou_xxxou_xxx)。

配置示例:

{
  "channels": {
    "feishu": {
      "enabled": true,
      "appId": "cli_xxxxxxxx",
      "appSecret": "xxxxxxxx",
      "ownerOpenId": "ou_xxx"
    }
  }
}

1.3 检查应用权限

使用 feishu_app_scopes() 查询当前飞书应用已开通的权限列表。

检查返回结果中是否包含 docs:permission.member:create

💡 如检查出有权限,后续可跳过此步骤。

1.4 判断逻辑

根据检查结果,按以下流程处理:

┌─────────────────────────────────────────────────────────┐
│  检查 appId + appSecret                                 │
│     ├─ ❌ 缺失 → [配置引导流程 A]                        │
│     └─ ✅ 完整 ↓                                        │
│  检查应用权限 docs:permission.member:create              │
│     ├─ ❌ 缺失 → [配置引导流程 C]                        │
│     └─ ✅ 完整 ↓                                        │
│  检查 ownerOpenId                                       │
│     ├─ ✅ 配置文件有 → 进入第二步                        │
│     ├─ ✅ 会话上下文有 → 提取使用,进入第二步             │
│     └─ ❌ 都没有 → [配置引导流程 B]                      │
└─────────────────────────────────────────────────────────┘

工具调用映射 🛠️

明确每个步骤应使用的工具,确保 Agent 能正确执行

| 步骤 | 操作 | 工具 | 说明 |
|------|------|------|------|
| 1.1 | 读取配置文件 | read | 读取 ~/.openclaw/openclaw.json |
| 1.3 | 检查应用权限 | feishu_app_scopes | 查询已开通权限列表 |
| 2.2 | 获取 tenantaccesstoken | exec | 执行 curl 命令请求 API |
| 2.3 | 解析文档 token | 内置逻辑 | 从 URL 或返回值中提取 |
| 2.4 | 添加用户权限 | exec | 执行 curl 命令请求 API |
| 配置写入 | 保存 ownerOpenId | edit | 更新 openclaw.json |

工具调用示例

# 读取配置文件
read("~/.openclaw/openclaw.json")

# 检查应用权限
feishu_app_scopes()

# 获取 tenant_access_token
exec('curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" ...')

# 添加权限
exec('curl -s -X POST "https://open.feishu.cn/open-apis/drive/v1/permissions/..." ...')

# 保存配置
edit("~/.openclaw/openclaw.json", oldText, newText)

第二步:执行权限添加 📋

前置条件:第一步检查全部通过

2.1 读取配置

工具read

APP_ID="读取到的appId"
APP_SECRET="读取到的appSecret"
OWNER_OPEN_ID="读取到的ownerOpenId"

2.2 获取 tenantaccesstoken

工具exec

进度提示[1/4] 获取访问令牌...

请求

curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
  -H "Content-Type: application/json" \
  -d "{
    \"app_id\": \"$APP_ID\",
    \"app_secret\": \"$APP_SECRET\"
  }"

成功返回

{
  "code": 0,
  "msg": "ok",
  "tenant_access_token": "xxxx",
  "expire": 5535
}

失败返回

{
  "code": 10003,
  "msg": "app id or app secret is invalid"
}

处理

  • ✅ 成功:提取 tenant_access_token,继续下一步
  • ❌ 失败:提示用户检查 App ID 和 App Secret 是否正确

token 缓存策略

| token 类型 | 有效期 | 缓存建议 |
|-----------|--------|----------|
| tenant_access_token | 约 2 小时 | 缓存至会话变量,过期前 5 分钟刷新 |

缓存实现

  • 使用会话级变量存储:CACHED_TENANT_TOKEN, TOKEN_EXPIRE_TIME
  • 每次请求前检查:若 now < TOKEN_EXPIRE_TIME - 300,直接使用缓存

2.3 获取云文档 token

进度提示[2/4] 解析文档 token...

来源

  1. 创建飞书文档后返回的 token 或文档 URL
  2. 从用户提供的文档链接解析

URL 解析规则

| 文档类型 | URL 示例 |
|----------|----------|
| 文件夹 | https://xxx.feishu.cn/drive/folder/【token】 |
| 文件 | https://xxx.feishu.cn/file/【token】 |
| 旧版文档 | https://xxx.feishu.cn/docs/【token】 |
| 新版文档 | https://xxx.feishu.cn/docx/【token】 |
| 电子表格 | https://xxx.feishu.cn/【token】 |
| 多维表格 | https://xxx.feishu.cn/base/【token】 |
| 知识空间 | https://xxx.feishu.cn/wiki/settings/【token】 |
| 知识库节点 | https://xxx.feishu.cn/wiki/【token】 |

⚠️ 复制 URL 时注意删除末尾多余的 # 符号。

自动识别 doc_type

| URL 路径特征 | doc_type |
|-------------|----------|
| /drive/folder/ | folder |
| /file/ | file |
| /docs/ | doc |
| /docx/ | docx |
| /base/ | bitable |
| /wiki/ | wiki |
| 其他(根路径) | sheet |

识别逻辑

  1. 从 URL 提取 token(最后一个路径段,去除 ?# 后的内容)
  2. 根据 URL 路径匹配 doc_type
  3. 若无法匹配,提示用户提供文档类型

变量定义

  • FILE_TOKEN = 获取到的云文档 token
  • DOC_TYPE = 识别到的文档类型

2.4 添加用户权限

工具exec

进度提示[3/4] 添加用户权限...

请求

curl -s -X POST "https://open.feishu.cn/open-apis/drive/v1/permissions/{FILE_TOKEN}/members/batch_create?type={DOC_TYPE}" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {tenant_access_token}" \
  -d "{
    \"members\": [{
      \"member_type\": \"openid\",
      \"member_id\": \"$OWNER_OPEN_ID\",
      \"perm\": \"full_access\"
    }]
  }"

参数说明

| 参数 | 来源 | 示例 |
|------|------|------|
| {FILE_TOKEN} | 创建文档时返回或 URL 解析 | xxxxx |
| {DOC_TYPE} | URL 路径自动识别 | bitable |
| {tenant_access_token} | 上一步获取 | t-xxx |
| $OWNER_OPEN_ID | ownerOpenId | ou_xxx |

doc_type 可选值

| 值 | 文档类型 |
|----|----------|
| bitable | 多维表格 |
| docx | 新版文档 |
| doc | 旧版文档 |
| sheet | 电子表格 |
| folder | 文件夹 |
| file | 云空间文件 |
| wiki | 知识库节点 |

成功返回

{
  "code": 0,
  "msg": "Success",
  "data": {
    "members": [{
      "member_id": "xxxx",
      "member_type": "openid",
      "perm": "full_access"
    }]
  }
}

2.5 执行结果反馈

进度提示[4/4] 完成!

成功时

✅ 权限添加成功!

📄 文档:{文档标题或 token}
🔗 链接:{文档 URL}
👤 权限:完整权限 (full_access)
你现在可以直接访问和编辑这个文档了。
如果配置文件中没有ownerOpenId 并询问 是否需要将 ownerOpenId 写入配置文件中

失败时

❌ 权限添加失败

原因:{错误信息}
解决方案:{具体步骤}

需要帮助?请提供以上信息。

使用示例 📝

示例 1:创建多维表格后自动添加权限

用户:帮我创建一个多维表格叫「项目进度追踪」

Agent 执行流程

[1/3] 创建多维表格...
      → 调用 feishu_bitable_create_app(name="项目进度追踪")
      → 返回 app_token: "bascnxxx"

[2/3] 添加用户权限...
      → 触发 feishu-perm-auto skill
      → 检查配置:appId ✓ appSecret ✓ ownerOpenId ✓
      → 获取 tenant_access_token
      → 调用权限 API 添加 full_access

[3/3] 完成!

Agent 回复

✅ 多维表格「项目进度追踪」已创建!

🔗 链接:https://xxx.feishu.cn/base/bascnxxx
🔐 已自动为你添加完整权限,可直接访问和编辑

示例 2:用户反馈文档无权限

用户:这个文档我打不开,提示没权限 https://xxx.feishu.cn/docx/doxcnxxx

Agent 执行流程

[1/3] 解析文档信息...
      → URL 解析:token=doxcnxxx, doc_type=docx

[2/3] 检查配置并添加权限...
      → 检查配置:appId ✓ appSecret ✓ ownerOpenId ✓
      → 获取 tenant_access_token
      → 调用权限 API 添加 full_access

[3/3] 完成!

Agent 回复

✅ 权限添加成功!

📄 文档:doxcnxxx
🔗 链接:https://xxx.feishu.cn/docx/doxcnxxx
👤 权限:完整权限 (full_access)

你现在可以直接访问和编辑这个文档了。

示例 3:首次使用,配置缺失

用户:帮我创建一个飞书文档

Agent 执行流程

[1/2] 检查配置...
      → 读取 ~/.openclaw/openclaw.json
      → 发现 channels.feishu.appId 缺失

[2/2] 引导配置...

Agent 回复

⚠️ 还没配置飞书应用凭证,需要先设置一下:

📱 获取飞书应用凭证:

1. 打开浏览器,访问:https://open.feishu.cn/app
2. 登录你的飞书账号
3. 点击「创建企业自建应用」或选择已有应用
4. 在左侧菜单找到「凭证与基础信息」
5. 复制以下内容:
   - App ID(cli_ 开头的字符串)
   - App Secret(点击「查看」后显示)

请把 App ID 和 App Secret 发给我,格式如下:
appId: cli_xxxxxxxx
appSecret: xxxxxxxx

用户回复后

用户:appId: cli_aabbccdd
      appSecret: 1234567890abcdef

Agent:
[1/2] 验证凭证...
      → 获取 tenant_access_token 成功 ✓

[2/2] 保存配置...
      → 更新 ~/.openclaw/openclaw.json

Agent 回复

✅ 飞书应用配置成功!

现在可以正常使用飞书功能了。需要我帮你创建文档吗?

示例 4:权限已存在(幂等处理)

用户:给这个文档加权限 https://xxx.feishu.cn/base/bascnxxx

Agent 执行流程

[1/3] 解析文档信息...
      → token=bascnxxx, doc_type=bitable

[2/3] 添加权限...
      → 调用 API 返回错误码 99991661(成员已存在)

[3/3] 幂等处理...
      → 视为成功,无需重复添加

Agent 回复

✅ 权限已存在!

📄 文档:bascnxxx
🔗 链接:https://xxx.feishu.cn/base/bascnxxx
👤 权限:完整权限 (full_access)

你已经有这个文档的完整权限了。

配置引导流程 🔧

当第一步检查发现配置缺失时,按以下流程引导用户配置。

A. 获取 App ID 和 App Secret

📱 获取飞书应用凭证:

1. 打开浏览器,访问:https://open.feishu.cn/app
2. 登录你的飞书账号
3. 点击「创建企业自建应用」或选择已有应用
4. 在左侧菜单找到「凭证与基础信息」
5. 复制以下内容:
   - App ID(cli_ 开头的字符串)
   - App Secret(点击「查看」后显示)

请把 App ID 和 App Secret 发给我,格式如下:
appId: cli_xxxxxxxx
appSecret: xxxxxxxx

B. 获取 ownerOpenId

优先从会话上下文提取:若上下文中出现 user:ou_xxx 格式,直接提取 ou_xxx 使用。

否则引导用户获取

  1. 登录 API 调试台,找到发送消息接口
  2. 在「查询参数」页签,将 user_id_type 设置为 open_id
  3. 点击「快速复制 open_id」

详见:https://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid

用户回复后

  1. 验证格式是否正确(以 ou_ 开头)
  2. 在当前会话中使用此 ownerOpenId

C. 配置应用权限

⚠️ 在使用前,还需要给应用添加权限:

1. 在飞书开放平台,点击左侧「权限管理」
2. 搜索并开通以下权限:
   - docs:permission.member:create (添加云文档协作者)

3. 点击「发布版本」使权限生效

如果权限显示「待确认」,需要联系企业管理员审批。

权限级别说明 🔐

| 权限值 | 中文名 | 能做什么 | 适用场景 |
|--------|--------|----------|----------|
| view | 只读 | 只能查看,不能修改 | 分享给他人查看 |
| edit | 可编辑 | 可以修改内容,不能管理权限 | 协作编辑 |
| full_access | 完整权限 | 可以编辑、管理权限、删除 | 文档所有者(推荐) |

💡 建议:给用户添加 full_access 权限,这样用户可以完全控制文档。

权限选择建议

| 场景 | 推荐权限 | 原因 |
|------|----------|------|
| 用户自己的文档 | full_access | 完全控制 |
| 协作编辑 | edit | 避免误删 |
| 只读分享 | view | 安全最小化 |

💡 默认使用 full_access,但可在执行时询问用户需求。


错误处理大全 ⚠️

| 错误码 | 错误信息 | 原因 | 解决方案 | 处理动作 |
|--------|---------|------|----------|----------|
| 10003 | app id or app secret is invalid | App ID 或 App Secret 错误 | 检查配置,确保复制正确 | 重新配置后重试 |
| 99991661 | 成员已存在 | 用户已有权限 | 视为成功,无需处理 | 直接返回成功 |
| 99991663 | Invalid access token | token 过期或无效 | 重新获取 tenantaccesstoken | 重新执行 2.2 |
| 99991664 | Permission denied | 应用没有权限 | 引导配置应用权限 | 跳转配置引导 C |
| 99991600 | token not found | 文档 token 不存在 | 检查 file_token 是否正确 | 确认后重试 |


最佳实践 💡

配置管理

  • ✅ 首次使用时引导用户配置
  • ✅ 配置保存后,后续自动读取
  • ⚠️ 不要在日志中输出 App Secret

错误处理

  • ✅ 每一步都要检查返回的 code
  • ✅ 失败时给出清晰的错误原因
  • ✅ 提供具体的解决方案和处理动作

用户体验

  • ✅ 每步输出进度提示 [1/4] [2/4] [3/4] [4/4]
  • ✅ 成功后返回文档链接
  • ✅ 告诉用户权限已添加
  • ✅ 提示用户可以直接访问
  • ✅ 成功后询问用户是否需要将 ownerOpenId 写入配置文件

安全考虑

  • ⚠️ App Secret 不要硬编码在 skill 中
  • ⚠️ 不要在回复中显示完整的 App Secret(只显示前4位 + ***
  • ⚠️ token 有效期约 2 小时,建议缓存避免频繁请求

敏感信息脱敏

| 信息类型 | 原始值 | 脱敏后 |
|---------|--------|--------|
| App Secret | abc123xyz789 | abc1*** |
| tenantaccesstoken | t-xxx123456 | t-xxx*** |
| ownerOpenId | ou_abc123 | ou_abc*** |

脱敏实现

def mask_secret(s, show=4):
    return s[:show] + '***' if len(s) > show else '***'

相关链接 📎

| 资源 | 链接 |
|------|------|
| 飞书开放平台 | https://open.feishu.cn/app |
| 权限配置指南 | https://open.feishu.cn/document/docs/permission/permission-member/batch_create |
| 获取 Open ID | https://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid |


快速参考卡片 📌

┌─────────────────────────────────────────────────────────┐
│  飞书权限添加快速参考                                    │
├─────────────────────────────────────────────────────────┤
│  1. 检查配置:~/.openclaw/openclaw.json                 │
│     - appId (必需)                                      │
│     - appSecret (必需)                                  │
│     - ownerOpenId (可选,会话上下文补充)                  │
│     - 应用权限: docs:permission.member:create (必需)     │
├─────────────────────────────────────────────────────────┤
│  2. 获取 tenant_access_token:                           │
│     POST /auth/v3/tenant_access_token/internal          │
│     Body: {app_id, app_secret}                          │
├─────────────────────────────────────────────────────────┤
│  3. 获取云文档 token:                                   │
│     创建时返回 或 从 URL 解析                            │
│     自动识别 doc_type: /base/→bitable, /docx/→docx...   │
├─────────────────────────────────────────────────────────┤
│  4. 添加权限:                                          │
│     POST /drive/v1/permissions/{token}/members          │
│     Header: Authorization: Bearer {token}               │
│     Body: {members: [{member_type, member_id, perm}]}   │
├─────────────────────────────────────────────────────────┤
│  文档类型:                                             │
│    bitable | docx | doc | sheet | folder | file | wiki │
│  权限级别:view | edit | full_access                    │
└─────────────────────────────────────────────────────────┘