Feishu Document Tool
Single tool feishu_doc with action parameter for all document operations, including table creation for Docx.
Token Extraction
From URL https://xxx.feishu.cn/docx/ABC123def → doc_token = INLINECODE3
Actions
Read Document
CODEBLOCK0
Returns: title, plain text content, block statistics. Check hint field — if present, structured content (tables, images) exists that requires list_blocks.
Write Document (Replace All)
CODEBLOCK1
Replaces entire document with markdown content. Supports: headings, lists, code blocks, quotes, links, images ( auto-uploaded), bold/italic/strikethrough, and Markdown tables.
Append Content
CODEBLOCK2
Appends markdown to end of document. Supports the same content types as write, including Markdown tables.
Insert Content (Positioned)
CODEBLOCK3
Inserts content after a specific block. Uses Descendant API internally, supports all block types including tables.
Key usage: This is the primary way to insert content at a precise position. Use list_blocks first to find the after_block_id.
Create Document
CODEBLOCK4
With folder:
CODEBLOCK5
Important: Always pass owner_open_id with the requesting user's open_id (from inbound metadata sender_id) so the user automatically gets full_access permission on the created document. Without this, only the bot app has access.
List Blocks
CODEBLOCK6
Returns full block data including tables, images. Use this to read structured content and find block IDs for positioning.
Get Single Block
CODEBLOCK7
Update Block Text
CODEBLOCK8
Supports Markdown inline styles: **bold**, ` code , link, ~~strike~~.
**Supported block types:** Text, Heading, Bullet, Ordered, Code, Quote, Todo.
**⚠️ NOT for tables:** Using updateblock on a table cell replaces content as plain text, destroying all inline formatting (inline_code, bold, etc.).
### Delete Block
CODEBLOCK9
### Create Table
CODEBLOCK10
**⚠️ Positioning unreliable:** parentblockid and index parameters do not work correctly for tables — tables always end up at the document end. Use insert action with afterblockid instead for positioned tables.
### Write Table Cells
CODEBLOCK11
Writes plain text into table cells. Supports Markdown inline styles in cell values.
**Note:** This clears and rebuilds cell children. Suitable for initial table filling or full-cell replacement, but not for partial cell edits.
### Create Table With Values (One-step)
CODEBLOCK12
**⚠️ Same positioning caveat as createtable** — use insert action for positioned tables.
### Table Row/Column Operations
CODEBLOCK13
**Note for deletetablerows:** Uses blockid (not tableblockid), rowstart (not rowindex).
### Upload Image
CODEBLOCK14
Or local path with position control:
CODEBLOCK15
Or base64 data URI:
CODEBLOCK16
**Note:** Image display size is determined by the uploaded image's pixel dimensions. For small images (e.g. 480x270), scale to 800px+ width before uploading.
### Upload File Attachment
CODEBLOCK17
Or local path:
CODEBLOCK18
### Color Text
CODEBLOCK19
## Reading Workflow
1. Start with action: "read" — get plain text + statistics
2. Check blocktypes in response for Table, Image, Code, etc.
3. If structured content exists, use action: "listblocks" for full data
---
## Incremental Sync Best Practices
### When to Use Incremental vs Full Sync
- **< 5 blocks changed** → incremental (delete + insert individual blocks)
- **> 80% blocks changed** → full sync (write action to replace all)
- **Single table changed** → delete old table + insert new table
### Table Update Strategy: Delete + Insert
Tables should NEVER be edited in-place. Always:
CODEBLOCK20
**Why not edit in-place?**
- updateblock on table cell → strips inline formatting (inline_code, bold, links all become plain text)
- writetablecells → clears and rebuilds cell children, similar formatting loss
- createtable / createtablewithvalues → positioning unreliable
### Multi-Block Batch Replacement
When changes span multiple consecutive blocks:
1. Find anchor (last unchanged block before the changed region)
2. Delete changed blocks in **reverse order** (to avoid index drift)
3. Single insert call with all new content (supports mixed block types)
### Diff Strategy (from feishu-doc-sync)
1. Block signature matching — (type, content) hash for alignment, style hash for change detection
2. LCS alignment of local ↔ remote blocks
3. Three-phase execution: **UPDATE** (text blocks) → **DELETE** (reverse order) → **INSERT** (forward order)
4. Tables: if structure is identical, cell-level diff is possible; if structure differs, full table replacement
5. When change rate > 80%, fall back to full sync
---
## Table Header Row (Dark Background)
The headerrow: true property gives tables a dark header background. This is a common requirement.
### ⚠️ Critical: headerrow can ONLY be set at creation time
**The PATCH API (updatetableproperty) does NOT work for headerrow** — it returns code: 0 (success) but silently fails to apply the property. This applies to both single-block PATCH and batchupdate.
### How to Create Tables with Header Row
Since insert action (Descendant API) and createtable action do not support headerrow, you must use the raw Feishu API:
CODEBLOCK21
**Credentials:** Read from /root/.openclaw/openclaw.json → channels.feishu.appId / channels.feishu.appSecret.
### Workflow for Positioned Table with Header Row
1. listblocks → find the anchor block and target index
2. (If replacing) deleteblock → remove old table
3. Raw API documentblockchildren.create → create empty table with headerrow: true at correct index
4. feishudoc writetablecells → fill content
5. Verify: getblock → check table.property.headerrow
### Column Width Algorithm
Auto-calculated when using insert action (Descendant API):
- Total width: ~730px
- CJK characters count as 2x width
- Per-column: proportional distribution, clamped to 50–400px
- When using raw API, specify columnwidth manually
---
## Sync Prerequisites
- **Always git pull before reading local repo files** — ensures latest content
- **Compare before writing** — use read or listblocks to check current state
- **Preserve formatting** — inline_code, bold, links in table cells require careful handling
## Configuration
CODEBLOCK22
**Note:** feishuwiki depends on this tool — wiki page content is read/written via feishu_doc.
## Permissions
Required: docx:document, docx:document:readonly, docx:document.block:convert, drive:drive`
飞书文档工具
单一工具 feishu_doc,通过 action 参数执行所有文档操作,包括 Docx 表格创建。
Token 提取
从 URL https://xxx.feishu.cn/docx/ABC123def → doc_token = ABC123def
操作
读取文档
json
{ action: read, doc_token: ABC123def }
返回:标题、纯文本内容、块统计信息。检查 hint 字段——如果存在,则表示存在需要 list_blocks 的结构化内容(表格、图片)。
写入文档(全部替换)
json
{ action: write, doc_token: ABC123def, content: # 标题\n\nMarkdown 内容... }
用 Markdown 内容替换整个文档。支持:标题、列表、代码块、引用、链接、图片(
自动上传)、粗体/斜体/删除线、以及 Markdown 表格。
追加内容
json
{ action: append, doc_token: ABC123def, content: 附加内容 }
将 Markdown 内容追加到文档末尾。支持与 write 相同的内容类型,包括 Markdown 表格。
插入内容(定位插入)
json
{
action: insert,
doc_token: ABC123def,
afterblockid: doxcnXXX,
content: 包含表格的 Markdown 内容...
}
在指定块之后插入内容。内部使用 Descendant API,支持包括表格在内的所有块类型。
关键用法: 这是在精确位置插入内容的主要方式。先使用 listblocks 查找 afterblock_id。
创建文档
json
{ action: create, title: 新文档, owneropenid: ou_xxx }
带文件夹:
json
{
action: create,
title: 新文档,
folder_token: fldcnXXX,
owneropenid: ou_xxx
}
重要: 始终传递 owneropenid 为请求用户的 openid(来自入站元数据 senderid),以便用户自动获得所创建文档的 full_access 权限。否则,只有机器人应用有权访问。
列出块
json
{ action: listblocks, doctoken: ABC123def }
返回完整的块数据,包括表格、图片。用于读取结构化内容和查找用于定位的块 ID。
获取单个块
json
{ action: getblock, doctoken: ABC123def, block_id: doxcnXXX }
更新块文本
json
{
action: update_block,
doc_token: ABC123def,
block_id: doxcnXXX,
content: 包含粗体和代码的新文本
}
支持 Markdown 内联样式:粗体、 代码 、链接、~~删除线~~。
支持的块类型: 文本、标题、无序列表、有序列表、代码、引用、待办事项。
⚠️ 不适用于表格: 对表格单元格使用 update_block 会将内容替换为纯文本,破坏所有内联格式(内联代码、粗体等)。
删除块
json
{ action: deleteblock, doctoken: ABC123def, block_id: doxcnXXX }
创建表格
json
{
action: create_table,
doc_token: ABC123def,
row_size: 2,
column_size: 2,
column_width: [200, 200]
}
⚠️ 定位不可靠: parentblockid 和 index 参数对表格无效——表格始终出现在文档末尾。如需定位表格,请改用带 afterblockid 的 insert 操作。
写入表格单元格
json
{
action: writetablecells,
doc_token: ABC123def,
tableblockid: doxcnTABLE,
values: [
[A1, B1],
[A2, B2]
]
}
将纯文本写入表格单元格。单元格值支持 Markdown 内联样式。
注意: 此操作会清除并重建单元格子元素。适用于初始表格填充或整格替换,但不适用于部分单元格编辑。
一步创建带值的表格
json
{
action: createtablewith_values,
doc_token: ABC123def,
row_size: 2,
column_size: 2,
column_width: [200, 200],
values: [[A1, B1], [A2, B2]]
}
⚠️ 与 create_table 相同的定位问题——如需定位表格,请使用 insert 操作。
表格行/列操作
json
{ action: inserttablerow, doctoken: ..., tableblockid: ..., rowindex: -1 }
{ action: inserttablecolumn, doctoken: ..., tableblockid: ..., columnindex: -1 }
{ action: deletetablerows, doctoken: ..., blockid: ..., rowstart: 1, rowcount: 1 }
{ action: deletetablecolumns, doctoken: ..., blockid: ..., columnstart: 0, columncount: 1 }
{ action: mergetablecells, doctoken: ..., tableblockid: ..., rowstart: 0, rowend: 2, columnstart: 0, column_end: 2 }
deletetablerows 的注意事项: 使用 blockid(而非 tableblockid)、rowstart(而非 row_index)。
上传图片
json
{ action: uploadimage, doctoken: ABC123def, url: https://example.com/image.png }
或带位置控制的本地路径:
json
{
action: upload_image,
doc_token: ABC123def,
file_path: /tmp/image.png,
parentblockid: doxcnParent,
index: 5
}
或 base64 数据 URI:
json
{
action: upload_image,
doc_token: ABC123def,
image: data:image/png;base64,iVBOR...
}
注意: 图片显示大小由上传图片的像素尺寸决定。对于小图片(如 480x270),请在上传前缩放到 800px 以上宽度。
上传文件附件
json
{ action: uploadfile, doctoken: ABC123def, url: https://example.com/report.pdf }
或本地路径:
json
{ action: uploadfile, doctoken: ABC123def, file_path: /tmp/report.pdf, filename: Q1-report.pdf }
文本着色
json
{
action: color_text,
doc_token: ABC123def,
block_id: doxcnXXX,
content: 彩色文本,
color: red
}
读取工作流
- 1. 从 action: read 开始——获取纯文本 + 统计信息
- 检查响应中的 blocktypes,查找表格、图片、代码等
- 如果存在结构化内容,使用 action: listblocks 获取完整数据
增量同步最佳实践
何时使用增量同步 vs 全量同步
- - 修改块数 < 5 → 增量同步(删除 + 插入单个块)
- 修改块数 > 80% → 全量同步(使用 write 操作全部替换)
- 单个表格修改 → 删除旧表格 + 插入新表格
表格更新策略:删除 + 插入
表格永远不应原地编辑。始终:
- 1. listblocks → 找到表格前的块(anchorblockid)
- deleteblock(blockid = oldtableid)
- insert(afterblockid = anchorblock_id, content = | 新 | 表格 |...)
为什么不原地编辑?
- - 对表格单元格使用 updateblock → 剥离内联格式(内联代码、粗体、链接全部变为纯文本)
- writetablecells → 清除并重建单元格子元素,同样导致格式丢失
- createtable / createtablewith_values → 定位不可靠
多