This guide is the operational and architectural reference for SiYuan — its internals, HTTP/WebSocket API, configuration surface, security model, deployment options, and operations. It is written for administrators, self-hosters, integrators, plugin authors, and developers. End-user feature walkthroughs live in the companion User Guide.
SiYuan is a privacy-first personal knowledge management system from Yunnan Liandi Technology Co., Ltd. (B3log), licensed AGPL-3.0. It is composed of a Go kernel (the engine) and a TypeScript UI that ships as a desktop (Electron), mobile (Android/iOS/HarmonyOS), and browser front end. This guide is generated from the source at the commit noted in the footer.
Table of Contents
- Executive Summary
- System Architecture
- Repository Structure
- Requirements
- Boot Sequence and Process Model
- Kernel Command-Line Reference
- Environment Variables
- Configuration Reference (
conf.json) - The HTTP/WebSocket Server
- Security Model
- HTTP API Reference
- WebSocket Command Channel
- WebDAV, CalDAV, and CardDAV
- Data Model and Storage
- Synchronization and the Data Repo
- Deployment
- The Publish Service
- Operations
- Performance Tuning
- Security Hardening Checklist
- Extensibility: Plugins, Widgets, and the Bazaar
- Code Quality and Conventions
- Potential Improvements
- Troubleshooting
- Quick Reference
1. Executive Summary
SiYuan's defining architectural decision is the kernel/UI split. The kernel is a single Go binary that runs a local HTTP + WebSocket server (gin + melody) on port 6806. It owns all state: it parses and stores block-structured Markdown (via the Lute engine), maintains a SQLite block index, renders databases, runs spaced-repetition scheduling (riff/FSRS), performs encrypted versioned sync (dejavu), and exposes ~485 JSON endpoints. The UI — whether the Electron desktop shell, a mobile app, or a plain browser — is a thin client that talks to that local kernel over the same API.
This design yields three deployment shapes from one codebase:
| Shape | Kernel | UI | Notes |
|---|---|---|---|
| Desktop | Bundled, child process of Electron | Electron renderer (/stage/build/{app,desktop}) |
Full feature set incl. PDF/Word/HTML export |
| Mobile | Compiled into the app (gomobile) |
Native shell + web view (/stage/build/mobile) |
Android/iOS/HarmonyOS |
| Self-hosted | b3log/siyuan Docker image |
Any browser over :6806 |
Browser only; no desktop/mobile connect; no PDF/Word/HTML export, no MD import |
| Attribute | Value |
|---|---|
| License | AGPL-3.0 |
| Vendor | Yunnan Liandi Technology Co., Ltd. (B3log) |
| Kernel language | Go (see go.mod for the toolchain version) |
| UI language | TypeScript + webpack; Electron desktop shell |
| Default kernel port | 6806 (HTTP/WS); publish service 6808 |
| Primary data store | Per-document .sy JSON files + SQLite block index |
| Sync | Encrypted snapshots to SiYuan Cloud / S3 / WebDAV / local FS |
2. System Architecture
┌──────────────────────────────────────────────┐
│ Front ends (thin clients) │
│ Electron desktop · Android/iOS/HarmonyOS · │
│ Browser (self-hosted) │
└───────────────┬──────────────────────────────┘
│ HTTP (JSON, POST /api/*)
│ WebSocket (/ws, melody) — realtime push & commands
▼
┌───────────────────────────────────────────────────────────────────────┐
│ Kernel (Go, single binary) │
│ │
│ gin HTTP engine ──► middleware: ControlConcurrency → Timing → │
│ Recover → CORS → JWT → gzip → sessions │
│ │
│ kernel/api REST handlers (~485 endpoints, /api/{domain}/{action}) │
│ kernel/server HTTP/WS wiring, WebDAV/CalDAV/CardDAV, static serving │
│ kernel/model Business logic (the largest package) │
│ kernel/cmd WebSocket command dispatch │
│ kernel/sql SQLite block / history / asset-content indexes │
│ kernel/av Attribute views (databases) │
│ kernel/treenode Block tree + block-tree index │
│ kernel/filesys .sy document (de)serialization │
│ kernel/bazaar Marketplace (plugins/widgets/themes/icons/templates) │
│ kernel/conf Configuration structs (conf.json) │
│ kernel/job Cron jobs (history, sync, cleanup) │
│ kernel/task Background task queue │
│ kernel/util Boot, paths, TLS, OCR, pandoc, device, working dir │
│ kernel/cache In-memory caches (assets, etc.) │
│ kernel/mobile gomobile entry points for mobile apps │
│ kernel/harmony HarmonyOS-specific glue │
└───────────────────────────────┬───────────────────────────────────────┘
│ uses
▼
Lute (Markdown engine) · dejavu (data repo) · riff/go-fsrs (flashcards) ·
go-sqlite3 (index) · pdfium/pdfcpu (PDF) · gosseract (OCR) · go-openai (AI) ·
aws-sdk-go-v2/s3 · gowebdav/go-webdav (sync, CalDAV/CardDAV) · excelize (xlsx)
2.1 Request lifecycle (REST)
- A client sends
POST /api/{domain}/{action}with a JSON body. - gin runs the global middleware chain: ControlConcurrency (serializes kernel API requests), Timing, Recover, CORS, JWT (parses the
X-Auth-Tokenand sets the request role), gzip, and sessions. - Per-route middleware enforces auth:
CheckAuth→ optionallyCheckAdminRole→ optionallyCheckReadonly. - The handler in
kernel/api/*.govalidates the request, calls intokernel/model, and returns a JSON envelope{code, msg, data}.
2.2 Realtime channel
The UI maintains a WebSocket to /ws (melody). The kernel pushes progress, notifications, and UI-reload events to clients, and also accepts commands over the socket (parsed into cmd.NewCommand and run via cmd.Exec). This is how long-running operations (sync, indexing, transactions) report progress live.
2.3 One kernel, three UIs
The root route (/) inspects the User-Agent and redirects to the correct static bundle: Electron → /stage/build/app/, tablets/Pad/non-mobile Android → /stage/build/desktop/, mobile → /stage/build/mobile/, otherwise desktop. All three bundles are produced from the app/ TypeScript source via separate webpack configs.
3. Repository Structure
The repo is a polyglot monorepo: app/ (TypeScript front end) + kernel/ (Go back end).
| Path | Purpose |
|---|---|
kernel/main.go |
Desktop/server kernel entry point (boot sequence) |
kernel/api/ |
REST handlers + router.go (the authoritative endpoint list) |
kernel/server/ |
HTTP/WS server, WebDAV/CalDAV/CardDAV, static serving, proxy |
kernel/model/ |
Core business logic (largest package): documents, blocks, sync, export, import, history, flashcards, attribute views, etc. |
kernel/cmd/ |
WebSocket command registry and executor |
kernel/sql/ |
SQLite schema and queries (block, history, asset-content DBs) |
kernel/av/ |
Attribute views (databases) |
kernel/treenode/ |
Block tree and block-tree index |
kernel/filesys/ |
.sy document read/write |
kernel/bazaar/ |
Marketplace client (install/stage/readme) |
kernel/conf/ |
Configuration structs (one struct per concern) |
kernel/job/, kernel/task/ |
Cron scheduler and background task queue |
kernel/util/ |
Boot, path resolution, TLS certs, OCR, pandoc, device id, working dir |
kernel/cache/ |
In-memory caches |
kernel/mobile/, kernel/harmony/ |
Mobile (gomobile) and HarmonyOS entry points |
app/electron/main.js |
Electron main process (window/workspace/tray/kernel-child management) |
app/src/ |
UI source: editor/, protyle/ (editor core), layout/, menus/, dialog/, config/, search/, plugin/, mobile/, window/, asset/, emoji/ |
app/stage/ |
Static runtime assets and vendored renderers (KaTeX, Mermaid, ECharts, PDF.js, highlight.js, PlantUML, Graphviz, abcjs) |
app/appearance/ |
Themes, icons, emojis, language packs (langs/) |
app/pandoc/ |
Bundled Pandoc resources |
app/changelogs/, app/guide/ |
Release changelogs and the built-in user-guide notebook |
scripts/ |
Build/packaging helpers |
Note
app/changelogs/andapp/guide/are large by file count but are content, not code — the guide folders are SiYuan notebooks (.sydocuments with ID-named subfolders), not source to be deployed as logic.
4. Requirements
4.1 Runtime (end users)
| Deployment | Requirement |
|---|---|
| Desktop | Windows / macOS / Linux (x64 and arm64 builds available) |
| Mobile | Android / iOS / iPadOS / HarmonyOS |
| Self-hosted | Docker host; a modern browser to access the UI |
The desktop app bundles the kernel, Electron runtime, and Pandoc — no separate installs needed.
4.2 Build / development
| Component | Toolchain |
|---|---|
| Kernel | Go (version pinned in kernel/go.mod); CGO for SQLite |
| UI | Node.js + pnpm (version pinned in app/package.json packageManager); webpack; TypeScript |
| Desktop packaging | electron + electron-builder (per-platform/arch electron-builder*.yml configs) |
| Export | Pandoc (bundled for the desktop) |
| OCR | Tesseract (bundled/available for OCR features) |
UI build scripts (app/package.json):
pnpm run dev # webpack dev build (app)
pnpm run dev:desktop # dev build, desktop bundle
pnpm run dev:mobile # dev build, mobile bundle
pnpm run build # production build of all bundles
pnpm run dist # electron-builder package (current platform)
pnpm run dist-darwin # macOS package, etc. (see all dist-* scripts)
Note
The kernel uses a forked SQLite driver (
88250/go-sqlite3) and a forked pdfcpu (88250/pdfcpu) viareplacedirectives ingo.mod. Build from the module graph as-is; don't substitute upstream versions without testing.
5. Boot Sequence and Process Model
kernel/main.go defines the startup order (desktop/server build; the //go:build !mobile tag separates it from mobile entry points):
util.Boot() // parse flags, resolve workspace/paths, logging, lock
model.InitConf() // load conf.json (defaults via conf.NewX())
go server.Serve(false, CookieKey) // start gin HTTP/WS server (async)
model.InitAppearance() // themes, icons, languages
sql.InitDatabase(false) // main block index (SQLite)
sql.InitHistoryDatabase(false) // history index
sql.InitAssetContentDatabase(false) // asset-content (search) index
model.BootSyncData() // boot-time sync if enabled
model.InitBoxes() // open notebooks
model.LoadFlashcards() // FSRS decks
job.StartCron() // scheduled jobs
... watchers (assets, emojis, themes) + HandleSignal()
Key facts:
- Workspace lock: only one kernel may use a workspace at a time (the "workspace is locked" error indicates a second kernel).
- Port file: the kernel writes its chosen port keyed by PID to
~/.config/siyuan/port.jsonso launchers and tools can discover it. - Desktop child process: the Electron main process (
app/electron/main.js) launches the kernel as a child with flags--port,--wd <appDir>,--workspace,--lang, and (in dev)--mode dev. It manages multiple workspaces/windows, a system tray per workspace, single-instance locking, and thesiyuan://protocol handler.
Important
On desktop you never start the kernel yourself — Electron does. For self-hosting you run the kernel binary directly (the Docker entrypoint does this for you), so the CLI flags below matter.
6. Kernel Command-Line Reference
Flags parsed in kernel/util/working.go:
| Flag | Default | Purpose |
|---|---|---|
--workspace |
~/SiYuan/ |
Workspace directory path |
--wd |
(binary working dir) | Working directory of SiYuan (where stage/, appearance/, etc. live) |
--port |
0 |
HTTP server port (0 = pick a free port; conventionally 6806) |
--readonly |
false |
Start in read-only mode (blocks all write operations) |
--accessAuthCode |
"" |
Access authorization code (the kernel's password) |
--ssl |
false |
Enable HTTPS/WSS |
--lang |
"" |
Interface language (e.g. en_US, zh_CN, ja_JP, de_DE, es_ES, fr_FR, ko_KR, ru_RU, pt_BR, tr_TR, zh_CHT, …) |
--mode |
prod |
dev or prod (dev enables /debug/pprof and dev asset paths) |
The Docker entrypoint additionally honors --workspace= and forwards any extra arguments to the kernel.
# Run the kernel directly (self-host without Docker)
./kernel --workspace=/data/siyuan --port=6806 --accessAuthCode=please-change-me --lang=en_US
7. Environment Variables
The kernel reads these via os.Getenv (UI/Electron reads NODE_ENV):
| Variable | Used by | Effect |
|---|---|---|
SIYUAN_WORKSPACE_PATH |
Docker entrypoint | Workspace path (CLI --workspace wins if both set) |
SIYUAN_ACCESS_AUTH_CODE |
Docker entrypoint | Access auth code (CLI --accessAuthCode wins) |
SIYUAN_ACCESS_AUTH_CODE_BYPASS |
kernel/util/working.go |
If true, bypasses the access auth code (insecure; use only in trusted/dev contexts) |
SIYUAN_OPENAI_API_KEY |
kernel/conf/ai.go |
Default OpenAI API key |
SIYUAN_OPENAI_API_TIMEOUT |
kernel/conf/ai.go |
OpenAI request timeout (seconds; default 30) |
SIYUAN_OPENAI_API_PROXY |
kernel/conf/ai.go |
Proxy for OpenAI calls |
SIYUAN_OPENAI_API_MAX_TOKENS |
kernel/conf/ai.go |
Max tokens |
SIYUAN_OPENAI_API_TEMPERATURE |
kernel/conf/ai.go |
Sampling temperature (default 1.0) |
SIYUAN_OPENAI_API_MAX_CONTEXTS |
kernel/conf/ai.go |
Number of context messages (default 7) |
SIYUAN_OPENAI_API_BASE_URL |
kernel/conf/ai.go |
API base URL (default https://api.openai.com/v1) |
SIYUAN_OPENAI_API_USER_AGENT |
kernel/conf/ai.go |
Custom user agent |
SIYUAN_TESSERACT_ENABLED |
kernel/util/ocr.go |
Enable Tesseract OCR |
SIYUAN_TESSERACT_TIMEOUT |
kernel/util/ocr.go |
OCR timeout |
SIYUAN_TESSERACT_MAX_SIZE |
kernel/util/ocr.go |
Max image size for OCR |
SIYUAN_TESSERACT_LANGS |
kernel/util/ocr.go |
OCR languages |
SIYUAN_PDF_ASSET_CONTENT_INDEX_MAX_SIZE |
kernel/model/asset_content.go |
Max PDF size to index for asset-content search |
SIYUAN_SYNC_INDEX_TIMING |
kernel/model/conf.go |
Sync-index timing threshold |
SIYUAN_PERFORMANCE_TIMING |
kernel/model/session.go |
Enable performance timing logs |
PUID / PGID |
Docker entrypoint | Run-as user/group IDs inside the container (default 1000/1000) |
NODE_ENV |
app/electron/main.js |
Electron dev/prod mode |
APPDATA / ProgramData / USERPROFILE |
kernel/util/path.go, working.go |
Windows path resolution |
Caution
SIYUAN_ACCESS_AUTH_CODE_BYPASS=truedisables authentication entirely. Never set it on an instance reachable by anyone but you.
8. Configuration Reference (conf.json)
Runtime configuration lives in workspace/conf/conf.json, deserialized into the AppConf aggregate. Each concern is its own struct in kernel/conf/*.go, with JSON keys and defaults defined by the corresponding NewX() constructor. Per-notebook settings live in each notebook's .siyuan/conf.json (BoxConf).
Note
Most settings are managed through the in-app Settings UI (which calls the
/api/setting/*and/api/system/*endpoints). Editingconf.jsonby hand is possible but should be done with the kernel stopped.
8.1 System (kernel/conf/system.go)
| Key | Type | Notes |
|---|---|---|
id, name |
string | Device ID and name |
kernelVersion, os, osPlatform |
string | Runtime info |
container |
string | docker / android / ios / harmony / std |
isMicrosoftStore, isInsider |
bool | Build flavor |
homeDir, workspaceDir, appDir, confDir, dataDir |
string | Resolved paths |
networkServe |
bool | Bind to 0.0.0.0 (LAN serving) instead of 127.0.0.1 |
networkServeTLS |
bool | Enable HTTPS (requires networkServe) |
networkProxy |
object | {scheme, host, port} outbound proxy |
downloadInstallPkg |
bool | Auto-download update packages |
autoLaunch2 |
int | 0 off / 1 on / 2 on+hidden |
lockScreenMode |
int | 0 manual / 1 manual+follow-system |
disabledFeatures |
[]string | Feature flags to disable |
microsoftDefenderExcluded |
bool | Whether the workspace was added to Defender exclusions |
8.2 Editor (kernel/conf/editor.go) — selected keys
| Key | Default | Notes |
|---|---|---|
fontSize |
16 | |
allowSVGScript, allowHTMLBLockScript |
false | Execute scripts inside SVG/HTML blocks (security-sensitive) |
codeSyntaxHighlightLineNum, codeLineWrap, codeLigatures |
false | Code-block rendering |
codeTabSpaces |
0 | Tab→spaces in code (0 = off) |
generateHistoryInterval |
10 | File-history interval (minutes) |
historyRetentionDays |
30 | History retention |
virtualBlockRef |
false | Virtual references; virtualBlockRefInclude/Exclude keyword lists |
blockRefDynamicAnchorTextMaxLen |
96 | |
plantUMLServePath |
https://www.plantuml.com/plantuml/svg/~1 |
PlantUML render server |
fullWidth |
true | Max-width layout |
katexMacros |
{} |
KaTeX macro definitions |
readOnly |
false | Editor read-only |
dynamicLoadBlocks |
192 | Blocks loaded per chunk (range 48–1024) |
spellcheck / spellcheckLanguages |
false / ["en-US"] |
|
backlinkExpandCount |
8 | |
floatWindowMode / floatWindowDelay |
0 / 620ms | Hover-preview behavior |
markdown |
object | Markdown parsing settings |
8.3 Appearance (kernel/conf/appearance.go)
| Key | Default | Notes |
|---|---|---|
mode / modeOS |
0 (light) / true | Theme mode; follow OS |
themeDark / themeLight |
midnight / daylight |
|
codeBlockThemeDark / codeBlockThemeLight |
base16/dracula / github |
|
icon |
material |
Icon set |
lang |
en_US |
UI language |
closeButtonBehavior |
0 | 0 quit / 1 minimize to tray |
hideStatusBar |
false |
8.4 Sync (kernel/conf/sync.go)
| Key | Default | Notes |
|---|---|---|
enabled |
false | Master sync toggle |
cloudName |
main |
Cloud sync directory name |
mode |
1 | 1 auto / 2 manual / 3 fully manual |
interval |
30 | Auto-sync seconds |
provider |
0 | 0 SiYuan / 2 S3 / 3 WebDAV / 4 Local |
perception |
false | Sync awareness |
generateConflictDoc |
false | Create a conflict doc on conflict |
s3 |
object | endpoint, accessKey, secretKey, bucket, region, pathStyle, skipTlsVerify, timeout, concurrentReqs |
webdav |
object | endpoint, username, password, skipTlsVerify, timeout, concurrentReqs |
local |
object | endpoint (local dir), timeout, concurrentReqs |
8.5 Repo (kernel/conf/repo.go)
| Key | Default | Notes |
|---|---|---|
key |
— | AES key for the encrypted data repo (binary) |
syncIndexTiming |
12000 | ms threshold to warn about slow indexing |
indexRetentionDays |
180 | Auto-purge local indexes older than this |
retentionIndexesDaily |
2 | Indexes kept per day |
8.6 Publish (kernel/conf/publish.go)
| Key | Default | Notes |
|---|---|---|
enable |
false | Enable the publish service |
port |
6808 | Publish service port |
auth.enable |
true | Basic auth on the publish service |
auth.accounts[] |
[] | {username, password, memo} accounts |
8.7 Other config structs
| Struct | File | Highlights |
|---|---|---|
AI / OpenAI |
ai.go |
API key, base URL, model, provider (OpenAI/Azure), temperature 1.0, contexts 7, timeout 30 |
API |
api.go |
token (16-char API token, randomly generated) |
Search |
search.go |
Per-block-type search toggles, limit 64, caseSensitive, name/alias/memo/IAL flags, asset-path indexing, backlink/virtual-ref matching |
Export |
export.go |
Block-ref/embed modes, PDF footer %page / %pages, watermarks, Pandoc bin/params, YAML front matter, include sub/related docs |
Flashcard |
flashcard.go |
New/review limits 20/200, card-making modes, FSRS requestRetention/maximumInterval/weights |
Graph |
graph.go |
maxBlocks 10240, local/global graph type filters and D3 force params |
FileTree |
filetree.go |
Sort, maxListCount 512, maxOpenTabCount 8, deep-create guard, large-file warning |
Bazaar |
bazaar.go |
trust, petalDisabled (disable plugin system) |
Tag |
tag.go |
Sort mode |
Snippet/Snpt |
snippet.go |
enabledCSS, enabledJS; per-snippet {id,name,type,enabled,disabledInPublish,content} |
Account, User, Stat |
account.go, user.go, stat.go |
Cloud account display, membership/traffic fields, content statistics |
BoxConf |
box.go |
Per-notebook: name, icon, sort, create/daily-note paths + template |
9. The HTTP/WebSocket Server
Defined in kernel/server/serve.go (Serve(fastMode, cookieKey)).
9.1 Binding and ports
if model.Conf.System.NetworkServe || util.ContainerDocker == util.Container {
host = "0.0.0.0" // LAN-accessible (or always in Docker)
} else {
host = "127.0.0.1" // localhost only (default)
}
- Default bind is loopback only. Setting
networkServe(or running in Docker) binds to all interfaces. - The actual port is recorded to
~/.config/siyuan/port.jsonkeyed by PID. - HTTP/2 cleartext (
UseH2C) is enabled; max multipart upload memory is 32 MiB.
9.2 TLS
When networkServeTLS and networkServe are both on, the kernel obtains/creates a self-signed CA + cert (util.GetOrCreateTLSCert) and serves HTTPS, multiplexing TLS and plain connections on a fixed port via cmux. You can export the CA cert/bundle via API (/api/system/exportTLSCACert, exportTLSCABundle) and import a bundle.
9.3 Middleware chain (global)
ControlConcurrency (serialize kernel API requests — see [issue #9939]) → Timing → Recover → corsMiddleware → jwtMiddleware → gzip (excluding already-compressed media) → sessions (cookie store named siyuan, HttpOnly, Secure when SSL).
9.4 Static and special route groups
| Route | Auth | Serves |
|---|---|---|
/ |
CheckAuth | Redirects to /stage/build/{app,desktop,mobile} by User-Agent |
/stage/* |
CheckAuth | UI bundles and static assets |
/appearance/*filepath |
CheckAuth | Themes/icons/langs (fills missing lang keys from en_US) |
/assets/*path |
CheckAuth | Workspace assets (path-escaped, publish-access-checked, thumbnail/SVG handling) |
/history/*path |
CheckAuth + Admin | File history |
/repo/diff/*path |
CheckAuth + Admin | Repo snapshot diffs |
/export/*filepath |
CheckAuth | Export downloads (sub-path + sensitive-file guarded; forces attachment download) |
/widgets/, /plugins/, /emojis/, /templates/ |
CheckAuth | Static dirs under data/ |
/public/ |
(open) | data/public/ contents |
/snippets/*filepath |
CheckAuth | Snippet content (conf.json requires admin role) |
/upload |
CheckAuth + Admin + ¬Readonly | File upload |
/check-auth |
(open) | Auth page (HTML) |
/ws |
(handshake auth) | WebSocket |
/webdav/*, /caldav/*, /carddav/*, /.well-known/{caldav,carddav} |
CheckAuth + Admin | WebDAV/CalDAV/CardDAV |
/debug/pprof/* |
dev mode only | Go profiling |
favicon.ico, manifest.json, service-worker.js |
(open) | PWA fixed files |
Warning
/debug/pprof/*is registered only when--mode dev. Production builds do not expose pprof (per [issue #10152]).
9.5 CORS
The CORS middleware sets Access-Control-Allow-Origin: * with credentials allowed, and tailors Access-Control-Allow-Methods per route family (standard HTTP, WebDAV, CalDAV, CardDAV methods). OPTIONS preflight returns 204 with a 600-second max-age.
Caution
Access-Control-Allow-Origin: *combined withAllow-Credentials: truemeans any web origin can attempt authenticated requests if it has valid credentials/token. Authentication is enforced by the auth code / token, not by origin. Treat the access auth code and API token as secrets and never expose the kernel directly to the internet without a reverse proxy and strong auth.
10. Security Model
SiYuan's authorization is enforced by three composable gin middlewares plus a role system. Defined in kernel/model and applied in kernel/api/router.go and kernel/server/serve.go.
10.1 Authentication layers
- Access Auth Code — the workspace "password" (
Conf.AccessAuthCode). When set, clients must authenticate (via the/check-authpage → session cookie). Can be supplied at launch via--accessAuthCode/SIYUAN_ACCESS_AUTH_CODE, or bypassed (insecurely) withSIYUAN_ACCESS_AUTH_CODE_BYPASS=true. - API Token —
Conf.API.Token(a random 16-char token). Sent asX-Auth-Tokenfor programmatic/API access; parsed byjwtMiddleware. - Session cookie — gin cookie session (
siyuan),HttpOnly,Secureunder TLS.
10.2 Roles
The JWT/token carries a role; jwtMiddleware sets it on the request (defaulting to Visitor when no valid token):
| Role | Capability |
|---|---|
Administrator |
Full read/write/admin |
Editor |
Read/write |
Reader |
Read-only |
Visitor |
Minimal/unauthenticated |
10.3 Authorization middleware
| Middleware | Enforces |
|---|---|
CheckAuth |
A valid session or token (authenticated) |
CheckAdminRole |
The request role is administrator (write/admin endpoints) |
CheckReadonly |
The kernel is not in read-only mode (blocks mutations when --readonly or Editor.ReadOnly) |
A typical mutating endpoint stacks all three: CheckAuth, CheckAdminRole, CheckReadonly. Read endpoints often use only CheckAuth. A handful of bootstrap endpoints (bootProgress, version, currentTime, loginAuth, logoutAuth, getCaptcha, getDynamicIcon) require no auth.
10.4 Publish-access checks
When an asset is requested by a non-admin context, the server consults the document's publish access settings (GetPublishAccess / CheckAbsPathAccessableByPublishAccess) before serving — so published/shared documents only expose what they're allowed to.
10.5 Content-execution safeguards
- SVG sanitization: SVG assets are sanitized unless
Editor.AllowSVGScriptis enabled. - HTML block scripts: disabled unless
Editor.AllowHTMLBLockScriptis on. - Sensitive paths: the export server refuses to serve files it deems sensitive and enforces sub-path containment to prevent path traversal.
- IP allow/deny: the network forward-proxy endpoint rejects prohibited IPs (
ip address [%s] is prohibited) to mitigate SSRF. - CA/JWT: TLS CA management and JWT parsing live in
kernel/util/cert.goandkernel/modelrespectively.
Important
The single most important hardening step for any networked instance is a strong access auth code plus a reverse proxy terminating TLS. See the hardening checklist.
11. HTTP API Reference
The kernel exposes a JSON REST API registered in kernel/api/router.go. All endpoints accept POST (a few also GET) at /api/{domain}/{action} and return {code, msg, data}. Authenticate with the API token via the X-Auth-Token header. There are ~485 endpoints; they are grouped by domain below. The official endpoint catalog is also published as API.md.
Auth legend: 🔓 no auth · 🔑 CheckAuth · 🛡 +Admin role · 🔒 +Readonly guard (mutating).
11.1 Calling convention
curl -X POST http://127.0.0.1:6806/api/notebook/lsNotebooks \
-H "Authorization: Token <your-api-token>" \
-H "X-Auth-Token: <your-api-token>" \
-H "Content-Type: application/json" \
-d '{}'
Note
Request/response bodies vary per endpoint; consult
kernel/api/*.gohandlers (or API.md) for exact fields. The tables below are the authoritative endpoint inventory grouped by function.
11.2 System & lifecycle (/api/system/*)
| Endpoint | Auth | Purpose |
|---|---|---|
bootProgress (GET/POST) |
🔓 | Boot progress |
version (GET/POST), currentTime |
🔓 | Kernel version / server time |
getConf |
🔑 | Full configuration |
getNetwork, getSysFonts, getChangelog, getWorkspaceInfo |
🔑/🛡 | System info |
setNetworkServe, setNetworkServeTLS, setNetworkProxy |
🛡🔒 | Network serving / TLS / proxy |
exportTLSCACert, exportTLSCABundle, importTLSCABundle |
🛡(🔒) | TLS CA management |
setAccessAuthCode, setFollowSystemLockScreen, setAPIToken |
🛡🔒 | Auth settings |
setWorkspaceDir, getWorkspaces, getMobileWorkspaces, checkWorkspaceDir, createWorkspaceDir, removeWorkspaceDir, removeWorkspaceDirPhysically |
🛡(🔒) | Workspace management |
setAppearanceMode, setUILayout |
🛡🔒 | UI/appearance |
setAutoLaunch, setDownloadInstallPkg, checkUpdate |
🛡(🔒) | Launch & updates |
exportConf, importConf, exportLog |
🛡(🔒) | Config import/export, logs |
vacuumDataIndex, rebuildDataIndex, clearTempFiles |
🛡🔒 | Index/temp maintenance |
addMicrosoftDefenderExclusion, ignoreAddMicrosoftDefenderExclusion |
🛡🔒 | Windows Defender |
exit, reloadUI (deprecated→/api/ui/reloadUI) |
🛡 | Lifecycle |
11.3 Notebooks (/api/notebook/*)
lsNotebooks 🔑 · openNotebook closeNotebook createNotebook removeNotebook renameNotebook changeSortNotebook setNotebookIcon 🛡🔒 · getNotebookConf getNotebookInfo 🔑 · setNotebookConf 🛡🔒.
11.4 File tree / documents (/api/filetree/*)
| Group | Endpoints |
|---|---|
| Read 🔑 | searchDocs, listDocsByPath, getDoc, getDocCreateSavePath, getRefCreateSavePath, getHPathByPath, getHPathsByPaths, getHPathByID, getPathByID, getFullHPathByID, getIDsByHPath |
| Create/modify 🛡🔒 | createDoc, createDocWithMd, createDailyNote, renameDoc, renameDocByID, removeDoc, removeDocByID, removeDocs, moveDocs, moveDocsByID, duplicateDoc, changeSort |
| Restructure 🛡🔒 | doc2Heading, heading2Doc, li2Doc |
| Index/publish 🛡🔒 | upsertIndexes, removeIndexes, listDocTree, moveLocalShorthands, setPublishAccess, getPublishAccess, authFilePublishAccess |
11.5 Blocks (/api/block/*)
The richest domain. Read operations (🔑/🛡): getBlockInfo, getBlockDOM(s), getBlockDOM(s)WithEmbed, getBlockKramdown(s), getChildBlocks, getTailChildBlocks, getBlockBreadcrumb, getBlockIndex, getBlocksIndexes, getRefIDs, getRefText, getDOMText, getTreeStat, getBlocksWordCount, getContentWordCount, getRecentUpdatedBlocks, getDocInfo(s), checkBlockExist, checkBlockFold, getUnfoldedParentID, getBlockSiblingID, getBlockRelevantIDs, getBlockTreeInfos, checkBlockRef, heading transactions (getHeadingLevelTransaction, getHeadingDeleteTransaction, getHeadingInsertTransaction, getHeadingChildrenIDs/DOM).
Mutations (🛡🔒): insertBlock, batchInsertBlock, prependBlock, appendBlock (+ batch + daily-note variants), updateBlock, batchUpdateBlock, deleteBlock, moveBlock, moveOutlineHeading, foldBlock, unfoldBlock, setBlockReminder, swapBlockRef, transferBlockRef, appendHeadingChildren, updateTaskListItemMarker (+ batch).
11.6 Attribute views / databases (/api/av/*)
Render: renderAttributeView, renderHistoryAttributeView, renderSnapshotAttributeView. Keys/fields: getAttributeViewKeys, addAttributeViewKey, removeAttributeViewKey, sortAttributeViewKey, sortAttributeViewViewKey. Rows/blocks: addAttributeViewBlocks, removeAttributeViewBlocks, batchReplaceAttributeViewBlocks, duplicateAttributeViewBlock, appendAttributeViewDetachedBlocksWithValues. Values/filters: setAttributeViewBlockAttr, batchSetAttributeViewBlockAttrs, getAttributeViewFilterSort, setAttrViewGroup, changeAttrViewLayout, setDatabaseBlockView. Search/relations: searchAttributeView, searchAttributeViewRelationKey, searchAttributeViewRollupDestKeys, getMirrorDatabaseBlocks, getAttributeViewKeysByAvID/ByID. Cleanup: getUnusedAttributeViews, removeUnusedAttributeView(s).
11.7 Search (/api/search/*)
fullTextSearchBlock, fullTextSearchAssetContent, searchTag, searchTemplate, searchWidget, searchRefBlock, searchEmbedBlock, getEmbedBlock, updateEmbedBlock, searchAsset, getAssetContent, findReplace 🛡🔒, removeTemplate 🛡🔒, listInvalidBlockRefs.
11.8 Editing pipeline & queries
| Domain | Endpoints |
|---|---|
/api/transactions |
performTransactions 🛡🔒 — the core batched edit operation the editor uses |
/api/query/sql |
SQL 🛡🔒 — run a SQL query against the block index |
/api/sqlite/flushTransaction |
flush pending DB writes |
/api/lute/* |
spinBlockDOM, html2BlockDOM, copyStdMarkdown — Markdown engine ops |
/api/template/* |
render, renderSprig, docSaveAsTemplate |
/api/convert/pandoc |
Pandoc conversion |
/api/format/* |
autoSpace, netImg2LocalAssets, netAssets2LocalAssets |
11.9 Assets & files
| Domain | Endpoints |
|---|---|
/api/asset/* |
upload, insertLocalAssets, resolveAssetPath, uploadCloud(ByAssetsPaths), getUnusedAssets, getMissingAssets, removeUnusedAsset(s), getDocImageAssets, getDocAssets, renameAsset, statAsset, setFileAnnotation, getFileAnnotation, ocr, getImageOCRText, setImageOCRText, fullReindexAssetContent |
/api/file/* |
getFile, putFile, copyFile, globalCopyFiles, workspaceCopyFiles, removeFile, renameFile, readDir, getUniqueFilename |
/api/archive/* |
zip, unzip 🛡🔒 |
/api/clipboard/* |
readFilePaths, writeFilePath |
/api/extension/copy |
Web-clipper copy |
11.10 Export & import
Export (/api/export/*, 🛡): exportMd, exportMds, exportNotebookMd, exportSY(s), exportNotebookSY, exportMdContent, exportHTML, exportPreviewHTML, exportMdHTML, exportBrowserHTML, exportDocx, processPDF, exportResources, exportAsFile, exportData, exportDataInFolder, exportTempContent, export2Liandi, exportReStructuredText, exportAsciiDoc, exportTextile, exportOPML, exportOrgMode, exportMediaWiki, exportODT, exportRTF, exportEPUB, exportAttributeView, exportCodeBlock, preview.
Import (/api/import/*, 🛡🔒): importStdMd, importZipMd, importData, importSY.
11.11 Sync, repo, and cloud
| Domain | Endpoints |
|---|---|
/api/sync/* |
setSyncEnable, setSyncInterval, setSyncMode, setSyncPerception, setSyncGenerateConflictDoc, setSyncProvider, setSyncProviderS3/WebDAV/Local, performSync, performBootSync, getBootSync, getSyncInfo, cloud-sync-dir CRUD, export/importSyncProviderS3/WebDAV |
/api/repo/* |
initRepoKey, initRepoKeyFromPassphrase, importRepoKey, resetRepo, purgeRepo, purgeCloudRepo, createSnapshot, tagSnapshot, checkoutRepo, getRepoSnapshots, getRepoTagSnapshots, removeRepoTagSnapshot, cloud snapshot ops, diffRepoSnapshots, openRepoSnapshotFile, rollbackRepoSnapshotFile, getRepoFile, setRepoIndexRetentionDays, setRetentionIndexesDaily |
/api/cloud/getCloudSpace |
Cloud quota |
/api/account/* |
login, checkActivationcode, useActivationcode, deactivate, startFreeTrial |
/api/setting/getCloudUser, logoutCloudUser, login2faCloudUser |
Cloud account |
11.12 Knowledge features
| Domain | Endpoints |
|---|---|
/api/ref/* |
getBacklink, getBacklink2, getBacklinkDoc, getBackmentionDoc, refreshBacklink |
/api/attr/* |
getBlockAttrs, batchGetBlockAttrs, setBlockAttrs, batchSetBlockAttrs, getBookmarkLabels (resetBlockAttrs deprecated) |
/api/tag/* |
getTag, renameTag, removeTag |
/api/bookmark/* |
getBookmark, renameBookmark, removeBookmark |
/api/outline/getDocOutline |
Document outline |
/api/graph/* |
getGraph, getLocalGraph, resetGraph, resetLocalGraph |
/api/riff/* |
Flashcard decks/cards: createRiffDeck, renameRiffDeck, removeRiffDeck, getRiffDecks, addRiffCards, removeRiffCards, getRiffDueCards (+tree/notebook), reviewRiffCard, skipReviewRiffCard, getRiffCards, resetRiffCards, batchSetRiffCardsDueTime, getRiffCardsByBlockIDs |
/api/history/* |
getNotebookHistory, getDocHistoryContent, getHistoryItems, searchHistory, rollbackDocHistory, rollbackNotebookHistory, rollbackAssetsHistory, rollbackAttributeViewHistory, clearWorkspaceHistory, reindexHistory |
/api/inbox/* |
getShorthands, getShorthand, removeShorthands |
/api/snippet/* |
getSnippet, setSnippet, removeSnippet |
11.13 AI, bazaar, storage, UI, network
| Domain | Endpoints |
|---|---|
/api/ai/* |
chatGPT, chatGPTWithAction 🛡 |
/api/bazaar/* |
Per package type (plugin/widget/icon/template/theme): getBazaarX, getInstalledX, installBazaarX 🛡🔒, uninstallBazaarX 🛡🔒; plus getBazaarPackageREADME, getUpdatedPackage, batchUpdatePackage |
/api/petal/* |
loadPetals, setPetalEnabled — plugin runtime |
/api/storage/* |
getLocalStorage, setLocalStorageVal, removeLocalStorageVals, criteria CRUD, recent-docs tracking, outline storage |
/api/setting/* |
setEditor, setExport, setFiletree, setSearch, setKeymap, setAppearance, setIcon, setTheme, setEmoji, setFlashcard, setAI, setBazaar, setPublish/getPublish, setSnippet, setEditorReadOnly, setAccount, virtual-block-ref include/exclude |
/api/ui/* |
reloadUI, reloadIcon, reloadTheme, reloadAttributeView, reloadProtyle, reloadFiletree, reloadTag |
/api/network/* |
forwardProxy (SSRF-guarded), echo |
/api/notification/* |
pushMsg, pushErrMsg |
/api/broadcast/*, /ws/broadcast, /es/broadcast/subscribe |
Pub/sub broadcast channels (publish, postMessage, getChannels, getChannelInfo) |
Note
Deprecated endpoints are marked in
router.goand log a warning when used (thedeprecatedhandler announces a removal date of2026-06-30). Examples being phased out:/api/system/reloadUI(→/api/ui/reloadUI),/api/storage/setLocalStorage(→setLocalStorageVal),/api/attr/resetBlockAttrs(→setBlockAttrs),/api/filetree/refreshFiletree(→/api/system/rebuildDataIndex). Migrate off them.
12. WebSocket Command Channel
The editor uses /ws (melody) for realtime, bidirectional communication, distinct from the REST API.
- Max message size: 8 MiB.
- Handshake auth: On connect, the kernel verifies either a valid session (matching
AccessAuthCode) or a validX-Auth-Tokenrole (Administrator/Editor/Reader). The auth page keeps a special connection alive (?app=siyuan&id=auth&type=auth). - Message shape: clients send
{cmd, reqId, param}. The kernel builds acmd.Commandviacmd.NewCommand(cmdStr, reqId, param, session)and runscmd.Exec. Unknown commands returncan not find command [...]. - Read-only enforcement: Non-read commands are rejected when the kernel is read-only or the token role is Reader/Visitor.
- Push: The kernel registers each session in a push channel set and broadcasts progress/notification/reload events to connected UIs.
Tip
For integrations, prefer the REST API for discrete operations; the WebSocket is primarily the editor's live transaction/push channel.
13. WebDAV, CalDAV, and CardDAV
The kernel embeds standards-compliant DAV servers (all under CheckAuth + CheckAdminRole, with write methods blocked in read-only mode):
| Service | Path | Backend | Use |
|---|---|---|---|
| WebDAV | /webdav/* |
golang.org/x/net/webdav over the workspace dir |
Mount your workspace as a network drive |
| CalDAV | /caldav/*, /.well-known/caldav |
emersion/go-webdav/caldav + SiYuan backend |
Expose reminders/dates as calendars |
| CardDAV | /carddav/*, /.well-known/carddav |
emersion/go-webdav/carddav + SiYuan backend |
Expose contacts |
Each DAV family advertises its extended method set (PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, etc.) via CORS and gin Match.
Note
A known limitation: the CardDAV backend can't yet satisfy Thunderbird's
PROPFINDwithcurrent-user-privilege-set.
14. Data Model and Storage
14.1 On-disk
- Documents are
.syJSON files (a serialized block tree,kernel/filesys). - Workspace layout:
data/(notebooks +assets/ emojis/ snippets/ storage/ templates/ widgets/ plugins/ public/),conf/,history/,repo/,temp/(logs attemp/siyuan.log). - Notebooks carry
.siyuan/conf.json(BoxConf).
14.2 Indexes (SQLite)
Three SQLite databases are initialized at boot (kernel/sql): the main block index, the history index, and the asset-content index (for searching inside attachments). The block index is the backing store for full-text search and /api/query/sql. Blocks carry type, content, attributes (IAL), and relationships. The block tree is also indexed in kernel/treenode.
Important
The
.syfiles are the source of truth; the SQLite indexes are derived and can be rebuilt (/api/system/rebuildDataIndex,vacuumDataIndex). If search behaves oddly after manual file changes, rebuild the index.
14.3 Block IDs
Every block has a stable unique ID. References, embeds, attributes, flashcards, and the index point at IDs, which is why content can move freely without breaking links.
15. Synchronization and the Data Repo
Sync is built on dejavu, a content-addressed, encrypted, versioned data repo (analogous to a Git-like object store), stored in workspace/repo/.
15.1 Repo key
Before sync/snapshots, initialize an AES repo key (/api/repo/initRepoKey or initRepoKeyFromPassphrase). Data is encrypted with this key before upload. The same key must be set on every device (importRepoKey). Losing it (with inconsistent device keys) requires a repo reset.
15.2 Providers
Conf.Sync.Provider: 0 SiYuan Cloud (membership), 2 S3, 3 WebDAV, 4 local file system. Each has its own config block (endpoint, credentials, timeout, concurrency, TLS-verify, path-style for S3). Sync modes: 1 auto (interval, default 30s), 2 manual, 3 fully manual.
15.3 Snapshots
Independent of cloud sync: create/tag/diff/checkout snapshots and roll back individual files or whole snapshots. Auto-purge keeps indexRetentionDays (180) of indexes and retentionIndexesDaily (2) per day.
Caution
Never place the workspace inside a third-party file-sync disk (Dropbox/OneDrive/etc.) — concurrent file syncing races with the kernel and can corrupt data. Use SiYuan's own sync to S3/WebDAV/Cloud instead.
16. Deployment
16.1 Docker
docker run -d \
-v /siyuan/workspace:/siyuan/workspace \
-p 6806:6806 \
-e PUID=1000 -e PGID=1000 \
b3log/siyuan \
--workspace=/siyuan/workspace/ \
--accessAuthCode=please-change-me
The image entrypoint (kernel/entrypoint.sh) creates a user/group from PUID/PGID, fixes ownership of /opt/siyuan, /home/siyuan, and the workspace, then runs the kernel as that user. The program lives under /opt/siyuan/ (appearance/, guide/, stage/, kernel).
Docker Compose
services:
main:
image: b3log/siyuan
command: ['--workspace=/siyuan/workspace/', '--accessAuthCode=${AuthCode}']
ports:
- 6806:6806
volumes:
- /siyuan/workspace:/siyuan/workspace
restart: unless-stopped
environment:
- TZ=${YOUR_TIME_ZONE}
- PUID=${YOUR_USER_PUID}
- PGID=${YOUR_USER_PGID}
Reverse proxy: To hide port 6806 behind NGINX, you must proxy the WebSocket at /ws, and you should not use URL rewriting/redirects (they break authentication) — configure a straight reverse proxy.
Warning
Docker/browser limitations (by design): no desktop/mobile app connections (browser only), no PDF/HTML/Word export, no Markdown import.
16.2 Unraid / TrueNAS
Both are supported via the same image; set ownership of the appdata/dataset folder to your PUID:PGID first (e.g. chown -R 1000:1000 ...), then map port 6806 and pass --accessAuthCode. See the project README for ready-made templates.
16.3 Desktop packaging
electron-builder produces per-platform/arch artifacts via the dist-* scripts and electron-builder*.yml configs (base, arm64, darwin, darwin-arm64, linux, linux-arm64). The Electron app uses @electron/remote and disables web security in the renderer because it loads the UI from the local kernel over http://127.0.0.1:<port>.
17. The Publish Service
When Conf.Publish.Enable is on, the kernel runs a separate publish service (default port 6808, kernel/server/proxy.InitPublishService) that exposes selected documents publicly. It supports HTTP Basic auth (Publish.Auth.Enable, default on) with a list of {username, password, memo} accounts. Combine with per-document publish access controls so only intended content is reachable.
Caution
The publish service makes content reachable without the main access auth code. Keep Basic auth enabled, use strong credentials, and front it with TLS if exposed beyond your LAN.
18. Operations
18.1 Health and status
- Boot progress:
GET /api/system/bootProgress. - Version:
GET /api/system/version. - Logs:
workspace/temp/siyuan.log(export via/api/system/exportLog). - Port discovery:
~/.config/siyuan/port.json(PID → port).
18.2 Scheduled jobs
kernel/job starts a cron (job.StartCron) at boot; model.AutoGenerateFileHistory and watchers run in the background. File history is generated on Editor.GenerateHistoryInterval (default 10 min) and retained for historyRetentionDays (30).
18.3 Index maintenance
| Operation | Endpoint |
|---|---|
| Rebuild block index | POST /api/system/rebuildDataIndex |
| Vacuum index | POST /api/system/vacuumDataIndex |
| Reindex asset content | POST /api/asset/fullReindexAssetContent |
| Reindex history | POST /api/history/reindexHistory |
| Clear temp files | POST /api/system/clearTempFiles |
18.4 Backup & restore
- Export/Import Data:
/api/export/exportData(+exportDataInFolder) and/api/import/importData. - Snapshots:
/api/repo/createSnapshot+tagSnapshot; restore viacheckoutRepoorrollbackRepoSnapshotFile. - Filesystem: copy
workspace/data/while the kernel is stopped.
18.5 Shutdown
POST /api/system/exit (desktop) or stop the container/process. The kernel handles OS signals (model.HandleSignal) to flush and release the workspace lock cleanly.
19. Performance Tuning
| Lever | Where | Effect |
|---|---|---|
dynamicLoadBlocks (48–1024, default 192) |
Editor |
Blocks loaded per scroll chunk in big docs |
Search.limit (default 64) |
Search |
Cap on search results |
Sync concurrentReqs / timeout |
Sync.{s3,webdav,local} |
Throughput vs. server limits |
syncIndexTiming (12s) |
Repo |
When to warn about slow indexing → suggests purge |
indexRetentionDays / retentionIndexesDaily |
Repo |
Local repo size vs. history depth |
SIYUAN_PDF_ASSET_CONTENT_INDEX_MAX_SIZE |
env | Skip indexing huge PDFs |
Graph.maxBlocks (10240) |
Graph |
Graph render size |
ControlConcurrency |
server | Kernel API requests are serialized for consistency |
- The kernel uses worker pools (
panjf2000/ants) and in-process caches (ristretto,patrickmn/go-cache) for hot paths. - For very large workspaces, periodically vacuum the index and purge old repo indexes.
Tip
If indexing is slow (>12s), SiYuan prompts to purge the data repo, which compacts local indexes and usually restores responsiveness.
20. Security Hardening Checklist
- [ ] Set a strong access auth code (
--accessAuthCode/SIYUAN_ACCESS_AUTH_CODE); never leave it blank on a networked instance. - [ ] Never set
SIYUAN_ACCESS_AUTH_CODE_BYPASS=trueon anything reachable by others. - [ ] Keep the kernel bound to
127.0.0.1unless you intentionally enablenetworkServe. - [ ] Front any LAN/internet exposure with a reverse proxy terminating TLS; proxy
/ws; avoid URL rewrites. - [ ] Treat the API token (
Conf.API.Token) as a secret; rotate via/api/system/setAPIToken. - [ ] Enable HTTPS (
networkServeTLS) for direct network serving; distribute the CA viaexportTLSCACert. - [ ] Leave SVG/HTML block scripts disabled (
AllowSVGScript/AllowHTMLBLockScript = false) unless you fully trust all content. - [ ] On the publish service, keep Basic auth on with strong credentials; scope per-document publish access.
- [ ] Only install plugins/snippets from trusted sources (they run with app privileges).
- [ ] Back up the repo key; use a passphrase-derived key for portability.
- [ ] For Docker, align
PUID/PGIDwith volume ownership; don't expose port 6806 directly to the internet.
21. Extensibility: Plugins, Widgets, and the Bazaar
- Plugins use the petal API; they're loaded via
/api/petal/loadPetalsand toggled withsetPetalEnabled. Globally disable the plugin system withBazaar.PetalDisabled(or per-plugin). Installed plugins live indata/plugins/and are served (auth-gated) under/plugins/. - Widgets are embeddable mini-apps under
data/widgets/, served under/widgets/. - Themes/Icons/Templates install into the appearance/
data/templatesfolders; the marketplace (kernel/bazaar) fetches packages and READMEs (rendered with Lute), with batch-update support. - Snippets (JS/CSS) provide lightweight customization without packaging a plugin; managed via
/api/snippet/*and served under/snippets/(the snippetconf.jsonrequires admin role).
Important
Plugins and JS snippets execute with the app's privileges. For managed/shared deployments, treat the installed-plugin set and snippet list as a code allowlist and review them.
22. Code Quality and Conventions
- Polyglot monorepo: Go kernel (
kernel/) + TypeScript UI (app/), each with its own build toolchain. - Router as source of truth:
kernel/api/router.gois the single authoritative endpoint registry; handlers live one-per-domain inkernel/api/*.goand delegate tokernel/model. - Config-as-structs: each
kernel/conf/*.gostruct owns one concern, with JSON tags andNewX()defaults — a clean, discoverable config surface. - Vendored renderers: heavy client-side renderers (KaTeX, Mermaid, ECharts, PDF.js, Graphviz, PlantUML, abcjs, highlight.js) are vendored under
app/stage/protyle/js/rather than npm-bundled. - First-party ecosystem: core capabilities are split into sibling repos the kernel imports —
lute(Markdown),dejavu(repo/sync),riff(FSRS),httpclient,filelock,encryption,logging— keeping the main repo focused. - Forked dependencies:
go.modreplaces pin a custom SQLite driver and pdfcpu fork. - Internationalization-first: source comments are predominantly Chinese; UI strings live in
app/appearance/langs/with English fallback fill-in at serve time. - Deprecation discipline: deprecated endpoints are explicitly flagged with a removal date and a migration target in
router.go.
23. Potential Improvements
Observations for maintainers and contributors, grounded in the source and community issues:
- API method semantics: nearly all endpoints are registered as
POSTregardless of read/write nature; adoptingGETfor read-only endpoints would improve cacheability and REST conventions (some read endpoints already acceptGET). - CORS breadth:
Access-Control-Allow-Origin: *with credentials relies entirely on token/auth-code secrecy. A configurable origin allowlist would reduce CSRF surface for networked deployments. - Deprecated-endpoint cleanup: several endpoints are slated for removal (2026-06-30); ensure plugins/integrations migrate (
reloadUI,setLocalStorage,resetBlockAttrs,refreshFiletree). - Community-requested features (open issues): a first-class CLI (#17674), MCP (Model Context Protocol) support (#13795), an AI agent (#17797), semantic search via embeddings (#17788), and a refreshed settings UI (#17601).
- Docker feature parity: documenting clearly (and, where feasible, closing) the export/import gaps in the headless deployment would reduce confusion.
- CardDAV completeness: handle Thunderbird's
current-user-privilege-setPROPFIND.
24. Troubleshooting
Error: boot kernel failed / exits with unavailable-port code
- Cause: The chosen port is in use, or the kernel can't bind.
- Solution: Check
port.jsonand free the port, or pass a different--port. Inspecttemp/siyuan.log.
Symptom: "The workspace is locked"
- Cause: Another kernel holds the workspace lock.
- Solution: Kill the
SiYuan-Kernelprocess (or restart the OS); ensure only one kernel uses a workspace.
Symptom: Database/index errors at boot ("database is unavailable")
- Cause: Corrupt or unreadable SQLite index, or insufficient permissions.
- Solution: Verify workspace permissions and disk space; rebuild via
/api/system/rebuildDataIndexonce booted. Your.syfiles remain intact.
Error: S3 sync put chunk failed:
- Cause: Wrong endpoint/region/keys/bucket or TLS/path-style mismatch.
- Solution: Re-verify
Sync.s3settings; trypathStyle/skipTlsVerify; confirm write permissions on the bucket.
Error: ip address [%s] is prohibited
- Cause: The forward-proxy/echo endpoint blocked a request to a disallowed IP (SSRF guard).
- Solution: Expected for private/blocked targets; route legitimate external requests through an allowed host.
Error: not found executable pandoc
- Cause: A Pandoc-dependent export with no Pandoc available (headless/Docker or bad
pandocBin). - Solution: Use the desktop app or set a valid
Export.PandocBin.
Error: require upgrade SiYuan to use this plugin [...]
- Cause: Plugin needs a newer kernel.
- Solution: Update SiYuan.
Error: TLS errors (failed to decode CA certificate PEM, the provided certificate is not a CA certificate)
- Cause: Importing an invalid TLS CA bundle.
- Solution: Provide a valid PEM CA cert+key; regenerate via
exportTLSCACertif unsure.
Symptom: Reverse proxy works for pages but realtime updates are broken
- Cause:
/wsWebSocket isn't proxied (or URL rewriting interferes with auth). - Solution: Add an explicit WebSocket proxy for
/ws; remove rewrite rules.
25. Quick Reference
25.1 Ports & paths
| Item | Value |
|---|---|
| Kernel HTTP/WS | 6806 (default; --port 0 picks free) |
| Publish service | 6808 |
| Bind | 127.0.0.1 (or 0.0.0.0 with networkServe/Docker) |
| Port discovery file | ~/.config/siyuan/port.json |
| Default workspace | ~/SiYuan/ |
| Log | workspace/temp/siyuan.log |
| Config | workspace/conf/conf.json |
| Data repo | workspace/repo/ |
25.2 Kernel flags
--workspace --wd --port --readonly --accessAuthCode --ssl --lang --mode
25.3 Auth model
| Layer | Mechanism |
|---|---|
| Access auth code | Session password (/check-auth) |
| API token | X-Auth-Token (JWT; Conf.API.Token) |
| Roles | Administrator / Editor / Reader / Visitor |
| Middleware | CheckAuth → CheckAdminRole → CheckReadonly |
25.4 Key API entry points
| Need | Endpoint |
|---|---|
| List notebooks | POST /api/notebook/lsNotebooks |
| Create doc from MD | POST /api/filetree/createDocWithMd |
| Insert/update/delete block | POST /api/block/{insert,update,delete}Block |
| Batched edit | POST /api/transactions |
| SQL query | POST /api/query/sql |
| Full-text search | POST /api/search/fullTextSearchBlock |
| Export Markdown | POST /api/export/exportMd |
| Trigger sync | POST /api/sync/performSync |
| Get config | POST /api/system/getConf |
25.5 Core dependencies
| Library | Role |
|---|---|
gin-gonic/gin, olahol/melody |
HTTP / WebSocket |
88250/lute |
Markdown engine |
mattn/go-sqlite3 (88250 fork) |
Block index |
siyuan-note/dejavu |
Encrypted data repo / sync |
siyuan-note/riff + open-spaced-repetition/go-fsrs |
Flashcards |
aws-sdk-go-v2/s3, studio-b12/gowebdav, emersion/go-webdav |
Sync, CalDAV/CardDAV |
klippa-app/go-pdfium, pdfcpu (88250 fork) |
|
otiai10/gosseract |
OCR (Tesseract) |
sashabaranov/go-openai |
AI |
golang-jwt/jwt, gin-contrib/sessions, steambap/captcha |
Auth |
xuri/excelize |
Spreadsheet export |