mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-26 01:01:40 +00:00
Add two new optional skills: - siyuan (optional-skills/productivity/): SiYuan Note knowledge base API skill — search, read, create, and manage blocks/documents in a self-hosted SiYuan instance via curl. Requires SIYUAN_TOKEN. - scrapling (optional-skills/research/): Intelligent web scraping skill using the Scrapling library — anti-bot fetching, Cloudflare bypass, CSS/XPath selectors, spider framework for multi-page crawling. Placed in optional-skills/ (not bundled) since both are niche tools that require external dependencies. Co-authored-by: FEUAZUR <FEUAZUR@users.noreply.github.com>
297 lines
9 KiB
Markdown
297 lines
9 KiB
Markdown
---
|
|
name: siyuan
|
|
description: SiYuan Note API for searching, reading, creating, and managing blocks and documents in a self-hosted knowledge base via curl.
|
|
version: 1.0.0
|
|
author: FEUAZUR
|
|
license: MIT
|
|
metadata:
|
|
hermes:
|
|
tags: [SiYuan, Notes, Knowledge Base, PKM, API]
|
|
related_skills: [obsidian, notion]
|
|
homepage: https://github.com/siyuan-note/siyuan
|
|
prerequisites:
|
|
env_vars: [SIYUAN_TOKEN]
|
|
commands: [curl, jq]
|
|
required_environment_variables:
|
|
- name: SIYUAN_TOKEN
|
|
prompt: SiYuan API token
|
|
help: "Settings > About in SiYuan desktop app"
|
|
- name: SIYUAN_URL
|
|
prompt: SiYuan instance URL (default http://127.0.0.1:6806)
|
|
required_for: remote instances
|
|
---
|
|
|
|
# SiYuan Note API
|
|
|
|
Use the [SiYuan](https://github.com/siyuan-note/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
|
|
|
|
1. Install and run SiYuan (desktop or Docker)
|
|
2. Get your API token: **Settings > About > API token**
|
|
3. Store it in `~/.hermes/.env`:
|
|
```
|
|
SIYUAN_TOKEN=your_token_here
|
|
SIYUAN_URL=http://127.0.0.1:6806
|
|
```
|
|
`SIYUAN_URL` defaults to `http://127.0.0.1:6806` if not set.
|
|
|
|
## API Basics
|
|
|
|
All SiYuan API calls are **POST with JSON body**. Every request follows this pattern:
|
|
|
|
```bash
|
|
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:
|
|
```json
|
|
{"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 | `/api/search/fullTextSearchBlock` |
|
|
| SQL query | `/api/query/sql` |
|
|
| Read block | `/api/block/getBlockKramdown` |
|
|
| Read children | `/api/block/getChildBlocks` |
|
|
| Get path | `/api/filetree/getHPathByID` |
|
|
| Get attributes | `/api/attr/getBlockAttrs` |
|
|
| List notebooks | `/api/notebook/lsNotebooks` |
|
|
| List documents | `/api/filetree/listDocsByPath` |
|
|
| Create notebook | `/api/notebook/createNotebook` |
|
|
| Create document | `/api/filetree/createDocWithMd` |
|
|
| Append block | `/api/block/appendBlock` |
|
|
| Update block | `/api/block/updateBlock` |
|
|
| Rename document | `/api/filetree/renameDocByID` |
|
|
| Set attributes | `/api/attr/setBlockAttrs` |
|
|
| Delete block | `/api/block/deleteBlock` |
|
|
| Delete document | `/api/filetree/removeDocByID` |
|
|
| Export as Markdown | `/api/export/exportMdContent` |
|
|
|
|
## Common Operations
|
|
|
|
### Search (Full-Text)
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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-`:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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 |
|
|
|------|-------------|
|
|
| `d` | Document (root block) |
|
|
| `p` | Paragraph |
|
|
| `h` | Heading |
|
|
| `l` | List |
|
|
| `i` | List item |
|
|
| `c` | Code block |
|
|
| `m` | Math block |
|
|
| `t` | Table |
|
|
| `b` | Blockquote |
|
|
| `s` | Super block |
|
|
| `html` | 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 `YYYYMMDDHHmmss-xxxxxxx`. Reject anything else.
|
|
- **Error responses**: always check `code != 0` in responses before processing `data`.
|
|
- **Large documents**: block content and export results can be very large. Use `LIMIT` in SQL and pipe through `jq` to extract only what you need.
|
|
- **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:
|
|
|
|
```yaml
|
|
# 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"
|
|
```
|