Hermes-agent siyuan
SiYuan Note API for searching, reading, creating, and managing blocks and documents in a self-hosted knowledge base via curl.
git clone https://github.com/NousResearch/hermes-agent
T=$(mktemp -d) && git clone --depth=1 https://github.com/NousResearch/hermes-agent "$T" && mkdir -p ~/.claude/skills && cp -r "$T/optional-skills/productivity/siyuan" ~/.claude/skills/nousresearch-hermes-agent-siyuan-601b17 && rm -rf "$T"
optional-skills/productivity/siyuan/SKILL.mdSiYuan Note API
Use the SiYuan kernel API via curl to search, read, create, update, and delete blocks and documents in a self-hosted knowledge base. No extra tools needed -- just curl and an API token.
Prerequisites
- Install and run SiYuan (desktop or Docker)
- Get your API token: Settings > About > API token
- Store it in
:~/.hermes/.envSIYUAN_TOKEN=your_token_here SIYUAN_URL=http://127.0.0.1:6806
defaults toSIYUAN_URL
if not set.http://127.0.0.1:6806
API Basics
All SiYuan API calls are POST with JSON body. Every request follows this pattern:
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/..." \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"param": "value"}'
Responses are JSON with this structure:
{"code": 0, "msg": "", "data": { ... }}
code: 0 means success. Any other value is an error -- check msg for details.
ID format: SiYuan IDs look like
20210808180117-6v0mkxr (14-digit timestamp + 7 alphanumeric chars).
Quick Reference
| Operation | Endpoint |
|---|---|
| Full-text search | |
| SQL query | |
| Read block | |
| Read children | |
| Get path | |
| Get attributes | |
| List notebooks | |
| List documents | |
| Create notebook | |
| Create document | |
| Append block | |
| Update block | |
| Rename document | |
| Set attributes | |
| Delete block | |
| Delete document | |
| Export as Markdown | |
Common Operations
Search (Full-Text)
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/search/fullTextSearchBlock" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"query": "meeting notes", "page": 0}' | jq '.data.blocks[:5]'
Search (SQL)
Query the blocks database directly. Only SELECT statements are safe.
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/query/sql" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"stmt": "SELECT id, content, type, box FROM blocks WHERE content LIKE '\''%keyword%'\'' AND type='\''p'\'' LIMIT 20"}' | jq '.data'
Useful columns:
id, parent_id, root_id, box (notebook ID), path, content, type, subtype, created, updated.
Read Block Content
Returns block content in Kramdown (Markdown-like) format.
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/block/getBlockKramdown" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "20210808180117-6v0mkxr"}' | jq '.data.kramdown'
Read Child Blocks
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/block/getChildBlocks" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "20210808180117-6v0mkxr"}' | jq '.data'
Get Human-Readable Path
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/filetree/getHPathByID" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "20210808180117-6v0mkxr"}' | jq '.data'
Get Block Attributes
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/attr/getBlockAttrs" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "20210808180117-6v0mkxr"}' | jq '.data'
List Notebooks
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/notebook/lsNotebooks" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' | jq '.data.notebooks[] | {id, name, closed}'
List Documents in a Notebook
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/filetree/listDocsByPath" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"notebook": "NOTEBOOK_ID", "path": "/"}' | jq '.data.files[] | {id, name}'
Create a Document
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/filetree/createDocWithMd" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "notebook": "NOTEBOOK_ID", "path": "/Meeting Notes/2026-03-22", "markdown": "# Meeting Notes\n\n- Discussed project timeline\n- Assigned tasks" }' | jq '.data'
Create a Notebook
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/notebook/createNotebook" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "My New Notebook"}' | jq '.data.notebook.id'
Append Block to Document
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/block/appendBlock" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "parentID": "DOCUMENT_OR_BLOCK_ID", "data": "New paragraph added at the end.", "dataType": "markdown" }' | jq '.data'
Also available:
/api/block/prependBlock (same params, inserts at the beginning) and /api/block/insertBlock (uses previousID instead of parentID to insert after a specific block).
Update Block Content
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/block/updateBlock" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": "BLOCK_ID", "data": "Updated content here.", "dataType": "markdown" }' | jq '.data'
Rename a Document
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/filetree/renameDocByID" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "DOCUMENT_ID", "title": "New Title"}'
Set Block Attributes
Custom attributes must be prefixed with
custom-:
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/attr/setBlockAttrs" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": "BLOCK_ID", "attrs": { "custom-status": "reviewed", "custom-priority": "high" } }'
Delete a Block
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/block/deleteBlock" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "BLOCK_ID"}'
To delete a whole document: use
/api/filetree/removeDocByID with {"id": "DOC_ID"}.
To delete a notebook: use /api/notebook/removeNotebook with {"notebook": "NOTEBOOK_ID"}.
Export Document as Markdown
curl -s -X POST "${SIYUAN_URL:-http://127.0.0.1:6806}/api/export/exportMdContent" \ -H "Authorization: Token $SIYUAN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"id": "DOCUMENT_ID"}' | jq -r '.data.content'
Block Types
Common
type values in SQL queries:
| Type | Description |
|---|---|
| Document (root block) |
| Paragraph |
| Heading |
| List |
| List item |
| Code block |
| Math block |
| Table |
| Blockquote |
| Super block |
| HTML block |
Pitfalls
- All endpoints are POST -- even read-only operations. Do not use GET.
- SQL safety: only use SELECT queries. INSERT/UPDATE/DELETE/DROP are dangerous and should never be sent.
- ID validation: IDs match the pattern
. Reject anything else.YYYYMMDDHHmmss-xxxxxxx - Error responses: always check
in responses before processingcode != 0
.data - Large documents: block content and export results can be very large. Use
in SQL and pipe throughLIMIT
to extract only what you need.jq - Notebook IDs: when working with a specific notebook, get its ID first via
.lsNotebooks
Alternative: MCP Server
If you prefer a native integration instead of curl, install the SiYuan MCP server:
# In ~/.hermes/config.yaml under mcp_servers: mcp_servers: siyuan: command: npx args: ["-y", "@porkll/siyuan-mcp"] env: SIYUAN_TOKEN: "your_token" SIYUAN_URL: "http://127.0.0.1:6806"