@frostime/siyuan-cli
v0.17.0
Published
Agent-first CLI for SiYuan Note — workspace management, kernel API proxy, workflow tools, and agent skill install
Maintainers
Readme
siyuan-cli
A command-line interface that allows external agents (Claude Code, Codex, OpenCode, etc.) to operate SiYuan Note safely and effectively.
siyuan-cli is essentially a wrapper that calls the SiYuan HTTP kernel API for local agents. It complements what those raw HTTP calls lack: connection management, access control, and self-documentation required by agentic workflows.
It is designed for agents such as OpenCode, Claude Code, Codex, and Pi Coding Agent, which can run shell commands, inspect stdout/stderr, and read files.
Beta · Node.js ≥ 20 · GPL-3.0
Quick Start
1. Install
# npm
npm install -g @frostime/siyuan-cli
# pnpm
pnpm add -g @frostime/siyuan-cliRequires Node.js ≥ 20.
Command name compatibility
Use siyuan-cli as the canonical command. The package also installs siyuan as a compatibility alias: on SiYuan versions earlier than 3.7.0, either entry can run this package. Starting with SiYuan 3.7.0, SiYuan provides its own native siyuan command, so the program selected by a bare siyuan depends on PATH order and is not guaranteed to be this package. Existing scripts and Agent instructions should migrate to siyuan-cli.
2. Connect a SiYuan workspace
siyuan-cli workspace add local --url http://127.0.0.1:6806 --token <your-token> # Settings → About in SiYuan
siyuan-cli workspace verify local
siyuan-cli current whichIf you don't know the port, use workspace directory auto-discovery (local only):
siyuan-cli workspace add devspace --workspace-dir /path/to/SiYuanDevSpace --token <token>3. Test the connection
siyuan-cli api query.sql "SELECT id, hpath FROM blocks WHERE type='d' LIMIT 5"Output (compact format, default):
5 rows [hpath, id]
1: /Restructure misc model provider | 20251111144823-0lhpmav
2: /Agent experiment design | 20260305172423-yswy868
3: /Prompt | Optimize notebook content | 20260124162935-qf9u737
...4. Install the agent SKILL
siyuan-cli skill installBy default, it installs the built-in SKILL to ~/.agents/skills/.
Use --agent to target a specific tool, for example: siyuan-cli skill install --agent claude-code. Run siyuan-cli skill targets to see every agent and where its skills live.
If you update siyuan-cli, run the command again to update the skill.
5. Use it in your agent
Launch an agent that can read skill files, read local files, and run shell commands.
Say to your agent:
"Help me use siyuan-cli. Read its SKILL, then follow that SKILL's routing to the bundled resources whenever you need detail."
There are two ways for an agent to read the SKILL: its host loads the installed copy (step 4), or the agent runs siyuan-cli skill read on demand with nothing installed at all. Either way the SKILL must match the CLI version — on a mismatch warning, run siyuan-cli skill install again and re-read.
The README is a human-facing overview. Detailed operational guidance lives in the SKILL and its bundled resources.
How to think about siyuan-cli
siyuan-cli is a substrate for agents: it provides reliable access to SiYuan through workspace resolution, permission checks, approval, response filtering, and built-in docs. It is not meant to encode every personal workflow.
For repeated workflows such as literature ingestion, daily review, project knowledge-base maintenance, or publication cleanup, create a task-specific Agent SKILL on top of this CLI. Use TypeScript extensions when you need reusable CLI runtime code; use downstream skills when you need reusable workflow policy.
Calling Kernel APIs
Every registered SiYuan endpoint becomes a subcommand under siyuan-cli api. The endpoint id format is <group>.<name>, derived from the kernel path /api/<group>/<name>.
# List all endpoints, optionally filter by group or tag
siyuan-cli api --help
siyuan-cli api list --group block
# View parameter schema and usage examples
siyuan-cli api block.updateBlock --help

Invocation styles
# Positional primary field (the first required string parameter)
siyuan-cli api query.sql "SELECT id, hpath FROM blocks WHERE type='d' LIMIT 5"
# Named flags
siyuan-cli api block.getBlockKramdown --id 20260425162235-pnpy21c
# Entire payload as inline JSON
siyuan-cli api attr.setBlockAttrs -j '{"id":"...","attrs":{"custom-key":"value"}}'
# Entire payload from a JSON file (useful for complex payloads)
siyuan-cli api attr.setBlockAttrs -f payload.json
# Payload from stdin
cat payload.json | siyuan-cli api attr.setBlockAttrs -f -
Flexible input sources
Some string fields accept content from external sources, so you don't have to inline large markdown or SQL into shell arguments. Which fields support which sources is declared per endpoint — check <endpoint> --help for the INPUT SOURCES section.
| Syntax | Meaning |
|--------|---------|
| "plain text" | Literal value (always available) |
| @file:./path | Read content from a file, resolved from cwd |
| @stdin | Read from stdin (single-use per invocation) |
| @env:VAR_NAME | Read from an environment variable |
| @@file:... | Escape — pass the literal string @file:... |
This is particularly useful for write operations where the content is long or contains characters that are awkward to escape in shell:
# Write a markdown file's content into a block
siyuan-cli tool update-block --blocks @file:./updates.json --yes
# Pipe SQL from another command
echo "SELECT id FROM blocks WHERE type='d' LIMIT 3" | siyuan-cli api query.sql @stdin
# Read token from environment at runtime
siyuan-cli workspace add ci --url http://ci-host:6806 --token @env:SIYUAN_TOKENFor agents, @file: is especially valuable — the agent can write content to a temporary file first, then pass it to the CLI, avoiding shell escaping issues entirely. Agent guidance recommends using the system temp directory and cleaning temporary files afterwards.
Output and debugging
# Default: compact human-readable output (when the endpoint defines a formatter)
siyuan-cli api query.sql "SELECT id, hpath FROM blocks LIMIT 5"
# Raw JSON from the kernel
siyuan-cli api query.sql "SELECT id, hpath FROM blocks LIMIT 5" --print json
# Preview a write operation without sending it to the kernel
siyuan-cli api block.deleteBlock --id <id> --dry-run
# Print the equivalent curl command to stderr
siyuan-cli api attr.setBlockAttrs --id <id> --attrs '{"custom-key":"val"}' --debugDry-run output includes a wouldRequestApproval field, telling you whether the current permission config would trigger the Approval Center for this operation.
High-Level Tools
Many real tasks require multiple API calls, extra safety checks, or agent-friendly output shaping. Tools wrap these workflows into single commands. Simple one-step operations should use siyuan-cli api directly.
# Append to today's daily note (markdown is the default dataType)
siyuan-cli api block.appendDailyNoteBlock --notebook <notebook-id> --data "## Today's notes\nNew content here"
# Append under a known document/block
siyuan-cli api block.appendBlock --parentID <doc-or-block-id> --data @file:./notes.md
# Document tree listing
siyuan-cli tool list-doc-tree --entry <notebook-id> --depth 2# Document tree: daily note
- 2026 (20260319110807-rpatefx)
├─ 03 (20260319110808-qvgecjr) (+3)
└─ 04 (20260425162235-bxpakql) (+2)# Daily notes by date range
siyuan-cli tool list-dailynote --afterDate 2026-04-01
# Bounded document content read
siyuan-cli tool get-block-content <doc-id> --range children --limit 30
# Full document content read
siyuan-cli tool get-block-content <doc-id> --range children --limit=-1
# Clean body-only read for local edit/write-back workflows
siyuan-cli tool get-block-content <doc-id> --range children --limit=-1 --bodyOnly true > /tmp/doc.md
# Context read around a specific block
siyuan-cli tool get-block-content <block-id> --range context --limit 7 --showId true
# Grep blocks by pattern
siyuan-cli tool locate-block "%keyword%" --id <doc-id>
# Block metadata inspection (includes TOC for document blocks)
siyuan-cli tool get-block-info <block-id>
# Guarded document-level rewrite: use only when block-level edits are fragile or inefficient
siyuan-cli tool brute-edit <doc-id> --check true
# If SAFE: checkpoint once before this high-risk edit group, then dry-run.
siyuan-cli tool checkpoint-doc <doc-id>
siyuan-cli tool brute-edit <doc-id> --overwrite @file:/tmp/doc.md --dry-run
# If UNSAFE: fall back to block-level APIs; a checkpoint does not make brute-edit safe.
# Next: locate stable child block ids, then use tool update-block
siyuan-cli tool update-block --blocks @stdin --yes <<'EOF'
[{"id":"<child-id>","data":"..."}]
EOFTools support --help and --print json; workflow/write tools support --dry-run when previewing is meaningful. Run siyuan-cli tool list for the full list.

Workspace Management
Global configuration
Workspace connections are stored in ~/.config/siyuan-cli/config.yaml (also respects $XDG_CONFIG_HOME and $SIYUAN_CLI_CONFIG), created automatically by workspace add.
siyuan-cli workspace add local --url http://127.0.0.1:6806 --token <token>
siyuan-cli workspace add remote --url http://192.168.1.100:6806 --token <token>
siyuan-cli current global local # set machine-global default
siyuan-cli workspace list # list all configured workspaces
siyuan-cli workspace verify local # test connection and authTokens can be stored literally or sourced from environment variables at runtime:
workspaces:
prod:
baseUrl: http://192.168.1.100:6806
tokenSource:
type: env
value: SIYUAN_TOKEN # resolved at call time, never written to configWorkspace selection
After workspace verify <name>, choose the narrowest selection scope:
- one or a few calls: pass
--workspace <name>; - repeated work in a project: add
workspace: <name>to.siyuan-cli.yaml; - long-lived work without a project file: use the experimental process binding flow,
siyuan-cli current bind <name>followed bysiyuan-cli current confirm <nonce>in a separate caller invocation; - deliberately change the machine-wide fallback: use
siyuan-cli current global <name>.
Before content work, inspect persistent/ambient selection with siyuan-cli current which; a one-off business command's explicit --workspace still determines that call. If confirmation is abandoned, run the printed siyuan-cli current cancel <nonce> command; after successful binding, run siyuan-cli current unbind before ending the task. Process binding follows observable OS process scope, not logical Agent/session identity; use a project file or explicit --workspace when callers share a process or ancestry cannot establish a reliable scope.
Project-level pinning
When multiple projects talk to different SiYuan instances, a global default causes conflicts. Place a .siyuan-cli.yaml at your project root to pin that project to a workspace:
# .siyuan-cli.yaml — safe to commit (the CLI hard-errors if you put tokens or URLs here)
schemaVersion: 1
workspace: prod # must exist in the global configThe full resolution chain:
--baseUrl → --workspace flag → $SIYUAN_CLI_WORKSPACE → project file / process binding → config.currentIf a project file and process binding both select a workspace, they must agree; otherwise resolution fails.
Use siyuan-cli current which at any time to inspect how the current directory resolves — it shows the resolved workspace, its source, the base URL or workspace directory, the project config path, and process-binding diagnostics when applicable. It does not access the kernel.
Permission & Guard System
Letting an agent freely operate on your personal notes is risky. SiYuan's kernel API includes endpoints that delete documents, close notebooks, or even shut down the kernel. The CLI enforces access control at two levels: request interception before requests reach the kernel, and response filtering that strips restricted items from query results.
Permission rules
Rules are declared per workspace (or per project in .siyuan-cli.yaml) and evaluated top-to-bottom — first match wins:
permission:
default: allow
rules:
# Hard-block kernel shutdown
- endpoint: "system.exit"
effect: deny
# Destructive system operations require human approval
- endpoint: "system.*"
effect: approval
# Deny all access to a private notebook
- notebook: "20220305173526-4yjl33h"
effect: deny
# Block writes to a specific document subtree
- path: "/20260107143325-zbrtqup/**"
action: write
effect: deny
# Block a specific document by id (equivalent to path: "**/20260107143325-zbrtqup.sy")
- root_id: "20260107143325-zbrtqup"
effect: denyRules match on endpoint/tool/action (evaluated immediately from the request) and on notebook/path (resolved from block ids in the payload). Three effects: deny (hard block, exit code 5), allow (pass through), approval (pause for human sign-off).
What it looks like in practice
Blocked endpoint — system.exit is hard-denied:
$ siyuan-cli api system.exit
{"error":"ENDPOINT_DENIED","message":"endpoint \"system.exit\" denied: denied by rule #0"}
exit code: 5Accessing a doc in a denied notebook — the CLI resolves the block's owning notebook before sending the request:
$ siyuan-cli api block.getBlockKramdown --id 20240416110608-8pr45e1
{"error":"CONTENT_DENIED","message":"id \"20240416110608-8pr45e1\" (access: read) denied by rule #3"}
exit code: 5Response filtering — query results from denied notebooks are automatically stripped. Here, one notebook is denied; lsNotebooks drops it and reports what was removed:
$ siyuan-cli api notebook.lsNotebooks
{"warning":"CONTENT_FILTERED","removed":1,"reasons":"1x: rule #3"}
10 notebooks [id, name, ...]
1: 20231217193559-sesjqwa | Inbox | ...
2: 20220306104547-c7ilt3x | Academic Learn | ...
...The same applies to SQL queries — rows from restricted notebooks are filtered before reaching stdout:
$ siyuan-cli api query.sql "SELECT id, hpath, box FROM blocks WHERE type='d' LIMIT 10"
{"warning":"CONTENT_FILTERED","removed":5,"reasons":"5x: rule #3"}
5 rows [box, hpath, id]
1: 20231217193559-sesjqwa | /daily note | ...
...Approval flow — when a rule sets approval (or the operation is auto-classified as destructive), the CLI starts a local broker and opens a WebUI for human sign-off:
$ siyuan-cli api system.getConf
{"event":"APPROVAL_PENDING","requestId":"apr_f0f32b2a8bbd492d","url":"http://127.0.0.1:1548/approval?token=...","summary":"Approve: system.getConf"}
siyuan-cli approval list # pending and recent requests
siyuan-cli approval approve <id> # approve from terminal
siyuan-cli approval reject <id> # reject from terminalIndependent of user-configured rules, endpoints classified as destructive or critical risk — batch deletes, system-level writes, runtime invocations — automatically require approval even if your rules say allow. This is a built-in safety net that cannot be bypassed by permission rules alone; only --yes (or behavior.allowYes: false to disable --yes entirely) controls it.
Use siyuan-cli current which to confirm the resolved workspace and source, inspect the applicable permission blocks in config.yaml or .siyuan-cli.yaml, or use --dry-run on any command to preview whether it would be blocked or gated. For the complete rule reference: siyuan-cli skill read cli-usage/permission.md.
Context Control & Built-in Docs
siyuan-cli does not push a large tool catalog or document corpus into the agent context upfront.
Agents discover capabilities incrementally:
siyuan-cli --helpfor the command tree;siyuan-cli api listfor endpoints;siyuan-cli api <id> --helpfor one endpoint;siyuan-cli skill read <resource-path>for bundled guidance;siyuan-cli tool listfor higher-level workflows.
This keeps context disclosure explicit, local, and task-driven.
These docs are designed for agent consumption — agents read them at runtime via CLI commands or direct file access. Human users generally don't need to read them directly; the SKILL and --help output cover day-to-day guidance.
Doc organization
The built-in doc set is organized in three layers:
| Layer | Path | Covers |
|-------|------|--------|
| SiYuan domain knowledge | siyuan-guide/ | Block data model, path semantics (id vs hpath), SQL query strategy, daily note model |
| CLI usage reference | cli-usage/ | Full command tree, global flags, input sources, permission config, extension authoring, error codes |
| Task recipes | recipes/ | Step-by-step workflows: connect workspace, find documents, read content, safely edit content |
siyuan-cli skill read # read the skill (with resource manifest)
siyuan-cli skill read recipes/edit-content.md # one bundled resource
siyuan-cli skill list # resources + summaries, without the skill bodyAddress resources with the paths exactly as listed in that manifest. siyuan-cli --help prints the skill root, so you can also browse the files directly.
Building Task-Specific Skills
siyuan-cli is the substrate — it gives agents the ability to discover and call the CLI. Real workflows should be built as separate task-specific skills on top of it, e.g.:
- literature note ingestion
- daily note review
- project knowledge-base maintenance
- refactoring tags and attributes
- exporting documents for publication
- syncing issue trackers into SiYuan
Install the skill:
siyuan-cli skill install # sync every recorded install (default: ~/.agents/skills/)
siyuan-cli skill install --agent claude-code # → ~/.claude/skills/
siyuan-cli skill install --agent pi # → ~/.pi/agent/skills/
siyuan-cli skill install --project # → ./.agents/skills/ (this checkout only)Global installs are remembered in the CLI config dir, so one bare skill install refreshes all of them (e.g. both ~/.agents and ~/.claude) after a CLI upgrade; --project installs are not tracked. siyuan-cli skill targets lists each known agent and where it loads skills from. See siyuan-cli skill read cli-usage/cli-overview.md.
Tip: install skill-creator, then ask your agent:
I want to xxxx, please create a skill based on
siyuan-cli
User Extensions
siyuan-cli only wraps a subset of SiYuan's kernel API — the most commonly needed endpoints. The kernel exposes many more, and you may also want to compose multiple API calls into reusable workflows. Extensions let you add both without touching the source code.
Extensions live in ~/.config/siyuan-cli/extensions/ and are written in TypeScript, loaded via jiti at execution time:
siyuan-cli extension init # scaffold the directory with tsconfig.json and examples
siyuan-cli extension list # show discovered extensions + cache status
siyuan-cli extension cache # batch-generate schema.json cachesTip: You can tell your agent: "I want to extend the siyuan-cli API. Please read the siyuan-cli docs and help me write an extension for
<endpoint>." The agent can readsiyuan-cli skill read cli-usage/extension.md, visit the website (if it is capable), and generate the extension file for you.Reference
- Source Code — Most reliable, but needs agent analyse code by it self
- Document provided by community, could be out-dated
https://leolee9086.github.io/siyuan-kernelApi-docs/, provided by leolee9086https://leolee9086.github.io/siyuan-kernelApi-docs/index.html, provided by leolee9086https://github.com/siyuan-community/siyuan-sdk/tree/main/schemas/kernel/api, provided by Zuoqiu-Yingyi
API extension example
The kernel has a /api/lute/copyStdMarkdown endpoint that exports a block's content as standard Markdown — useful when you need clean Markdown instead of SiYuan's internal Kramdown. This endpoint is not built into the CLI, but you can add it in three steps.
Step 1 — Create ~/.config/siyuan-cli/extensions/apis/copyStdMarkdown.ts:
import type { EndpointSchema } from "@frostime/siyuan-cli/schema";
export const schema: EndpointSchema = {
endpoint: "/api/lute/copyStdMarkdown",
summary: "Get standard Markdown content of a block",
payload: {
type: "object",
properties: {
id: { type: "string", description: "Block ID" },
},
required: ["id"],
},
classification: { mode: "read", surface: "content", scope: "single" },
};Step 2 — Cache and verify:
siyuan-cli extension cache
siyuan-cli api lute.copyStdMarkdown --helpStep 3 — Use it:
siyuan-cli api lute.copyStdMarkdown --id 20240401175210-c2iabsnThe extension gets the same CLI surface as built-ins: --help, --dry-run, --print json, parameter validation, and permission checks.
Custom tool example
Create ~/.config/siyuan-cli/extensions/tools/hello.ts:
import type { ToolSchema } from "@frostime/siyuan-cli/schema";
export const tool: ToolSchema = {
id: "hello-ext",
summary: "Greet someone",
input: {
type: "object",
properties: { name: { type: "string", description: "Name to greet" } }
},
async run(_ctx, input) {
const { name = "world" } = input as { name?: string };
return { content: `Hello, ${name}!` };
}
};siyuan-cli extension cache
siyuan-cli tool hello-ext --name AliceTool extensions receive a ToolContext with callEndpoint() for calling registered endpoints (with full permission and guard logic) and callEndpointRaw() for calling arbitrary kernel paths directly.
For the full authoring guide: siyuan-cli skill read cli-usage/extension.md.
Troubleshooting
Windows Git Bash / MSYS
Arguments starting with / may be rewritten into Windows paths by the shell before reaching the CLI. This affects SiYuan virtual paths like --path "/TestDoc". Two workarounds:
# Disable path conversion for this command
MSYS_NO_PATHCONV=1 siyuan-cli api filetree.getIDsByHPath --notebook <id> --path "/TestDoc"
# Or use double-slash as a Git Bash / MSYS escape
siyuan-cli api filetree.getIDsByHPath --notebook <id> --path //TestDocAuth failures
- Verify the token with
siyuan-cli workspace verify <name> - Verify the effective selection with
siyuan-cli current verify - Check that SiYuan's kernel is running and reachable at the configured URL
- Tokens from
tokenSource: envare resolved at call time; ensure the env var is set in the calling shell
Wrong workspace
Run siyuan-cli current which to inspect the resolved workspace and its resolution source. Use --workspace <name> to override for a single command.
Permission denied
- Run
siyuan-cli api <id> --dry-runto see if the operation would be blocked - Inspect the applicable
permissionblocks inconfig.yamlor.siyuan-cli.yaml - Edit the applicable
permissionrules inconfig.yamlor.siyuan-cli.yaml
License
GPL-3.0 · GitHub: https://github.com/frostime/siyuan-cli
