agentleFS
yangwhaleyangwhale/CloseCrab/skills/feishu-doc/SKILL.md

feishu-doc

Skill5 starsChanged 3 months agoApache-2.0View on GitHub

创建飞书文档(Feishu DocX)。当用户说"写个飞书文档"、"创建飞书文档"、"生成飞书doc"、"feishu doc"等关键词时触发。

7 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use deep-research.

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.
  • NVIDIASkill

    deep-research

    Queue deep, multi-step research and analysis tasks to the DeepAgents worker. Supports execution depth presets, request-specific rubrics, SubAgent delegation, and RubricMiddleware cross-validation.

    Also in 3 projects that use this

The file

Files
SKILL.md

飞书文档创建(Feishu DocX API)

通过飞书 DocX API 创建富格式文档,支持文本格式、标题、列表、表格、代码块、Callout、公式等全部原生能力。

触发条件

  • "写个飞书文档"、"创建飞书文档"
  • "生成飞书doc"、"feishu doc"
  • "写到飞书文档里"、"输出成飞书文档"

前置条件

  • 飞书 App 需要 docx:document 和 drive:drive 权限
  • 环境变量已配置:FEISHU_APP_ID_JARVIS / FEISHU_APP_SECRET_JARVIS(或对应 bot 的 env)

API 概览

1. 创建文档

import os, lark_oapi as lark
from lark_oapi.api.docx.v1 import *

client = lark.Client.builder() \
    .app_id(os.environ['FEISHU_APP_ID_JARVIS']) \
    .app_secret(os.environ['FEISHU_APP_SECRET_JARVIS']) \
    .domain(lark.FEISHU_DOMAIN).build()

req = CreateDocumentRequest.builder() \
    .request_body(CreateDocumentRequestBody.builder()
        .title("文档标题")
        .folder_token("")  # 空字符串 = 根目录
        .build()).build()
resp = client.docx.v1.document.create(req)
doc_id = resp.data.document.document_id

2. 添加内容块

body = CreateDocumentBlockChildrenRequestBody.builder() \
    .children(blocks)  # List[Block]
    .index(-1)         # -1 = 追加到末尾
    .build()
req = CreateDocumentBlockChildrenRequest.builder() \
    .document_id(doc_id) \
    .block_id(parent_id)      # doc_id = 根级,或容器 block_id
    .document_revision_id(-1) # -1 = 最新版本
    .request_body(body).build()
resp = client.docx.v1.document_block_children.create(req)

3. 获取子块(表格填充用)

req = GetDocumentBlockChildrenRequest.builder() \
    .document_id(doc_id) \
    .block_id(table_block_id) \
    .build()
resp = client.docx.v1.document_block_children.get(req)
cell_ids = [item.block_id for item in resp.data.items]

Block Types 速查

block_type类型Builder setter说明
2text.text()普通文本段落
3-8heading1-6.heading1() ~ .heading6()标题 H1-H6
12bullet.bullet()无序列表
13ordered.ordered()有序列表
14code.code()代码块
15quote.quote()引用行
17todo.todo()任务清单
19callout.callout()高亮块(容器)
22divider.divider({})分割线
25grid.grid()多列布局(API 不支持创建)
27iframe.iframe()内嵌网页
28image.image()图片(需先上传获取 token)
31table.table()表格
34quote_container.quote_container({})引用容器(可嵌套)

构建 Block 的工具函数

以下函数可直接复制使用:

make_text_element — 创建带格式的文本片段

def make_text_element(content, bold=False, italic=False, underline=False,
                      strikethrough=False, inline_code=False,
                      text_color=None, bg_color=None, link=None):
    style_builder = TextElementStyleBuilder()
    if bold: style_builder.bold(True)
    if italic: style_builder.italic(True)
    if underline: style_builder.underline(True)
    if strikethrough: style_builder.strikethrough(True)
    if inline_code: style_builder.inline_code(True)
    if text_color: style_builder.text_color(text_color)     # 1=红 2=橙 3=黄 4=绿 5=蓝 6=紫
    if bg_color: style_builder.background_color(bg_color)   # 同上
    if link: style_builder.link(LinkBuilder().url(link).build())
    return TextElementBuilder() \
        .text_run(TextRunBuilder().content(content)
            .text_element_style(style_builder.build()).build()).build()

make_text_block — 创建文本类 Block

def make_text_block(elements, block_type=2, align=None, style_kwargs=None):
    style_builder = TextStyleBuilder()
    if align: style_builder.align(align)  # 1=左 2=中 3=右
    if style_kwargs:
        if 'language' in style_kwargs: style_builder.language(style_kwargs['language'])
        if 'done' in style_kwargs: style_builder.done(style_kwargs['done'])
    text = TextBuilder().elements(elements).style(style_builder.build()).build()
    bb = BlockBuilder().block_type(block_type)
    type_map = {
        2: 'text', 3: 'heading1', 4: 'heading2', 5: 'heading3',
        6: 'heading4', 7: 'heading5', 8: 'heading6',
        12: 'bullet', 13: 'ordered', 14: 'code', 15: 'quote', 17: 'todo',
    }
    getattr(bb, type_map.get(block_type, 'text'))(text)
    return bb.build()

make_divider — 分割线

def make_divider():
    return BlockBuilder().block_type(22).divider({}).build()

常用代码块语言 ID

ID语言ID语言
1PlainText22JavaScript
15Bash/Shell40TypeScript
49Python18Java
19JSON12Go
7C++56YAML
29Markdown54SQL
53Rust4C

Callout 高亮块

Callout 是容器块,创建后需要往内部添加子块:

callout = BlockBuilder().block_type(19) \
    .callout(CalloutBuilder()
        .background_color(4)   # 1=红 2=橙 3=黄 4=绿 5=蓝 6=紫
        .border_color(4)
        .emoji_id("bulb")      # 英文 emoji 名称,非 unicode
        .build()).build()
ids = add_blocks([callout])
add_blocks([make_text_block(...)], parent_id=ids[0])  # 填充内容

常用 emoji_id: bulb, check, warning, star, crystal_ball, rocket, fire, heart, memo, pushpin

表格

表格创建后自动生成空 cell,需要查询 cell_ids 再逐个填充:

table = BlockBuilder().block_type(31) \
    .table(TableBuilder()
        .property(TablePropertyBuilder().row_size(3).column_size(4).build())
        .cells([]).build()).build()
table_ids = add_blocks([table])

# 获取 cell block_ids
req = GetDocumentBlockChildrenRequest.builder() \
    .document_id(doc_id).block_id(table_ids[0]).build()
resp = client.docx.v1.document_block_children.get(req)
cell_ids = [item.block_id for item in resp.data.items]
# cells 按行优先排列: [row0col0, row0col1, ..., row1col0, ...]

for idx, cell_id in enumerate(cell_ids):
    row, col = idx // num_cols, idx % num_cols
    add_blocks([make_text_block([make_text_element(data[row][col])])], parent_id=cell_id)

行内公式(LaTeX)

make_text_block([
    make_text_element("能量公式:"),
    TextElementBuilder().equation(
        EquationBuilder().content("E = mc^2").build()
    ).build(),
])

引用容器

容器块,可嵌套文本、列表等:

qc = BlockBuilder().block_type(34).quote_container({}).build()
qc_ids = add_blocks([qc])
add_blocks([make_text_block(...)], parent_id=qc_ids[0])

图片

需要先上传文件获取 image token,再创建 image block:

# 1. 上传图片到飞书(使用 drive API 的 upload_media)
# 2. 创建 image block
image_block = BlockBuilder().block_type(28) \
    .image(ImageBuilder().token(image_token).width(800).height(400).build()).build()

注意事项

  • Rate limit: 每秒约 5 次 API 调用,批量操作间加 time.sleep(0.2)
  • Grid 不支持 API 创建: block_type=25 返回 block not support to create,只能在客户端手动添加
  • 容器块填充: Callout (19)、Quote Container (34)、Table Cell (32) 都是容器,创建后需要往 children 添加内容
  • document_revision_id=-1: 总是使用最新版本,避免并发冲突
  • 文档 URL: https://bytedance.feishu.cn/docx/{document_id}

工作流程

  1. 创建空文档 → 拿到 document_id
  2. 规划内容结构 → 标题、段落、表格、Callout 等
  3. 批量添加块 → 一次 API 调用可加多个同级 block
  4. 填充容器 → 表格 cell、callout、quote_container 需要二次填充
  5. 返回文档链接 → https://bytedance.feishu.cn/docx/{document_id}

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.