Files
Synapse/docs/cli/logseq-cli.md
Dasemu 40631362b3 Initial import of LogDarioSeq baseline
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>
2026-08-25 15:32:15 +02:00

36 KiB
Raw Permalink Blame History

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-node and lock-file protocol for a graph.
  • Disk SQLite under ~/logseq/graphs is 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-source value (cli, electron, unknown) and lifecycle actions enforce owner boundaries.
  • server stop and server restart are owner-aware: CLI can only stop/restart servers it owns (or legacy unknown ownership).
  • If lock is missing but a matching orphan db-worker-node process 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 with graph 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>/graphs are user-facing graph names e.g. demo and do not start with logseq_db_.
  • :output-format - Format for output. Default is :human. Use :json or :edn for scripting.
  • :list-title-max-display-width - For :human output, the max display width for TITLE column, defaulting to 40.
  • :http-base - Http base domain for sync service. Interact with this via sync config.
  • :ws-url - Websocket url for sync service. Interact with this via sync 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 with query --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-graphs or ~/.logseq/cli.edn, pass --root-dir and/or --config to continue using equivalent custom locations.
  • :e2ee-password in cli.edn is ignored and removed silently during config read/update. Use sync start --e2ee-password or sync download --e2ee-password instead.
  • cli.edn no 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 from logseq.db.frontend.rules by appending % to the :in part of a query. See logseq.cli.command.query for 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 :name and :default. This defines positional arguments to a query e.g. the arguments a user passes map to these inputs and the :in bindings in a :query.

Authentication

Use logseq login to authenticate the current machine with Logseq cloud.

  • logseq login starts a temporary callback server at http://localhost:8765/auth/callback, opens a browser to the Logseq Cognito Hosted UI, exchanges the returned authorization code, and writes ~/logseq/auth.json.
  • logseq logout removes ~/logseq/auth.json, opens a browser to the Cognito Hosted UI logout endpoint, and completes the browser logout flow at http://localhost:8765/logout-complete.
  • Sync commands still pass an in-memory runtime :auth-token to db-sync, but that token is now resolved from auth.json instead of cli.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:

  • --verbose enables structured debug logs to stderr for CLI option parsing and db-worker-node API calls.
  • sync download can stream realtime progress lines to stdout when progress is enabled; debug previews remain truncated.

Timeouts:

  • --timeout-ms continues to control request timeout behavior for CLI transport.
  • Login callback timeout is controlled separately by :login-timeout-ms / LOGSEQ_CLI_LOGIN_TIMEOUT_MS and defaults to 5 minutes.
  • Logout callback timeout is controlled separately by :logout-timeout-ms / LOGSEQ_CLI_LOGOUT_TIMEOUT_MS and defaults to 2 minutes.

Commands

Graph commands:

  • graph list - list all db graphs
  • graph create --graph <name> - create a new db graph and switch to it
    • Fails with graph-exists if a local graph with the same name already exists
    • --enable-sync creates the graph, switches to it, uploads it to Logseq Sync, and starts sync in one command
    • --e2ee-password <password> is accepted only with --enable-sync and uses the same password verification path as sync upload and sync start
  • graph switch --graph <name> - switch current graph
  • graph remove --graph <name> - remove a graph
  • graph validate --graph <name> - validate graph data
  • graph 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-options is 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-print writes the EDN file through clojure.pprint for readability while remaining round-trippable via graph import --type edn
    • SQLite export writes the snapshot directly to the destination path through db-worker-node instead of round-tripping a base64 payload through the CLI
    • --edn-options and --pretty-print are rejected when --type sqlite is selected; a non-map value for --edn-options is also rejected
  • 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 graph
  • graph backup list - list backup snapshots under <root-dir>/graphs/<graph>/backup
  • graph backup create [--graph <name>] [--name <label>] - create a backup snapshot for the selected graph
  • graph backup restore --src <backup-name> --dst <graph-name> - restore one backup snapshot into a graph; the current command does not reject an existing destination graph
  • graph 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 create copies only db.sqlite.
  • search-db.sqlite and client-ops-db.sqlite are intentionally excluded.
  • Desktop graph backups use the same <root-dir>/graphs/<graph>/backup/<backup-name>/db.sqlite layout, 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 servers
  • server cleanup - manually terminate revision-mismatched CLI-owned db-worker-node servers discovered from lock files in the current root-dir
  • server start --graph <name> - start db-worker-node for a graph
  • server stop --graph <name> - stop db-worker-node for a graph
  • server restart --graph <name> - restart db-worker-node for a graph
  • doctor [--dev-script] - run runtime diagnostics for db-worker-node.js, root-dir permissions, and running server readiness (--dev-script checks static/db-worker-node.js explicitly)

Auth commands:

  • login - authenticate this machine and create/update ~/logseq/auth.json
  • logout - 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 lookup
  • debug pull --ident <db-ident> [--graph <name>] - pull a raw entity by :db/ident lookup
    • --ident must be a strict EDN keyword (for example :logseq.class/Tag)
    • exactly one of --id, --uuid, or --ident is required
    • if --graph is omitted, CLI falls back to current graph config

Utility commands:

  • completion <zsh|bash> - generate shell completion script to stdout
  • example <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
  • skill show - print built-in logseq-cli skill markdown to stdout
    • always prints raw markdown text, even when --output json or --output edn is set
  • skill install - install built-in skill to ./.agents/skills/logseq-cli/SKILL.md
  • skill 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 stop and server restart can return server-owned-by-other if the daemon was started by another owner source.
  • server start can return server-start-timeout-orphan when 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 stop and server restart keep owner protections; cross-owner stop is only used by the automatic revision-mismatch startup path after the target mismatch is proven.
  • server list human output includes both OWNER and REVISION columns.
  • server list prints a compatibility warning in human output when any server revision string is not exactly equal to the local CLI revision string.
  • server cleanup remains a manual maintenance command. It checks discovered servers in the current root-dir, treats revision != local CLI revision (including missing revision) as mismatch, and attempts graceful-first termination only for :owner-source :cli targets.
  • server cleanup structured output includes checked, mismatched, eligible, skipped-owner, killed, and failed summaries.
  • Structured output (--output json|edn) includes per-server revision data but does not include human warning text.

Sync commands:

  • sync status --graph <name> - show db-sync runtime state for a graph daemon
  • sync start --graph <name> [--e2ee-password <password>] - start db-sync websocket client for a graph
  • sync stop --graph <name> - stop db-sync client on a graph daemon
  • sync upload --graph <name> - upload local graph snapshot to remote
  • sync download --graph <name> [--progress true|false] [--e2ee-password <password>] - download remote graph <name> into a same-name local graph directory
  • sync asset download --graph <name> --id <asset-db-id> - request one remote asset download by the ID shown by list asset
  • sync asset download --graph <name> --uuid <asset-uuid> - request one remote asset download by asset block UUID
  • sync remote-graphs [--graph <name>] - list remote graphs visible to the current login context
  • sync ensure-keys [--graph <name>] - ensure user RSA keys for sync/e2ee
  • sync grant-access --graph <name> --graph-id <uuid> --email <email> - grant encrypted graph access to a user
  • sync config set [--graph <name>] ws-url|http-base <value> - set non-auth db-sync runtime config key
  • sync config get [--graph <name>] ws-url|http-base - get non-auth db-sync runtime config key
  • sync 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-password fails fast and does not overwrite a previously stored encrypted password payload.

Sync upload behavior:

  • sync upload requires --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?, and logseq.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 login first so refresh-token based E2EE password persistence can be used by follow-up sync start/sync download flows.
  • sync upload returns 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 json and confirm data.kv.logseq.kv/graph-uuid is present. If it is missing, rerun sync upload for the same graph to trigger identity backfill.

Sync download behavior:

  • sync download requires --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 download starts db-worker-node in create-empty mode so local startup does not write db-initial-data before 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/events and shared :rtc.log/download events.
  • --progress defaults to true for human output.
  • For structured output (--output json|edn), progress is auto-disabled unless explicitly overridden with --progress true.
  • --progress false always suppresses progress streaming.
  • If the target graph DB is not empty at download time, the CLI returns graph-db-not-empty and aborts before import.
  • For e2ee remote graphs, provide --e2ee-password on sync download (or persist once via sync start --e2ee-password).
  • If e2ee password is required but missing, sync start, sync download, and sync status return e2ee-password-not-found with a hint to provide --e2ee-password.

Sync asset download behavior:

  • sync asset download requires --graph and exactly one of --id or --uuid.
  • --id selects the asset node by the Datascript db/id shown as ID in list asset human output.
  • --uuid selects 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-started with a hint to run logseq 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 reports download-requested? false and 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 existing sync start or sync download flows 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, and hint when applicable. It intentionally omits local filesystem paths.

Sync config persistence:

  • sync config set/unset writes non-auth sync config to the CLI config file selected by --config.
  • If --config is not provided, the default config path is ~/logseq/cli.edn.
  • sync config get reads from that same config source.
  • :e2ee-password is not part of sync config and is silently ignored when found in legacy cli.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 E2EE service. 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; TYPE and CARDINALITY are included by default even without --expand; missing schema cardinality is treated as one)
  • 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)
    • --status is 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 --tags or --properties is required; defaults to --sort updated-at --order desc)
    • --tags and --properties use 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 given
  • upsert block --blocks <edn> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling] - insert blocks via EDN vector
  • upsert block --blocks-file <path> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling] - insert blocks from an EDN file
  • upsert 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
    • --status is not supported on upsert block; use upsert 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 page
  • upsert 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 #Task is attached
  • upsert 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 #Task is attached
  • upsert 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 #Task is attached
    • --status is 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; use upsert block --update-tags/--update-properties/--remove-tags/--remove-properties when needed.
    • for the same field, set and clear options are mutually exclusive (for example: --status todo --no-status is 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 graph assets/ 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.
  • upsert tag --name <name> - create or upsert a tag by name
  • upsert tag --id <id> [--name <name>] - validate a tag by id; when --name is provided, rename that tag id (no-op if normalized name is unchanged)
  • upsert tag --id <id> --name <name> conflicts: returns tag-name-conflict when target name is a non-tag page, and tag-rename-conflict when target name is another existing tag
  • upsert property --name <name> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false] - create or update a property by name
  • upsert property --id <id> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false] - update a property by id
  • move --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 pages
  • search 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 graph
  • query --name <query-name> [--inputs <edn-vector>] - run a named query (built-in or from cli.edn)
  • query list - list available named queries
  • show --page <name> [--level <n>] - show page content tree
    • Use --page-hierarchy true to display child pages connected through page hierarchy instead of normal page content blocks.
  • show --uuid <uuid> [--level <n>] - show block tree
  • show --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 --version prints:
Build time: <timestamp>
Revision: <commit>

Output formats:

  • Global --output <human|json|edn> applies to all commands
  • Output formatting is controlled via global --output, :output-format in config, or LOGSEQ_CLI_OUTPUT.
  • Global --profile enables 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 show output 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 output is plain text. List/search commands render tables with a final Count: N line. For list and search subcommands, the ID column uses :db/id (not UUID). If :db/ident exists, an IDENT column is included. list property includes dedicated TYPE and CARDINALITY columns; list node/list asset include a dedicated TYPE column (page/block) and page context columns for blocks. Search table columns are ID and TITLE. For list page|tag|property|task|node|asset in human output, the TITLE column is display-width-aware (CJK-safe), defaults to max width 40, and truncates overflow with …; set :list-title-max-display-width in cli.edn to override. JSON/EDN outputs keep full titles (no truncation). Block titles can include multiple lines; multi-line rows align additional lines under the TITLE column. Times such as list UPDATED-AT/CREATED-AT and graph info Created at are shown in human-friendly relative form. Errors include error codes and may include a Hint: line. Use --output json|edn for structured output.
  • example human output includes Selector, Matched commands, and Examples sections. Structured output (json/edn) includes selector, matched-commands, examples, and message fields under data.
  • skill show always prints raw markdown text to stdout, regardless of --output mode.
  • sync download progress lines are streamed to stdout only when progress is enabled. In json/edn mode, progress is disabled by default unless --progress true is provided.
  • JSON machine output preserves namespaced keyword semantics:
    • Namespaced keyword keys are emitted as canonical string keys in namespace/name form (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.
  • For list property, TYPE and cardinality are returned in default output (without --expand) for human and structured (json/edn) formats.
    • Human output renders cardinality as one or many in the CARDINALITY column.
    • 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/one or :db.cardinality/many).
    • When a property omits schema cardinality, CLI treats it as default one.

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, and upsert asset return entity ids in data.result for 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]}}
  • doctor output includes overall status (ok, warning, error) and per-check rows for db-worker-script, data-dir, running-servers, and server-revision-mismatch. For scripting, --output json|edn keeps the structured check payload.
  • Common doctor failures and warnings:
    • doctor-script-missing: db-worker-node.js runtime target is missing (default target: dist/db-worker-node.js; use doctor --dev-script to check static/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 :starting state (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:bundle and confirm dist/db-worker-node.js exists and every path listed in dist/db-worker-node-assets.json is present next to it.
  • query human output returns a plain string (the query result rendered via pr-str), which is convenient for pipelines like logseq query ... | xargs logseq show --id.
  • Built-in named queries currently include block-search, task-search, recent-updated, list-status, and list-priority. Use query list to 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 show targets an ordinary block (--id or --uuid), human output prepends one breadcrumb line (page > ... > nearest parent) above the root block line. Each segment is display-width truncated to 24 with ….
Project Alpha > Milestone 2026 > API rollout
5137 Implement retry policy for upload worker
5138 ├── Add timeout backoff guard
5139 └── Add deterministic retry test
  • show tree lines print :db/id as 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 logout and then logseq login again.
  • You can also manually remove ~/logseq/auth.json and repeat logseq 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