26 KiB
Logseq CLI
COMPACT-GIT-COMMIT (oldest first)
- 1a91084894
Scope and sources of truth
This document is the current-state agent guide for the Logseq CLI under docs/agent-guide/.
It replaces the older CLI planning documents in this directory with one implementation-aligned reference.
Authoritative sources, in priority order:
- Current implementation in
src/main/logseq/cli/, especiallycommands.cljs,command/*.cljs,main.cljs,config.cljs,root_dir.cljs,auth.cljs,server.cljs,format.cljs,humanize.cljs, andlog.cljs. - Current tests in
src/test/logseq/cli/and shell e2e manifests undercli-e2e/. - The operator-facing CLI document at
docs/cli/logseq-cli.mdas an auxiliary reference only. - Live command help from the built CLI:
logseq --help,logseq <command> --help, andlogseq <command> <subcommand> --help.
Do not treat older docs/agent-guide/*cli*.md proposal files as current behavior. The public command table is the one assembled in src/main/logseq/cli/commands.cljs; helper namespaces such as command/add.cljs and command/update.cljs are internal implementation pieces for current commands and do not make add or update public commands.
Current non-public or removed interfaces:
- There is no public
addcommand. Create and update flows useupsertsubcommands. - There is no public
updatecommand. Block update/move behavior is exposed throughupsert blockupdate mode. - There is no public standalone
movecommand. Moving a block usesupsert block --id|--uuidwith--target-*and--pos. - There is no
server statuscommand. Useserver listfor status-like inspection andserver cleanupfor revision-mismatched CLI-owned daemons. - There is no current
--data-dirglobal flag. Use--root-dir; graph storage is derived from it. ~/.logseq,~/logseq/cli-graphs, and~/.logseq/cli-graphsare not current default CLI storage paths.- Positional search queries are not supported. Use
search <scope> --content <text>.
Current CLI layout
The CLI is a Node-targeted ClojureScript program. logseq.cli.main/run! parses command-line arguments, resolves configuration, ensures the CLI root directory, builds an action from the parsed command, executes it, formats the result, and returns an exit code plus stdout payload. logseq.cli.main/main prints command output to stdout and exits non-zero for errors.
The current implementation layout is:
src/main/logseq/cli/main.cljs- process entrypoint, result-to-exit-code handling,--verbose, and--profileorchestration.src/main/logseq/cli/commands.cljs- command table composition, top-level parsing, validation, action building, and dispatch to command namespaces.src/main/logseq/cli/command/core.cljs- shared global option spec, help rendering, graph/repo normalization, and parsing helpers.src/main/logseq/cli/command/*.cljs- command-family implementation modules.src/main/logseq/cli/config.cljs- config/env/flag resolution and config persistence.src/main/logseq/cli/root_dir.cljs- root-dir normalization and permission checks.src/main/logseq/cli/server.cljs- db-worker-node lifecycle, lock handling, server discovery, graph listing, and revision cleanup.src/main/logseq/cli/auth.cljs- persisted login state and browser-based login/logout flows.src/main/logseq/cli/format.cljs,output_mode.cljs,humanize.cljs,style.cljs, andlog.cljs- human/JSON/EDN output, styling, humanized values, and stderr debug logs.
The CLI talks to db-worker-node through the transport layer and starts or reuses per-graph worker daemons as needed. The worker binds to localhost and publishes health/lock metadata used by server discovery.
Command families and subcommands
The top-level help groups commands into graph inspection/editing, graph management, authentication, and utilities. The current public command set is assembled from the command namespace entries vectors and dynamic example entries.
Graph inspect and edit
list pagelist taglist propertylist tasklist nodelist assetupsert blockupsert pageupsert taskupsert assetupsert tagupsert propertyremove blockremove pageremove tagremove propertyqueryquery listsearch blocksearch pagesearch propertysearch tagshow
Graph and server management
graph listgraph creategraph switchgraph removegraph validategraph infograph exportgraph importgraph backup listgraph backup creategraph backup restoregraph backup removeserver listserver cleanupserver startserver stopserver restartdoctorsync statussync startsync stopsync uploadsync downloadsync asset downloadsync remote-graphssync ensure-keyssync grant-accesssync config setsync config getsync config unset
Authentication and utilities
loginlogoutcompletiondebug pullskill showskill installexample <selector...>
example entries are generated from command metadata for the inspect/edit families list, upsert, remove, query, search, and show. Use exact selectors such as example upsert page or prefix selectors such as example upsert.
Global flags and output modes
Global flags are defined in logseq.cli.command.core/global-spec:
| Flag | Alias | Meaning |
|---|---|---|
--help |
-h |
Show help. |
--version |
none | Show build time and revision. |
--config <path> |
none | Path to cli.edn; default is <root-dir>/cli.edn. |
--graph <name> |
-g |
Target graph name. |
--root-dir <path> |
none | CLI root directory; default is ~/logseq. |
--timeout-ms <n> |
none | Request timeout in milliseconds; default is 10000. |
| `--output <human | json | edn>` |
--verbose |
-v |
Enable structured debug logging to stderr. |
--profile |
none | Print stage timing profile lines to stderr. |
Configuration precedence is CLI options over environment variables over cli.edn over defaults. Environment variables currently recognized by config.cljs include LOGSEQ_CLI_GRAPH, LOGSEQ_CLI_ROOT_DIR, LOGSEQ_CLI_TIMEOUT_MS, LOGSEQ_CLI_LOGIN_TIMEOUT_MS, LOGSEQ_CLI_LOGOUT_TIMEOUT_MS, LOGSEQ_CLI_OUTPUT, and LOGSEQ_CLI_CONFIG.
Supported structured output modes are json and edn. human is the default when no output mode is resolved.
--verbose and --profile write diagnostic output to stderr and should not be parsed as command stdout. sync download can stream progress lines to stdout when progress is enabled; for structured output, progress is disabled by default unless explicitly enabled.
Paths, config, auth, and graph storage
Current defaults:
| Resource | Default |
|---|---|
| CLI root directory | ~/logseq |
| Graph storage root | <root-dir>/graphs |
| CLI config file | <root-dir>/cli.edn |
| Server list file | <root-dir>/server-list |
| Auth file | ~/logseq/auth.json |
root_dir.cljs normalizes ~, resolves paths, creates the root directory if needed, and checks read/write access. A root-dir problem returns :root-dir-permission and the human formatter adds a permissions hint.
config.cljs sanitizes legacy config keys on read and update. :auth-token, :retries, and :e2ee-password are removed from persisted config data. Cloud login state is stored in auth.json, not cli.edn.
The current cli.edn keys include:
:graph- active graph selected bygraph switchorgraph create.:root-dir- CLI root directory.:output-formator:output- output mode.:timeout-ms- transport request timeout.:login-timeout-msand:logout-timeout-ms- browser callback timeouts.:list-title-max-display-width- human table title truncation width; default40.:ws-urland:http-base- sync runtime endpoints, also managed withsync config.:custom-queries- named query definitions consumed byquery --nameand listed byquery list.
Graph directories live under <root-dir>/graphs and use the current graph-directory encoding helpers. User-visible graph names are stripped of internal DB prefixes in formatted graph output. graph list also detects legacy graph directories and can print warnings or rename suggestions for directories whose old names can be decoded.
auth.cljs uses browser-based Cognito login/logout:
loginstarts a temporary callback server athttp://localhost:8765/auth/callback, opens a browser, exchanges the authorization code, and writes~/logseq/auth.json.logoutremoves the auth file, opens the hosted logout endpoint, and waits forhttp://localhost:8765/logout-complete.- The auth file contains Cognito token state such as
id-token,access-token,refresh-token,expires-at,sub,email, andupdated-at; formatted login output redacts tokens.
There is an internal :auth-path option in auth helpers for tests/config maps, but there is no current public --auth-path global flag.
Server lifecycle, locking, cleanup, and revision compatibility
The CLI manages db-worker-node automatically for graph commands that need worker access. Manual server commands are available for inspection and lifecycle control.
Current server commands:
server listdiscovers running db-worker-node servers for the current root-dir and rewrites the server-list file to drop dead entries.server cleanupterminates revision-mismatched servers only when they are CLI-owned.server start --graph <name>starts or reuses a graph worker.server stop --graph <name>stops a graph worker when ownership allows it.server restart --graph <name>stops then starts a graph worker, or starts one if none is running.
There is no server status command.
Lifecycle behavior comes from server.cljs:
- The server script path is
../static/db-worker-node.jsin debug builds and../dist/db-worker-node.jsin release builds. - Graph server discovery is scoped to the current root-dir.
- Server list entries are filtered by root-dir so one root cannot accidentally manage another root's workers.
- Worker health is read from
/healthz, and the health payload includes status, repo, owner source, PID, host, port, and revision data. - Lock ownership uses
owner-sourcevalues such as:cli,:electron, and:unknown. - CLI can manage CLI-owned workers and legacy
:unknownworkers; it returnsserver-owned-by-otherfor another owner. - Startup cleans stale locks and waits for lock creation, server-list publication, and worker readiness.
server listhuman output includesOWNERandREVISIONcolumns and prints a warning when any server revision differs from the local CLI revision.server cleanupchecks discovered servers, counts mismatches, skips non-CLI owners, and reportschecked,mismatched,eligible,skipped-owner,killed, andfaileddata in structured output.
doctor checks the db-worker runtime script, root-dir permissions, running-server readiness, and server revision mismatch. A revision mismatch warning includes logseq server restart --graph <name> guidance for each affected graph.
Inspect and edit workflows
Use --graph or a configured current graph for commands that operate on graph data.
Listing
All list subcommands support common pagination and sorting options: --fields, --limit, --offset, --sort, and --order. The default sort field is updated-at and the default order is desc.
list pagesupports page metadata expansion, built-in inclusion, journal filters, hidden pages, and created/updated time filters.list tagsupports expanded metadata, built-in inclusion, tag properties, and tag extends.list propertysupports expanded metadata, built-in inclusion, classes, type, and cardinality. Type is included by default.list taskfilters by runtime-resolved task status, priority, and title content.list noderequires at least one of--tagsor--properties; the CSV selectors are trimmed, empty tokens are rejected, and combined filters use all-of semantics.list assetlists nodes tagged with:logseq.class/Assetand includes asset metadata fields when requested.
Upserting
upsert is the current write surface:
upsert blockcreates blocks from--content,--blocks, or--blocks-file, and updates existing blocks when--idor--uuidis present. Update mode can rewrite content, move the block with--target-id,--target-uuid, or--target-page, and mutate tags/properties with--update-tags,--update-properties,--remove-tags, and--remove-properties.upsert pagecreates or updates a page by--page, or updates a page by--id. It supports tag/property add and remove options.upsert taskcreates or updates task pages/blocks/nodes, ensures the#Tasktag, sets task status/priority/scheduled/deadline properties, and supports--no-status,--no-priority,--no-scheduled, and--no-deadlineclears. Generic tag/property mutation options are intentionally not supported onupsert task; useupsert blockwhen generic mutation is needed.upsert assetcreates an asset node from a local file path, attaches#Asset, stores file metadata, and copies the file into the graphassets/directory. Update mode accepts--idor--uuidand can update the title content; update mode rejects--path.upsert tagcreates/upserts a tag by--name; with--id, it validates the target tag and optionally renames it.upsert propertycreates or updates a property by--name, or updates by--id; it supports--type,--cardinality one|many,--hide, and--public.
Compatibility guidance in parser errors maps old options to the current surface, for example --tags to --update-tags, --properties to --update-properties, and block --status to upsert task --status.
Removing
Removal is split by entity kind:
remove block --id <id-or-edn-vector>orremove block --uuid <uuid>removes blocks. An EDN vector of IDs is supported for multi-remove.remove page --page <name>orremove page --id <id>removes a page.remove tag --name <name>orremove tag --id <id>removes a public non-built-in tag.remove property --name <name>orremove property --id <id>removes a public non-built-in property.
Selectors that would be ambiguous or target the wrong entity type return structured errors and candidate lists when available.
Search
Search uses scoped subcommands and requires --content or -c:
search block --content <text>searches block titles.search page --content <text>searches page names.search property --content <text>searches property titles.search tag --content <text>searches tag titles.
Search is case-insensitive substring search. Page and block search filter recycled entities. Legacy positional queries such as search block alpha are rejected with guidance to use --content.
Query
query runs Datascript queries:
query --query <edn> [--inputs <edn-vector>]runs an inline EDN query.query --name <name> [--inputs <edn-vector>]runs a built-in or custom named query.query listlists built-in and:custom-queriesentries from config.
Built-in query names currently defined in command/query.cljs are:
task-searchrecent-updatedlist-statuslist-priority
task-search normalizes string status input into :logseq.property/status.* keywords. recent-updated requires a positive integer recent-days. Optional named-query inputs can be supplied via input specs and defaults; internal ?now-ms inputs are hidden from query list output.
Show
show renders a page or block tree:
show --page <name>shows a page tree.show --id <id-or-edn-vector>shows one or more entities by db/id.show --uuid <uuid>shows one entity by UUID.--level <n>limits tree depth and must be at least1.--linked-referencesdefaults to true and includes linked references unless set false.--ref-id-footerdefaults to true and shows referenced-entity ID footer rows unless set false.show --idcan read IDs from stdin when--idis present without a value.
Human show output prints :db/id in the first column, renders a tree, displays selected user and public built-in properties, resolves UUID references in text recursively up to a bounded depth, and prepends a breadcrumb for ordinary block roots. Structured json/edn output returns sanitized tree data and removes internal UUID fields from the output tree.
Graph management, import/export, and backup
Graph management commands use --graph or the configured current graph, depending on the operation:
graph listlists canonical graph names and legacy graph directory diagnostics.graph create --graph <name>creates or opens a graph and persists it as current graph.graph switch --graph <name>checks that the graph exists, starts/reuses its worker, and persists it as current graph.graph remove --graph <name>stops the graph worker when possible and unlinks the graph directory.graph validate --graph <name> [--fix]delegates validation to the worker.graph info --graph <name>reads graph metadata andlogseq.kv/*values; human output redacts sensitive KV keys matching token/secret/password.graph export --graph <name> --type edn|sqlite --file <path>exports EDN graph data or a SQLite snapshot.- For
--type edn, the CLI also accepts--include-timestamps,--exclude-built-in-pages, and--exclude-namespaces <csv>. --exclude-namespacesis normalized as trimmed CSV values with empty segments removed and duplicates collapsed; the worker receives the final value as a keyword set.--exclude-namespacesintentionally reduces some backend export validation strictness because excluded ontology namespaces cannot be validated the same way.- For
--type sqlite, the CLI rejects those EDN-only flags and invokes:thread-api/backup-db-sqliteso the worker writes the snapshot directly to the requested file path.
- For
graph import --graph <name> --type edn|sqlite --input <path>imports EDN or SQLite data. SQLite import requires the target graph to be missing; EDN import can target a graph action that the worker can open.
Graph backups are SQLite snapshot helpers under the graph's backup directory:
graph backup listlists backups for the selected graph.graph backup create [--name <label>]creates a backup named from the graph, optional label, and UTC timestamp.graph backup restore --src <backup-name> --dst <graph-name>restores a backup into a missing destination graph.graph backup remove --src <backup-name>removes a backup directory.
Backups store db.sqlite under <root-dir>/graphs/<encoded-graph>/backup/<encoded-backup>/db.sqlite. The backup commands are graph-database backups; auxiliary files such as search indexes are not listed as backup payloads in the CLI command implementation.
Sync, doctor, debug, completion, skill, and example
Sync
Sync commands live in command/sync.cljs.
Authenticated sync actions are sync start, sync upload, sync download, sync asset download, sync remote-graphs, sync ensure-keys, and sync grant-access; they resolve runtime auth from auth.json unless token data is already present in runtime config. sync status, sync stop, and sync config commands do not require the CLI login resolution path in the same way.
Current sync commands:
sync status --graph <name>shows worker db-sync status.sync start --graph <name> [--e2ee-password <password>]configures runtime sync state, handles E2EE password availability when needed, starts db-sync, and waits for readiness or a clear failure state.sync stop --graph <name>stops db-sync for a graph worker.sync upload --graph <name> [--e2ee-password <password>]uploads the local graph snapshot.sync download --graph <name> [--progress true|false] [--e2ee-password <password>]downloads a remote graph into a new local graph. It creates an empty DB, requires the local graph to be missing, checks that the target DB is empty, uses a 30-minute download timeout by default, and cleans up a newly created graph on failure.sync asset download --graph <name> --id <asset-db-id>requests one remote asset download by theIDshown bylist asset.sync asset download --graph <name> --uuid <asset-uuid>requests one remote asset download by asset block UUID.sync remote-graphslists remote graphs visible to the current login context.sync ensure-keys [--e2ee-password <password>] [--upload-keys]ensures user RSA keys;--upload-keysasks the worker to ensure server-side presence.sync grant-access --graph <name> --graph-id <uuid> --email <email>grants graph access to an email.sync config set|get|unset ws-url|http-basemanages non-auth sync config keys incli.edn.
Sync config defaults are wss://api.logseq.io/sync/%s for :ws-url and https://api.logseq.io for :http-base. Missing required endpoint values for start/upload/download/asset-download/grant-access return :missing-sync-config.
sync asset download reuses the existing db-worker-node asset request API :thread-api/db-sync-request-asset-download; it does not add a dedicated worker API. The command requires sync to already be active for the graph and returns :sync-not-started with logseq sync start --graph <graph> guidance when the worker sync client is inactive. Before enqueueing, it resolves the asset node, verifies asset UUID/type/checksum/remote metadata, rejects external URL assets, checks the local assets/<asset-uuid>.<asset-type> file, skips matching checksums, and requests a re-download on checksum mismatch. It returns immediately after enqueue and does not return local filesystem paths. This first version intentionally does not accept --e2ee-password.
For E2EE graphs, --e2ee-password verifies and persists the password through worker sync crypt logic. Missing required E2EE password state returns :e2ee-password-not-found with a hint to provide --e2ee-password.
Doctor
doctor [--dev-script] checks:
- the bundled db-worker runtime script, or
static/db-worker-node.jswhen--dev-scriptis used; - root-dir readability/writability;
- discovered running server readiness;
- server revision compatibility with the local CLI revision.
The command can return overall ok, warning, or error. Structured output preserves per-check payloads.
Debug
debug pull pulls a raw entity using selector [*]:
debug pull --id <db-id>debug pull --uuid <uuid>debug pull --ident <edn-keyword>
Exactly one selector is required. --ident must parse as a strict EDN keyword such as :logseq.class/Tag.
Completion
completion zsh, completion bash, or completion --shell zsh|bash prints a shell completion script to stdout. Unsupported shells return :invalid-options.
Skill
skill showprints the built-inlogseq-cliskill Markdown as raw human output regardless of requested output mode.skill installwrites the skill to./.agents/skills/logseq-cli/SKILL.mdunder the current working directory.skill install --globalwrites the skill to~/.agents/skills/logseq-cli/SKILL.md.
Example
example <selector...> prints runnable examples pulled from current command metadata. It supports group selectors such as example list and exact selectors such as example list page for the inspect/edit command families.
Output contract and machine-readable behavior
All command executions format a result map with :status and either :data or :error. Errors produce exit code 1 unless a command explicitly overrides the exit code.
Human output:
- List and search commands render tables and a final
Count: Nline. - Human tables use display-width-aware title truncation for list commands, with
:list-title-max-display-widthdefaulting to40. - Time values such as
UPDATED-AT,CREATED-AT, and graph creation time are rendered in relative human form where applicable. - Error output includes
Error (<code>): <message>and may includeHint:orCandidates:lines. showrenders an ID-prefixed tree and linked-reference sections when enabled.queryhuman output is thepr-strof the query result, which is suitable for pipelines into commands such asshow --id.
JSON output:
- Top-level shape is
{"status":"ok","data":...}or{"status":"error","error":...}. - Keyword keys are emitted as strings. Namespaced keyword keys use
namespace/nameform, for example:block/titlebecomes"block/title". - Keyword values are emitted as strings with namespace text when present, for example
:db.cardinality/onebecomes"db.cardinality/one". - UUID values are emitted as strings.
- For
doctorerrors, structureddatais retained alongsideerrorwhen available.
EDN output:
- EDN output preserves Clojure/EDN keywords and data shapes:
{:status :ok, :data ...}or{:status :error, :error ...}. - For
doctorerrors, structured:datais retained when available.
Special output behavior:
skill showforces raw human Markdown output.completionreturns the generated script as human message data.sync downloadprogress uses stdout progress lines only when progress is enabled; structured output auto-disables progress unless explicitly overridden.--verboseand--profilewrite to stderr.
Test coverage and verification sources
Use these paths to verify current behavior before editing CLI code or docs:
- Command parsing and dispatch:
src/test/logseq/cli/commands_test.cljs. - Command-family tests:
src/test/logseq/cli/command/*_test.cljs. - Config/root-dir/output/log/profile tests:
src/test/logseq/cli/config_test.cljs,root_dir_test.cljs,format_test.cljs,output_mode_test.cljs,log_test.cljs, andprofile_test.cljs. - Server lifecycle tests:
src/test/logseq/cli/server_test.cljsandsrc/test/logseq/cli/command/server_test.cljs. - Auth tests:
src/test/logseq/cli/auth_test.cljsandsrc/test/logseq/cli/command/auth_test.cljs. - Shell e2e harness rules:
cli-e2e/AGENTS.md. - Non-sync shell e2e inventory:
cli-e2e/spec/non_sync_inventory.edn. - Sync shell e2e inventory:
cli-e2e/spec/sync_inventory.edn. - CLI operator reference:
docs/cli/logseq-cli.md, with implementation/tests taking precedence when there is a conflict.
Useful verification commands:
bb dev:test -v logseq.cli.commands-test
bb dev:test -v logseq.cli.command.server-test
bb dev:test -v logseq.cli.command.sync-test
bb -f cli-e2e/bb.edn test --skip-build
bb -f cli-e2e/bb.edn test-sync --skip-build
For broad validation, use bb dev:lint-and-test. For CLI e2e, use the cli-e2e/AGENTS.md workflow and choose non-sync or sync suites explicitly.