Establishes version control for the personal Logseq DB fork before starting the server-client architecture migration and domain features described in docs/agent-guide and the approved implementation plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
36 KiB
Logseq CLI (Node)
The Logseq CLI is a Node.js program built from the cli/ Dune, Melange, and Vite runtime. It connects to a ClojureScript db-worker-node server managed by the CLI. When installed, the CLI binary name is logseq.
Build the CLI
pnpm cli:release
pnpm db-worker-node:release:bundle
pnpm cli:release bundles the cli/ runtime and stages it to static/logseq-cli.js, which is the stable local, npm package, and desktop packaging runtime path.
pnpm db-worker-node:release:bundle compiles and bundles db-worker-node with Vite, and writes a standalone runtime to dist/db-worker-node.js plus an asset manifest at dist/db-worker-node-assets.json (which may contain an empty assets array when no extra files are required).
db-worker-node lifecycle
logseq manages db-worker-node automatically. You should not start the server manually. The server binds to localhost on a random port and records that port in the repo lock file.
Desktop + CLI shared semantics:
- Electron desktop and CLI are expected to use the same
db-worker-nodeand lock-file protocol for a graph. - Disk SQLite under
~/logseq/graphsis the source of truth; OPFS periodic export is not part of the desktop primary write path. - If a daemon already exists for the graph and reports the same revision as the requester, CLI reuses it via lock-file discovery instead of starting a second writer.
- If the discovered daemon reports a different revision, startup stops that exact server, starts a replacement from the requester's bundled runtime, and only returns a usable endpoint after the replacement reports the expected revision.
- A proven revision mismatch may be stopped across owner sources for the same repo/root-dir. Matching-revision servers keep the normal owner boundary.
- If lock ownership is invalid or stale, startup cleans stale lock state before retrying.
- Lock metadata includes an
owner-sourcevalue (cli,electron,unknown) and lifecycle actions enforce owner boundaries. server stopandserver restartare owner-aware: CLI can only stop/restart servers it owns (or legacyunknownownership).- If lock is missing but a matching orphan
db-worker-nodeprocess still exists for the same repo/root-dir, startup performs orphan cleanup before retrying.
Run the CLI
node ./dist/logseq.js graph list
You can also use npm link to make ./dist/logseq.js globally available, run:
npm link
If installed(or linked) globally, run:
logseq graph list
Configuration
The CLI config file defaults to <root-dir>/cli.edn, where root-dir defaults to ~/logseq.
Supported keys include:
:graph- The current active graph. Set this withgraph switch.:root-dir- CLI root directory. Default is~/logseq.- Graph data directory is derived as
<root-dir>/graphs. - Config file default is derived as
<root-dir>/cli.edn. - Server list file default is derived as
<root-dir>/server-list. - Graph directories under
<root-dir>/graphsare user-facing graph names e.g.demoand do not start withlogseq_db_.
- Graph data directory is derived as
:output-format- Format for output. Default is:human. Use:jsonor:ednfor scripting.:list-title-max-display-width- For:humanoutput, the max display width for TITLE column, defaulting to40.:http-base- Http base domain for sync service. Interact with this viasync config.:ws-url- Websocket url for sync service. Interact with this viasync config.:timeout-ms- Request timeout in milliseconds.:login-timeout-ms- Login callback timeout. Defaults to 5 minutes.:logout-timeout-ms- Logout callback timeout. Defaults to 2 minutes.:custom-queries- Map of custom queries which are run withquery --name. See below for more.
CLI global flags take precedence over environment variables, which take precedence over the config file. Here is a mapping of these three:
| Config key | Environment variable | Global flag |
|---|---|---|
| :graph | $LOGSEQ_CLI_GRAPH | --graph |
| :root-dir | $LOGSEQ_CLI_ROOT_DIR | --root-dir |
| :output-format | $LOGSEQ_CLI_OUTPUT | --output |
| :timeout-ms | $LOGSEQ_CLI_TIMEOUT_MS | --timeout-ms |
| :login-timeout-ms | $LOGSEQ_CLI_LOGIN_TIMEOUT_MS | n/a |
| :logout-timeout-ms | $LOGSEQ_CLI_LOGOUT_TIMEOUT_MS | n/a |
Legacy notes:
- Migration note: If you previously used
~/.logseq/cli-graphsor~/.logseq/cli.edn, pass--root-dirand/or--configto continue using equivalent custom locations. :e2ee-passwordincli.ednis ignored and removed silently during config read/update. Usesync start --e2ee-passwordorsync download --e2ee-passwordinstead.cli.ednno longer persists cloud auth tokens. CLI login state is stored separately in~/logseq/auth.json.
Custom Queries
Custom queries are defined in :custom-queries of a config file. This config is a map with the key as a query name and the value as a map with the following keys:
:query- Required datalog query as a vector. Queries can use built-in rules fromlogseq.db.frontend.rulesby appending%to the:inpart of a query. Seelogseq.cli.command.queryfor example queries.:doc- Optional doc string describing the query.:inputs- Optional vector of inputs where each input is a map. Valid keys for the map are:nameand:default. This defines positional arguments to a query e.g. the arguments a user passes map to these inputs and the:inbindings in a:query.
Authentication
Use logseq login to authenticate the current machine with Logseq cloud.
logseq loginstarts a temporary callback server athttp://localhost:8765/auth/callback, opens a browser to the Logseq Cognito Hosted UI, exchanges the returned authorization code, and writes~/logseq/auth.json.logseq logoutremoves~/logseq/auth.json, opens a browser to the Cognito Hosted UI logout endpoint, and completes the browser logout flow athttp://localhost:8765/logout-complete.- Sync commands still pass an in-memory runtime
:auth-tokento db-sync, but that token is now resolved fromauth.jsoninstead ofcli.edn.
Default auth file: ~/logseq/auth.json
Auth file contents include the persisted Cognito id-token, access-token, refresh-token, expires-at, sub, email, and updated-at values needed for headless refresh.
Verbose logging:
--verboseenables structured debug logs to stderr for CLI option parsing and db-worker-node API calls.sync downloadcan stream realtime progress lines to stdout when progress is enabled; debug previews remain truncated.
Timeouts:
--timeout-mscontinues to control request timeout behavior for CLI transport.- Login callback timeout is controlled separately by
:login-timeout-ms/LOGSEQ_CLI_LOGIN_TIMEOUT_MSand defaults to 5 minutes. - Logout callback timeout is controlled separately by
:logout-timeout-ms/LOGSEQ_CLI_LOGOUT_TIMEOUT_MSand defaults to 2 minutes.
Commands
Graph commands:
graph list- list all db graphsgraph create --graph <name>- create a new db graph and switch to it- Fails with
graph-existsif a local graph with the same name already exists --enable-synccreates the graph, switches to it, uploads it to Logseq Sync, and starts sync in one command--e2ee-password <password>is accepted only with--enable-syncand uses the same password verification path assync uploadandsync start
- Fails with
graph switch --graph <name>- switch current graphgraph remove --graph <name>- remove a graphgraph validate --graph <name>- validate graph datagraph info [--graph <name>]- show graph metadata (defaults to current graph)graph export --type edn|sqlite --file <path> [--graph <name>]- export a graph to EDN or SQLite- EDN export also accepts
--edn-options/-e <edn-map>and--pretty-print/-p --edn-optionsis an EDN map;:export-type(if present) overrides the default:graph, and every other key is forwarded to the worker as:graph-options(for example,'{:export-type :graph-human :include-timestamps? true :exclude-built-in-pages? true :exclude-namespaces #{:user :project}}')--pretty-printwrites the EDN file throughclojure.pprintfor readability while remaining round-trippable viagraph import --type edn- SQLite export writes the snapshot directly to the destination path through
db-worker-nodeinstead of round-tripping a base64 payload through the CLI --edn-optionsand--pretty-printare rejected when--type sqliteis selected; a non-map value for--edn-optionsis also rejected
- EDN export also accepts
graph import --type edn|sqlite --input <path> --graph <name>- import a graph from EDN or SQLite; SQLite import requires a new graph, while EDN import may target an existing graphgraph backup list- list backup snapshots under<root-dir>/graphs/<graph>/backupgraph backup create [--graph <name>] [--name <label>]- create a backup snapshot for the selected graphgraph backup restore --src <backup-name> --dst <graph-name>- restore one backup snapshot into a graph; the current command does not reject an existing destination graphgraph backup remove --src <backup-name>- delete one backup snapshot
For any command that requires --graph, if the target graph does not exist, the CLI returns graph not exists (except for graph create). SQLite graph import fails if the target graph already exists; EDN import and graph backup restore do not currently share that top-level preflight.
Backup scope note:
graph backup createcopies onlydb.sqlite.search-db.sqliteandclient-ops-db.sqliteare intentionally excluded.- Desktop graph backups use the same
<root-dir>/graphs/<graph>/backup/<backup-name>/db.sqlitelayout, so the CLI can list, restore, and remove Desktop-created graph backups when it uses the same root directory.
Server commands:
server list- list running db-worker-node serversserver cleanup- manually terminate revision-mismatched CLI-owned db-worker-node servers discovered from lock files in the current root-dirserver start --graph <name>- start db-worker-node for a graphserver stop --graph <name>- stop db-worker-node for a graphserver restart --graph <name>- restart db-worker-node for a graphdoctor [--dev-script]- run runtime diagnostics fordb-worker-node.js,root-dirpermissions, and running server readiness (--dev-scriptchecksstatic/db-worker-node.jsexplicitly)
Auth commands:
login- authenticate this machine and create/update~/logseq/auth.jsonlogout- remove persisted CLI auth from~/logseq/auth.json
Debug commands:
debug pull --id <db-id> [--graph <name>]- pull a raw entity by db id with selector[*]debug pull --uuid <uuid> [--graph <name>]- pull a raw entity by block UUID lookupdebug pull --ident <db-ident> [--graph <name>]- pull a raw entity by:db/identlookup--identmust be a strict EDN keyword (for example:logseq.class/Tag)- exactly one of
--id,--uuid, or--identis required - if
--graphis omitted, CLI falls back to current graph config
Utility commands:
completion <zsh|bash>- generate shell completion script to stdoutexample <command-or-prefix...>- show runnable command examples for a command path or command prefix (phase 1 covers Graph Inspect and Edit commands)- exact selector example:
logseq example upsert page - prefix selector example:
logseq example upsert
- exact selector example:
skill show- print built-inlogseq-cliskill markdown to stdout- always prints raw markdown text, even when
--output jsonor--output ednis set
- always prints raw markdown text, even when
skill install- install built-in skill to./.agents/skills/logseq-cli/SKILL.mdskill install --global- install built-in skill to~/.agents/skills/logseq-cli/SKILL.md
Setup for zsh (add to ~/.zshrc):
autoload -Uz compinit && compinit
eval "$(logseq completion zsh)"
Setup for bash (add to ~/.bashrc):
eval "$(logseq completion bash)"
Skill command examples:
# Print markdown content to stdout
logseq skill show
# Install for current working directory
logseq skill install
# Install for current user home directory
logseq skill install --global
Server ownership behavior:
server stopandserver restartcan returnserver-owned-by-otherif the daemon was started by another owner source.server startcan returnserver-start-timeout-orphanwhen lock creation times out and orphan matching processes are detected.- Normal connection startup compares the discovered server revision with the local requester revision. Missing revision is treated as mismatch.
- On revision mismatch, startup attempts one graceful-first restart of the exact discovered server for the same repo/root-dir, even if the stale server has a different owner source. If the replacement still reports a different revision, startup fails fast and does not return an incompatible endpoint.
- Manual
server stopandserver restartkeep owner protections; cross-owner stop is only used by the automatic revision-mismatch startup path after the target mismatch is proven. server listhuman output includes bothOWNERandREVISIONcolumns.server listprints a compatibility warning in human output when any server revision string is not exactly equal to the local CLI revision string.server cleanupremains a manual maintenance command. It checks discovered servers in the current root-dir, treatsrevision != local CLI revision(including missing revision) as mismatch, and attempts graceful-first termination only for:owner-source :clitargets.server cleanupstructured output includeschecked,mismatched,eligible,skipped-owner,killed, andfailedsummaries.- Structured output (
--output json|edn) includes per-serverrevisiondata but does not include human warning text.
Sync commands:
sync status --graph <name>- show db-sync runtime state for a graph daemonsync start --graph <name> [--e2ee-password <password>]- start db-sync websocket client for a graphsync stop --graph <name>- stop db-sync client on a graph daemonsync upload --graph <name>- upload local graph snapshot to remotesync download --graph <name> [--progress true|false] [--e2ee-password <password>]- download remote graph<name>into a same-name local graph directorysync asset download --graph <name> --id <asset-db-id>- request one remote asset download by theIDshown bylist assetsync asset download --graph <name> --uuid <asset-uuid>- request one remote asset download by asset block UUIDsync remote-graphs [--graph <name>]- list remote graphs visible to the current login contextsync ensure-keys [--graph <name>]- ensure user RSA keys for sync/e2eesync grant-access --graph <name> --graph-id <uuid> --email <email>- grant encrypted graph access to a usersync config set [--graph <name>] ws-url|http-base <value>- set non-auth db-sync runtime config keysync config get [--graph <name>] ws-url|http-base- get non-auth db-sync runtime config keysync config unset [--graph <name>] ws-url|http-base- remove non-auth db-sync runtime config key
Sync start behavior:
sync start --e2ee-password <password>verifies the password against user encrypted private key before persisting it.- Verification and persistence run in worker-side sync crypt logic (shared with desktop/web interaction paths).
- Wrong
--e2ee-passwordfails fast and does not overwrite a previously stored encrypted password payload.
Sync upload behavior:
sync uploadrequires--graph <name>.- The CLI starts or reuses that graph's
db-worker-node, applies the current sync config, and uploads the local snapshot only after the worker has resolved a usable remote graph id. - If the local graph already has sync metadata, upload reuses the stored remote
graph-id. - If the local graph does not have a stored remote
graph-id, upload first lists visible remote graphs and reuses an exact same-name match when one exists. - If no same-name remote graph exists, upload creates a new remote graph and persists the returned remote metadata locally before snapshot transfer.
- Successful upload persists graph identity metadata locally in both client-op state and graph KV (
logseq.kv/graph-uuid,logseq.kv/graph-remote?, andlogseq.kv/graph-rtc-e2ee?) so CLI and web upload/bootstrap flows stay aligned. - Fresh uploads default to encrypted remote graph creation unless local sync metadata explicitly marks the graph as non-e2ee. In headless CLI mode, run
logseq loginfirst so refresh-token based E2EE password persistence can be used by follow-upsync start/sync downloadflows. sync uploadreturns a real error instead of false success when login state, remote graph bootstrap, or snapshot upload fails.- Common upload failures include missing/invalid CLI login state, missing
http-base, remote graph creation failure, snapshot upload failure, and local DB/worker startup failure. - Troubleshooting: after a successful upload, run
graph info --graph <name> --output jsonand confirmdata.kv.logseq.kv/graph-uuidis present. If it is missing, rerunsync uploadfor the same graph to trigger identity backfill.
Sync download behavior:
sync downloadrequires--graph <name>.- If a local graph with the same name already exists, the CLI returns
graph-exists. - If no remote graph with that name exists, the CLI returns
remote-graph-not-found. sync downloadstartsdb-worker-nodein create-empty mode so local startup does not writedb-initial-databefore snapshot import.- The final snapshot download/import invoke uses a command-specific long-running timeout (30 minutes by default) rather than the generic short-request timeout path.
- Progress streaming uses db-worker-node SSE
/v1/eventsand shared:rtc.log/downloadevents. --progressdefaults totruefor human output.- For structured output (
--output json|edn), progress is auto-disabled unless explicitly overridden with--progress true. --progress falsealways suppresses progress streaming.- If the target graph DB is not empty at download time, the CLI returns
graph-db-not-emptyand aborts before import. - For e2ee remote graphs, provide
--e2ee-passwordonsync download(or persist once viasync start --e2ee-password). - If e2ee password is required but missing,
sync start,sync download, andsync statusreturne2ee-password-not-foundwith a hint to provide--e2ee-password.
Sync asset download behavior:
sync asset downloadrequires--graphand exactly one of--idor--uuid.--idselects the asset node by the Datascript db/id shown asIDinlist assethuman output.--uuidselects the asset block UUID for scripts that already track UUIDs.- The command requires sync to already be running for the graph. If the graph's sync client is not active, it returns
sync-not-startedwith a hint to runlogseq sync start --graph <name>first. - The command uses the existing worker asset request API (
:thread-api/db-sync-request-asset-download) and returns immediately after the worker accepts the enqueue request. - Before enqueueing, the CLI checks the local
assets/<asset-uuid>.<asset-type>file. If the file exists and its checksum matches asset metadata, the command reportsdownload-requested? falseand skips the request. - If the local file exists but its checksum mismatches, the command reports
checksum-status mismatch, prints a mismatch hint in human output, and requests a re-download. - The first version does not accept
--e2ee-password; persist E2EE password state with existingsync startorsync downloadflows before requesting asset download. - Structured output includes asset identity and status fields such as
asset-id,asset-uuid,asset-type,download-requested?,checksum-status,skipped-reason, andhintwhen applicable. It intentionally omits local filesystem paths.
Sync config persistence:
sync config set/unsetwrites non-auth sync config to the CLI config file selected by--config.- If
--configis not provided, the default config path is~/logseq/cli.edn. sync config getreads from that same config source.:e2ee-passwordis not part of sync config and is silently ignored when found in legacycli.edn.- Cloud auth is persisted separately in
~/logseq/auth.json.
E2EE password persistence locations:
- Browser runtime stores the refresh-token-encrypted password payload in its platform secret storage.
- Node runtime prefers the OS keychain under the
Logseq E2EEservice. If keychain access fails, it falls back to<root-dir>/kv-store.json. CLI E2E mode uses the KV store directly.
Inspect and edit commands:
list page [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list pages (defaults to--sort updated-at --order desc)list tag [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list tags (defaults to--sort updated-at --order desc)list property [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list properties (defaults to--sort updated-at --order desc;TYPEandCARDINALITYare included by default even without--expand; missing schema cardinality is treated asone)list task [--status <status>] [--priority <low|medium|high|urgent>] [-c|--content <text>] [--fields <csv>] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list task nodes tagged with#Task(supports both pages and blocks; defaults to--sort updated-at --order desc)--statusis validated at runtime using values from the current graph; invalid values return an error that includes available values from that graph.
list node [--tags <csv>] [--properties <csv>] [--fields <csv>] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list ordinary nodes (pages and blocks) filtered by tags/properties (supports selector forms id/uuid/ident/name; at least one of--tagsor--propertiesis required; defaults to--sort updated-at --order desc)--tagsand--propertiesuse all-of semantics, and when both are present they are combined with AND.- CSV tokens are trimmed and empty tokens are ignored; if a provided filter becomes empty after normalization, CLI returns
invalid-options.
list asset [--fields <csv>] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list nodes tagged with#Asset(:logseq.class/Asset; defaults to--sort updated-at --order desc)upsert block --content <text> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- create blocks; defaults to today’s journal page if no target is givenupsert block --blocks <edn> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- insert blocks via EDN vectorupsert block --blocks-file <path> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- insert blocks from an EDN fileupsert block --id <id>|--uuid <uuid> [--content <text>] [--target-id <id>|--target-uuid <uuid>|--target-page <name>] [--pos first-child|last-child|sibling] [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- update and/or move a block--statusis not supported onupsert block; useupsert task --status ...for task status updates.
upsert page --page <name> [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- create (or update by page name) a pageupsert page --id <id> [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- update a page by id (cannot be combined with--page)upsert task --content <text> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling] [--status <status>] [--priority <low|medium|high|urgent>] [--scheduled <datetime>] [--deadline <datetime>] [--no-status] [--no-priority] [--no-scheduled] [--no-deadline]- create a task block and ensure#Taskis attachedupsert task --page <name> [--status <status>] [--priority <low|medium|high|urgent>] [--scheduled <datetime>] [--deadline <datetime>] [--no-status] [--no-priority] [--no-scheduled] [--no-deadline]- create/update a task page and ensure#Taskis attachedupsert task --id <id>|--uuid <uuid> [--status <status>] [--priority <low|medium|high|urgent>] [--scheduled <datetime>] [--deadline <datetime>] [--no-status] [--no-priority] [--no-scheduled] [--no-deadline]- update an existing node and ensure#Taskis attached--statusis validated at runtime using values from the current graph; invalid values return an error that includes available values from that graph.- generic task tag/property mutation options are not supported on
upsert task; useupsert block --update-tags/--update-properties/--remove-tags/--remove-propertieswhen needed. - for the same field, set and clear options are mutually exclusive (for example:
--status todo --no-statusis invalid).
upsert asset --path <asset-file-path> [--content <text>] [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- create an asset node, add#Asset, set asset metadata (type,size,checksum), and copy the local file into graphassets/as<block-uuid>.<ext>upsert asset --id <id>|--uuid <uuid> [--content <text>]- update an existing asset node title; target node must be tagged with#Asset- create mode requires
--path; update mode rejects--path.
- create mode requires
upsert tag --name <name>- create or upsert a tag by nameupsert tag --id <id> [--name <name>]- validate a tag by id; when--nameis provided, rename that tag id (no-op if normalized name is unchanged)upsert tag --id <id> --name <name>conflicts: returnstag-name-conflictwhen target name is a non-tag page, andtag-rename-conflictwhen target name is another existing tagupsert property --name <name> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false]- create or update a property by nameupsert property --id <id> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false]- update a property by idmove --id <id>|--uuid <uuid> --target-id <id>|--target-uuid <uuid>|--target-page <name> [--pos first-child|last-child|sibling]- move a block and its children (defaults to first-child)remove --id <id>|--uuid <uuid>|--page <name>- remove blocks (by db/id or UUID) or pagessearch block --content <query>- search blocks by:block/title(case-insensitive substring)search page --content <query>- search pages by:block/name(case-insensitive substring)search property --content <query>- search properties by:block/title(Property entities only)search tag --content <query>- search tags by:block/title(Tag entities only)query --query <edn> [--inputs <edn-vector>]- run a Datascript query against the graphquery --name <query-name> [--inputs <edn-vector>]- run a named query (built-in or fromcli.edn)query list- list available named queriesshow --page <name> [--level <n>]- show page content tree- Use
--page-hierarchy trueto display child pages connected through page hierarchy instead of normal page content blocks.
- Use
show --uuid <uuid> [--level <n>]- show block treeshow --id <id> [--level <n>]- show block tree by db/id
Help output:
Subcommands:
list page [options] List pages
list tag [options] List tags
list property [options] List properties
list task [options] List tasks
list node [options] List nodes
list asset [options] List assets
upsert block [options] Upsert block
upsert page [options] Upsert page
upsert task [options] Upsert task
upsert asset [options] Upsert asset
upsert tag [options] Upsert tag
upsert property [options] Upsert property
move [options] Move block
remove [options] Remove block or page
search block [options] Search blocks by title
search page [options] Search pages by name
search property [options] Search properties by title
search tag [options] Search tags by title
show [options] Show tree
Options grouping:
- Help output separates Global options (apply to all commands) and Command options (command-specific flags).
Version output:
logseq --versionprints:
Build time: <timestamp>
Revision: <commit>
Output formats:
- Global
--output <human|json|edn>applies to all commands - Output formatting is controlled via global
--output,:output-formatin config, orLOGSEQ_CLI_OUTPUT. - Global
--profileenables stage timing output to stderr. This is for debugging latency and does not change command stdout payloads.- Human profile output is rendered as a tree (similar to
showoutput style). The elapsed time column is printed at the far left with fixed width for alignment, for example:146ms command=list status=ok stages 146ms └── cli.total 4ms ├── cli.parse-args 139ms └── cli.execute-action 129ms └── transport.invoke:thread-api/cli-list-pages
- Human profile output is rendered as a tree (similar to
- Human output is plain text. List/search commands render tables with a final
Count: Nline. For list and search subcommands, the ID column uses:db/id(not UUID). If:db/identexists, anIDENTcolumn is included.list propertyincludes dedicatedTYPEandCARDINALITYcolumns;list node/list assetinclude a dedicatedTYPEcolumn (page/block) and page context columns for blocks. Search table columns areIDandTITLE. Forlist page|tag|property|task|node|assetin human output, theTITLEcolumn is display-width-aware (CJK-safe), defaults to max width40, and truncates overflow with…; set:list-title-max-display-widthincli.ednto override. JSON/EDN outputs keep full titles (no truncation). Block titles can include multiple lines; multi-line rows align additional lines under theTITLEcolumn. Times such as listUPDATED-AT/CREATED-ATandgraph infoCreated atare shown in human-friendly relative form. Errors include error codes and may include aHint:line. Use--output json|ednfor structured output. examplehuman output includesSelector,Matched commands, andExamplessections. Structured output (json/edn) includesselector,matched-commands,examples, andmessagefields underdata.skill showalways prints raw markdown text to stdout, regardless of--outputmode.sync downloadprogress lines are streamed to stdout only when progress is enabled. Injson/ednmode, progress is disabled by default unless--progress trueis provided.- JSON machine output preserves namespaced keyword semantics:
- Namespaced keyword keys are emitted as canonical string keys in
namespace/nameform (for example:block/title->"block/title"). - Unqualified keyword keys remain plain strings (for example
:status->"status"). - Keyword values are emitted as strings with namespace text preserved when present (for example
:db.cardinality/one->"db.cardinality/one"). - UUID values are emitted as strings.
- Namespaced keyword keys are emitted as canonical string keys in
- For
list property,TYPEand cardinality are returned in default output (without--expand) for human and structured (json/edn) formats.- Human output renders cardinality as
oneormanyin theCARDINALITYcolumn. - JSON keeps namespaced key/value form via
"db/cardinality"and values like"db.cardinality/one"or"db.cardinality/many". - EDN keeps
:db/cardinality(for example:db.cardinality/oneor:db.cardinality/many). - When a property omits schema cardinality, CLI treats it as default
one.
- Human output renders cardinality as
JSON key migration (flat -> namespaced):
| Old JSON key path | New JSON key path |
|---|---|
data.items[].title |
data.items[].block/title |
data.items[].id |
data.items[].db/id |
data.items[].type |
data.items[].logseq.property/type |
data.items[].cardinality |
data.items[].db/cardinality |
data.root.children[] |
data.root.block/children[] |
upsert page,upsert block,upsert task, andupsert assetreturn entity ids indata.resultfor JSON/EDN output, and include ids in human output.- Human example:
Upserted page: [123] - Human example:
Upserted blocks: [201 202] - JSON example:
{"status":"ok","data":{"result":[123]}} - EDN example:
{:status :ok, :data {:result [123]}}
- Human example:
doctoroutput includes overall status (ok,warning,error) and per-check rows fordb-worker-script,data-dir,running-servers, andserver-revision-mismatch. For scripting,--output json|ednkeeps the structured check payload.- Common doctor failures and warnings:
doctor-script-missing:db-worker-node.jsruntime target is missing (default target:dist/db-worker-node.js; usedoctor --dev-scriptto checkstatic/db-worker-node.js).doctor-script-unreadable: script path exists but is not a readable file.data-dir-permission: configured data dir is not readable or writable.doctor-server-not-ready: one or more lock-discovered servers are still in:startingstate (warning).doctor-server-revision-mismatch: one or more discovered servers use a different revision than the local CLI revision (warning). Follow the printed remediation command for each affected graph:logseq server restart --graph <name>.- If bundled runtime startup fails with missing-module or missing-file errors, rebuild with
pnpm db-worker-node:release:bundleand confirmdist/db-worker-node.jsexists and every path listed indist/db-worker-node-assets.jsonis present next to it.
queryhuman output returns a plain string (the query result rendered viapr-str), which is convenient for pipelines likelogseq query ... | xargs logseq show --id.- Built-in named queries currently include
block-search,task-search,recent-updated,list-status, andlist-priority. Usequery listto see the full set for your config. - Show output resolves block reference UUIDs inside text, replacing
[[<uuid>]]with the referenced block content. Nested references are resolved recursively up to 10 levels to avoid excessive expansion. For example:[[<uuid1>]]→[[some text [[<uuid2>]]]]and then<uuid2>is also replaced. - When
showtargets an ordinary block (--idor--uuid), human output prepends one breadcrumb line (page > ... > nearest parent) above the root block line. Each segment is display-width truncated to24with….
Project Alpha > Milestone 2026 > API rollout
5137 Implement retry policy for upload worker
5138 ├── Add timeout backoff guard
5139 └── Add deterministic retry test
showtree lines print:db/idas the first column:
id1 block1
id2 ├── b2
id3 │ └── b3
id4 ├── b4
id5 │ ├── b5
id6 │ │ └── b6
id7 │ └── b7
id8 └── b8
Troubleshooting:
- If authenticated sync commands fail with missing or invalid local auth, run
logseq logoutand thenlogseq loginagain. - You can also manually remove
~/logseq/auth.jsonand repeatlogseq login.
Examples:
node ./dist/logseq.js login
node ./dist/logseq.js graph create --graph demo
node ./dist/logseq.js graph export --type edn --file /tmp/demo.edn --graph demo
node ./dist/logseq.js graph import --type edn --input /tmp/demo.edn --graph demo-import
node ./dist/logseq.js graph backup create --graph demo --name nightly
node ./dist/logseq.js graph backup list
node ./dist/logseq.js graph backup restore --src demo-nightly-20260101T000000Z --dst demo-restore
node ./dist/logseq.js graph backup remove --src demo-nightly-20260101T000000Z
node ./dist/logseq.js upsert block --target-page TestPage --content "hello world"
node ./dist/logseq.js move --uuid <uuid> --target-page TargetPage
node ./dist/logseq.js search block --content "hello"
node ./dist/logseq.js show --page TestPage --output json
node ./dist/logseq.js show --page Foo --page-hierarchy true
node ./dist/logseq.js debug pull --graph demo --ident :logseq.class/Tag --output json
node ./dist/logseq.js server list
node ./dist/logseq.js doctor
node ./dist/logseq.js doctor --dev-script
node ./dist/logseq.js doctor --output json
node ./dist/logseq.js --graph demo sync start --e2ee-password "my-secret"
node ./dist/logseq.js --graph demo sync download --e2ee-password "my-secret"
node ./dist/logseq.js logout