/install craft-connect
Craft Document Management
Operate on a Craft space via the Craft Connect REST API. Full CRUD on documents, blocks, folders, tasks, collections, and comments.
Requirements
- curl — used for all API requests
- CRAFT_API_URL — your Craft Connect API base URL (contains embedded link token for authentication)
Setup
- Create a Craft Connect link in your Craft space (Settings → Connect → Create Link)
- Copy the API base URL and store it in TOOLS.md under a Craft section:
CRAFT_API_URL=https://connect.craft.do/links/\x3CLINK_ID>/api/v1
- Read TOOLS.md before making any calls to retrieve the URL.
All calls use curl with -H "Content-Type: application/json" for writes and
-H "Accept: application/json" for reads.
Important: URL-encode non-ASCII characters (e.g. Chinese) in query params.
API Reference
Connection Info
curl -s "$CRAFT_API_URL/connection"
Returns space ID, timezone, current time, and deep-link URL templates.
Discovery
# List all folders and locations
curl -s "$CRAFT_API_URL/folders"
# List documents in a location (unsorted | trash | templates | daily_notes)
curl -s "$CRAFT_API_URL/documents?location=unsorted"
# List documents in a folder
curl -s "$CRAFT_API_URL/documents?folderId=\x3CFOLDER_ID>"
# With metadata (creation/modification dates, deep links)
curl -s "$CRAFT_API_URL/documents?location=unsorted&fetchMetadata=true"
# Date filters (ISO YYYY-MM-DD or: today, yesterday, tomorrow)
curl -s "$CRAFT_API_URL/documents?createdDateGte=2025-01-01&lastModifiedDateLte=today"
Search
# Search across ALL documents (URL-encode non-ASCII!)
curl -s "$CRAFT_API_URL/documents/search?include=\x3CTERM>&fetchMetadata=true"
# Search within a specific document (with context blocks)
curl -s "$CRAFT_API_URL/blocks/search?blockId=\x3CDOC_ID>&pattern=\x3CREGEX>&beforeBlockCount=2&afterBlockCount=2"
# Filter search by folder or location
curl -s "$CRAFT_API_URL/documents/search?include=\x3CTERM>&folderIds=\x3CFOLDER_ID>"
curl -s "$CRAFT_API_URL/documents/search?include=\x3CTERM>&location=daily_notes"
Documents
# Create document (defaults to unsorted)
curl -s -X POST "$CRAFT_API_URL/documents" \
-H "Content-Type: application/json" \
-d '{"documents": [{"title": "My Document"}]}'
# Create in a specific folder
curl -s -X POST "$CRAFT_API_URL/documents" \
-H "Content-Type: application/json" \
-d '{"documents": [{"title": "Doc"}], "destination": {"folderId": "\x3CID>"}}'
# Create as template
curl -s -X POST "$CRAFT_API_URL/documents" \
-H "Content-Type: application/json" \
-d '{"documents": [{"title": "Template"}], "destination": {"destination": "templates"}}'
# Delete (soft-delete to trash, recoverable)
curl -s -X DELETE "$CRAFT_API_URL/documents" \
-H "Content-Type: application/json" \
-d '{"documentIds": ["\x3CDOC_ID>"]}'
# Move between locations
curl -s -X PUT "$CRAFT_API_URL/documents/move" \
-H "Content-Type: application/json" \
-d '{"documentIds": ["\x3CID>"], "destination": {"folderId": "\x3CFOLDER_ID>"}}'
# Restore from trash
curl -s -X PUT "$CRAFT_API_URL/documents/move" \
-H "Content-Type: application/json" \
-d '{"documentIds": ["\x3CID>"], "destination": {"destination": "unsorted"}}'
Reading Content
# Get document content (JSON)
curl -s "$CRAFT_API_URL/blocks?id=\x3CDOC_ID>" -H "Accept: application/json"
# Get daily note
curl -s "$CRAFT_API_URL/blocks?date=today" -H "Accept: application/json"
# Control depth (0=block only, 1=direct children, -1=all)
curl -s "$CRAFT_API_URL/blocks?id=\x3CID>&maxDepth=1"
# With metadata (comments, authors, timestamps)
curl -s "$CRAFT_API_URL/blocks?id=\x3CID>&fetchMetadata=true"
Writing Content
Two methods: markdown (recommended) and blocks JSON.
Method 1: Markdown (Recommended)
Best for most content. Craft parses markdown and auto-generates correct block types, indentation levels, and list styles.
curl -s -X POST "$CRAFT_API_URL/blocks" \
-H "Content-Type: application/json" \
-d '{
"markdown": "## Heading\
\
Paragraph\
\
- bullet 1\
- bullet 2",
"position": {"position": "end", "pageId": "\x3CDOC_ID>"}
}'
Method 2: Blocks JSON
Use when you need explicit control over color, font, textStyle, or other
properties not expressible in plain markdown.
curl -s -X POST "$CRAFT_API_URL/blocks" \
-H "Content-Type: application/json" \
-d '{
"blocks": [
{"type": "text", "textStyle": "h2", "markdown": "## Title"},
{"type": "text", "color": "#00A3CB", "markdown": "\x3Ccallout>💡 Info\x3C/callout>"}
],
"position": {"position": "end", "pageId": "\x3CDOC_ID>"}
}'
Position Options
| Position | Syntax |
|---|---|
| Append to document | {"position": "end", "pageId": "\x3CDOC_ID>"} |
| Prepend to document | {"position": "start", "pageId": "\x3CDOC_ID>"} |
| After a specific block | {"position": "after", "siblingId": "\x3CBLOCK_ID>"} |
| Before a specific block | {"position": "before", "siblingId": "\x3CBLOCK_ID>"} |
| Append to daily note | {"position": "end", "date": "today"} |
Updating & Deleting Blocks
# Update (only provided fields change; others preserved)
curl -s -X PUT "$CRAFT_API_URL/blocks" \
-H "Content-Type: application/json" \
-d '{"blocks": [{"id": "\x3CBLOCK_ID>", "markdown": "Updated", "font": "serif"}]}'
# Delete blocks (permanent!)
curl -s -X DELETE "$CRAFT_API_URL/blocks" \
-H "Content-Type: application/json" \
-d '{"blockIds": ["\x3CID1>", "\x3CID2>"]}'
# Move blocks between documents
curl -s -X PUT "$CRAFT_API_URL/blocks/move" \
-H "Content-Type: application/json" \
-d '{"blockIds": ["\x3CID>"], "position": {"position": "end", "pageId": "\x3CDOC_ID>"}}'
Tasks
# List tasks (scopes: inbox, active, upcoming, logbook, document)
curl -s "$CRAFT_API_URL/tasks?scope=active"
curl -s "$CRAFT_API_URL/tasks?scope=document&documentId=\x3CDOC_ID>"
# Create task in inbox
curl -s -X POST "$CRAFT_API_URL/tasks" \
-H "Content-Type: application/json" \
-d '{"tasks": [{"markdown": "Task text", "taskInfo": {"scheduleDate": "tomorrow"}, "location": {"type": "inbox"}}]}'
# Create task in daily note
curl -s -X POST "$CRAFT_API_URL/tasks" \
-H "Content-Type: application/json" \
-d '{"tasks": [{"markdown": "Task", "taskInfo": {"scheduleDate": "2025-01-20", "deadlineDate": "2025-01-22"}, "location": {"type": "dailyNote", "date": "today"}}]}'
# Create task in a document
curl -s -X POST "$CRAFT_API_URL/tasks" \
-H "Content-Type: application/json" \
-d '{"tasks": [{"markdown": "Task", "location": {"type": "document", "documentId": "\x3CDOC_ID>"}}]}'
# Complete task
curl -s -X PUT "$CRAFT_API_URL/tasks" \
-H "Content-Type: application/json" \
-d '{"tasksToUpdate": [{"id": "\x3CTASK_ID>", "taskInfo": {"state": "done"}}]}'
# Delete task
curl -s -X DELETE "$CRAFT_API_URL/tasks" \
-H "Content-Type: application/json" \
-d '{"idsToDelete": ["\x3CTASK_ID>"]}'
Folders
# Create folder (root level)
curl -s -X POST "$CRAFT_API_URL/folders" \
-H "Content-Type: application/json" \
-d '{"folders": [{"name": "New Folder"}]}'
# Create nested folder
curl -s -X POST "$CRAFT_API_URL/folders" \
-H "Content-Type: application/json" \
-d '{"folders": [{"name": "Sub", "parentFolderId": "\x3CPARENT_ID>"}]}'
# Delete folder (docs move to parent or Unsorted)
curl -s -X DELETE "$CRAFT_API_URL/folders" \
-H "Content-Type: application/json" \
-d '{"folderIds": ["\x3CFOLDER_ID>"]}'
# Move folder
curl -s -X PUT "$CRAFT_API_URL/folders/move" \
-H "Content-Type: application/json" \
-d '{"folderIds": ["\x3CID>"], "destination": "root"}'
# or: "destination": {"parentFolderId": "\x3CID>"}
Collections (Structured Databases)
Collections are like Notion databases — structured tables with typed columns.
# List all collections
curl -s "$CRAFT_API_URL/collections"
# Create collection in a document
curl -s -X POST "$CRAFT_API_URL/collections" \
-H "Content-Type: application/json" \
-d '{
"schema": {
"name": "Tasks",
"contentPropDetails": {"name": "Title"},
"properties": [
{"name": "Status", "type": "singleSelect", "options": [{"name": "Todo"}, {"name": "In Progress"}, {"name": "Done"}]},
{"name": "Priority", "type": "singleSelect", "options": [{"name": "High"}, {"name": "Medium"}, {"name": "Low"}]},
{"name": "Due Date", "type": "date"}
]
},
"position": {"position": "end", "pageId": "\x3CDOC_ID>"}
}'
# Get schema (use json-schema-items format to learn the property keys!)
curl -s "$CRAFT_API_URL/collections/\x3CCOL_ID>/schema?format=json-schema-items"
# ⚠️ IMPORTANT: schema returns auto-generated keys like "", "_2", "_3", "_4"
# You MUST read the schema first to know the correct keys for items
# Get items
curl -s "$CRAFT_API_URL/collections/\x3CCOL_ID>/items"
# Add items (use schema keys, NOT "title"!)
# First GET the schema to find the contentProp key (e.g. "_4" for title)
curl -s -X POST "$CRAFT_API_URL/collections/\x3CCOL_ID>/items" \
-H "Content-Type: application/json" \
-d '{"items": [{"\x3CCONTENT_KEY>": "Item Title", "properties": {"\x3CSTATUS_KEY>": "Todo", "\x3CPRIORITY_KEY>": "High"}}]}'
# Update items
curl -s -X PUT "$CRAFT_API_URL/collections/\x3CCOL_ID>/items" \
-H "Content-Type: application/json" \
-d '{"itemsToUpdate": [{"id": "\x3CITEM_ID>", "properties": {"\x3CSTATUS_KEY>": "Done"}}]}'
# Delete items
curl -s -X DELETE "$CRAFT_API_URL/collections/\x3CCOL_ID>/items" \
-H "Content-Type: application/json" \
-d '{"idsToDelete": ["\x3CITEM_ID>"]}'
# Update schema (replaces entirely — include ALL fields you want to keep)
curl -s -X PUT "$CRAFT_API_URL/collections/\x3CCOL_ID>/schema" \
-H "Content-Type: application/json" \
-d '{"schema": { ... }}'
Comments
curl -s -X POST "$CRAFT_API_URL/comments" \
-H "Content-Type: application/json" \
-d '{"comments": [{"blockId": "\x3CBLOCK_ID>", "content": "Comment text"}]}'
File Upload
curl -s -X POST "$CRAFT_API_URL/upload?position=end&pageId=\x3CDOC_ID>" \
-H "Content-Type: application/octet-stream" \
--data-binary @file.png
Position params: position (start|end|before|after) + pageId/date/siblingId.
Block Types & Formatting
Headings
# H1 Title → textStyle: "h1"
## H2 Subtitle → textStyle: "h2"
### H3 Heading → textStyle: "h3"
#### H4 Strong → textStyle: "h4"
Inline Styles
**bold**, *italic*, ~strikethrough~, `inline code`
[link text](https://url)
$(a+b)^2$ ← inline equation
Highlights (9 solid + 5 gradient)
\x3Chighlight color="COLOR">text\x3C/highlight>
Solid: yellow, blue, red, green, purple, pink, mint, cyan, gray
Gradient: gradient-blue, gradient-purple, gradient-red, gradient-yellow, gradient-brown
Lists
- bullet item → listStyle: "bullet"
1. numbered item → listStyle: "numbered"
- [ ] todo task → listStyle: "task", taskInfo.state: "todo"
- [x] completed task → listStyle: "task", taskInfo.state: "done"
+ toggle (collapsible) → listStyle: "toggle"
Toggle (Collapsible) Lists — CRITICAL
Children MUST be indented 2 spaces to nest inside a toggle:
+ Parent toggle
- Child 1 (hidden when collapsed)
- Child 2
+ Nested toggle
- Deep child
Use markdown mode only. indentationLevel in blocks JSON is silently
ignored on insert.
Blockquote
> Quoted text
Produces block with decorations: ["quote"].
Dividers / Lines
Blocks JSON with lineStyle:
{"type": "line", "lineStyle": "extraLight", "markdown": "***"}
{"type": "line", "lineStyle": "light", "markdown": "****"}
{"type": "line", "lineStyle": "regular", "markdown": "*****"}
{"type": "line", "lineStyle": "strong", "markdown": "******"}
Markdown mode: --- produces extraLight by default.
Code Blocks
Markdown mode:
```python
def hello():
print("Hello")
```
Blocks JSON (requires rawCode!):
{"type": "code", "language": "python", "rawCode": "def hello():\
print('Hello')", "markdown": "```python\
def hello():\
print('Hello')\
```"}
Math Formula (TeX)
{"type": "code", "language": "math_formula", "rawCode": "x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}", "markdown": "```math_formula\
x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}\
```"}
Inline equation in markdown: $(a+b)^2 = a^2 + 2ab + b^2$
Tables
Markdown mode:
| Col A | Col B |
| --- | --- |
| val 1 | val 2 |
Images
Blocks JSON:
{"type": "image", "url": "https://example.com/photo.jpg", "markdown": ""}
Craft re-hosts the image and returns a https://r.craft.do/ URL.
Rich URL (Link Preview)
{"type": "richUrl", "url": "https://www.youtube.com/watch?v=..."}
Page / Card (Sub-pages)
{"type": "page", "textStyle": "page", "markdown": "Sub-page Title"}
{"type": "page", "textStyle": "card", "markdown": "Card Title"}
Then insert content inside using the returned page ID as pageId.
Callouts (Colored Blocks)
Require blocks JSON with color:
{"type": "text", "color": "#00A3CB", "markdown": "\x3Ccallout>💡 Info\x3C/callout>"}
Common colors: #00A3CB (blue/info), #FF3B30 (red/warning), #34C759
(green/success), #FF9500 (orange/caution), #9862E8 (purple), #003382
(deep blue), #006744 (deep green), #864d00 (brown), #ef052a (bright red),
#9ea4aa (gray).
Callouts support inline styles inside:
\x3Ccallout>**bold** and \x3Chighlight color="yellow">highlight\x3C/highlight>\x3C/callout>
Fonts
Set via font in blocks JSON: (default), serif, mono, rounded.
Caption
{"type": "text", "textStyle": "caption", "markdown": "\x3Ccaption>Small annotation\x3C/caption>"}
Task Blocks in Documents
{"type": "text", "listStyle": "task", "taskInfo": {"state": "todo"}, "markdown": "- [ ] Task"}
States: todo, done, canceled — NOT "completed".
Combination Example
{
"type": "text",
"font": "rounded",
"textStyle": "h3",
"color": "#9862E8",
"markdown": "\x3Ccallout>### ✨ Purple rounded heading callout\x3C/callout>"
}
Choosing Insert Method
| Need | Use | Why |
|---|---|---|
| Text, lists, headings | Markdown | Clean, auto-detects types |
| Toggle lists with children | Markdown | Only way to get indentation right |
| Code blocks, tables | Either | Markdown is simpler; JSON needs rawCode |
| Colored callouts | Blocks JSON | Need color property |
| Custom fonts | Blocks JSON | Need font property |
| Captions | Blocks JSON | Need textStyle: "caption" |
| Images, richUrl, pages | Blocks JSON | Need type field |
| Line styles | Blocks JSON | Need lineStyle |
| Math formulas | Blocks JSON | Need language: "math_formula" + rawCode |
| Mixed content | Split calls | Combine markdown + blocks JSON |
Gotchas & Lessons Learned
-
Toggle indentation: markdown mode with 2-space indent is the only way.
indentationLevelin blocks JSON is silently ignored on insert. -
Task state values:
todo | done | canceled. NOTcompleted. -
Position
after/before: usesiblingId(notblockId). -
Position
end/start: usepageIdordate. -
Code blocks in JSON mode: require
rawCodefield. Without it you get a validation error. -
Collection item keys: the API docs say
titlebut the real field name is the auto-generatedcontentPropkey from the schema (e.g._4). AlwaysGET /collections/\x3Cid>/schema?format=json-schema-itemsfirst to discover the correct keys. -
URL-encode search terms: Chinese and special characters in query params must be URL-encoded or
curlreturns 400. -
Accept header: use
application/jsonfor reads.text/markdownmay 502. -
Document delete is soft: goes to trash, restorable via move. Block delete is permanent.
-
Large inserts: one POST can insert many blocks. Prefer fewer larger writes to avoid rate limits.
-
Image re-hosting: Craft downloads external images and re-hosts them at
https://r.craft.do/. Your original URL is replaced. -
Collections are experimental: the API may change. Always read the schema before writing items.
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install craft-connect - 安装完成后,直接呼叫该 Skill 的名称或使用
/craft-connect触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Craft Connect 是什么?
Read and write Craft documents via the Craft Connect API. Use when the user asks to create, read, update, or search Craft documents, manage tasks, write dail... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 293 次。
如何安装 Craft Connect?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install craft-connect」即可一键安装,无需额外配置。
Craft Connect 是免费的吗?
是的,Craft Connect 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Craft Connect 支持哪些平台?
Craft Connect 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Craft Connect?
由 HWnex(@hwnex)开发并维护,当前版本 v1.0.1。