187 lines
6.2 KiB
Markdown
187 lines
6.2 KiB
Markdown
---
|
|
name: feishu-docs
|
|
description: 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.
|
|
version: 1.0.0
|
|
author: agent
|
|
metadata:
|
|
hermes:
|
|
tags: [feishu, lark, documents, docx, api, content]
|
|
related_skills: [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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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:
|
|
```python
|
|
# ❌ Redaction will eat the string
|
|
elif line.startswith("FEISHU_APP_SECRET=*** ...
|
|
```
|
|
Instead construct the key name dynamically:
|
|
```python
|
|
# ✅ 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
|
|
|
|
## Related Files
|
|
|
|
- `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
|