Files
hermes-skills/SKILL.md
T

6.2 KiB

name, description, version, author, metadata
name description version author metadata
feishu-docs Create and edit Feishu/Lark documents programmatically via the Docx Open API — create docs, add content blocks, read raw text, and manage permissions. Use when the user asks to create a Feishu doc from scratch or add structured content. 1.0.0 agent
hermes
tags related_skills
feishu
lark
documents
docx
api
content
homelab-services

Feishu Docs — Document Creation & Editing

When to Use

  • User asks you to create a Feishu document (docx) with structured content
  • User wants a report, summary, or reference saved as a Feishu doc
  • User says "帮我创建一份飞书文档" or similar
  • Supplement to lark-mcp MCP tools (which cover search, import, bitable, IM but not block-level editing)

Trigger Conditions

  • Keywords: 飞书文档, 创建文档, 写个文档, Feishu doc, Lark docx
  • NOT: 飞书表格 (use lark-mcp bitable tools), 发送消息 (use send_message or lark-mcp IM tools)

Architecture

Two complementary systems:

System Strengths Gaps
lark-mcp (MCP server) Bitable CRUD, IM/groups, document search, markdown→doc import No block-level editing, no doc creation
Feishu Docx API (this skill) Create docs, add/edit/delete blocks, read raw content Requires manual API calls via Python

Use lark-mcp for everything it covers. Fall back to direct API for document creation and block editing.

Prerequisites

The Feishu app must have these permissions in the developer console:

  • docx:document — create and manage documents
  • drive:drive — access cloud documents (for import API)

Without these, the API returns 404. User must add them at https://open.feishu.cn/app.

Credentials are in ~/.hermes/.env:

FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=xxx

Workflow: Create a Document from Scratch

Step 1: Get tenant access token

import requests
r = requests.post(
    "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
    json={"app_id": aid, "app_secret": sec}, timeout=10
)
token = r.json()["tenant_access_token"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

Step 2: Create empty document

r = requests.post(
    "https://open.feishu.cn/open-apis/docx/v1/documents",
    headers=headers,
    json={"title": "文档标题"},
    timeout=10
)
doc_id = r.json()["data"]["document"]["document_id"]
# URL: https://xiteng.feishu.cn/docx/{doc_id}

Step 3: Add content blocks

The document root is also the root block. Add children to it:

blocks = [
    {"block_type": 3, "heading1": {"elements": [
        {"text_run": {"content": "大标题"}}
    ]}},
    {"block_type": 2, "text": {"elements": [
        {"text_run": {"content": "正文段落"}}
    ]}},
    {"block_type": 12, "bullet": {"elements": [
        {"text_run": {"content": "列表项"}}
    ]}},
]

# Batch up to 50 blocks per request
r = requests.post(
    f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children",
    headers=headers,
    json={"children": blocks},
    timeout=15
)

Block type reference

block_type Name Structure
2 Text paragraph {"text": {"elements": [{"text_run": {"content": "..."}}]}}
3 Heading 1 {"heading1": {"elements": ...}}
4 Heading 2 {"heading2": {"elements": ...}}
5 Heading 3 {"heading3": {"elements": ...}}
6 Heading 4 {"heading4": {"elements": ...}}
12 Bullet list {"bullet": {"elements": ...}}
13 Ordered list {"ordered": {"elements": ...}}
14 Code block {"code": {"elements": ..., "style": {"language": 1}}}
17 Callout/hint {"callout": {"elements": ...}}
22 Divider {"divider": {}}
27 Table Complex — see API docs

Step 4: Read back and verify

r = requests.get(
    f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/raw_content",
    headers={"Authorization": f"Bearer {token}"},
    timeout=10
)
content = r.json()["data"]["content"]

Common Pitfalls

1. 404 on import API — missing permissions

The drive/v1/files/import API requires drive:drive permission. Without it, returns 404. Fix: User must add the permission in Feishu Developer Console → App → Permissions.

2. ENV var redaction in scripts

When writing Python scripts that read ~/.hermes/.env, do NOT write lines like:

# ❌ Redaction will eat the string
elif line.startswith("FEISHU_APP_SECRET=***    ...

Instead construct the key name dynamically:

# ✅ Safe from redaction
if k == "FEISHU_APP_SECRET": ...
# or
prefix = "FEISHU_APP"
if k == prefix + "_SECRET": ...

3. Block batch limit

The children API accepts at most 50 blocks per request. Split large documents into batches.

4. Document ID = Root block ID

The document_id returned from create is also the root block ID. Use it for both:

  • GET /docx/v1/documents/{doc_id} — get document metadata
  • POST /docx/v1/documents/{doc_id}/blocks/{doc_id}/children — add blocks

Integration with lark-mcp

When lark-mcp is connected (see references/lark-mcp-setup.md), use it for:

  • docx_builtin_search — search existing documents
  • docx_v1_document_rawContent — read document plain text
  • docx_builtin_import — quick markdown→doc conversion (creates new doc)
  • bitable_* — multi-dimensional table operations
  • im_* — messages and groups

Use direct API (this skill) when you need:

  • Create a blank document with a specific title
  • Add/edit/delete individual blocks
  • Modify existing document structure

Verification Checklist

  • FEISHU_APP_ID and FEISHU_APP_SECRET are set in .env
  • App has docx:document permission
  • Document created: GET /docx/v1/documents/{id} returns 200
  • Content added: GET /docx/v1/documents/{id}/blocks returns blocks
  • User can open the URL in Feishu
  • scripts/create_doc.py — reusable script: create doc + add content from markdown
  • references/lark-mcp-setup.md — MCP server installation and credential management
  • references/docx-block-types.md — full block type reference with examples