# 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: 1. Current implementation in `src/main/logseq/cli/`, especially `commands.cljs`, `command/*.cljs`, `main.cljs`, `config.cljs`, `root_dir.cljs`, `auth.cljs`, `server.cljs`, `format.cljs`, `humanize.cljs`, and `log.cljs`. 2. Current tests in `src/test/logseq/cli/` and shell e2e manifests under `cli-e2e/`. 3. The operator-facing CLI document at `docs/cli/logseq-cli.md` as an auxiliary reference only. 4. Live command help from the built CLI: `logseq --help`, `logseq --help`, and `logseq --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 `add` command. Create and update flows use `upsert` subcommands. - There is no public `update` command. Block update/move behavior is exposed through `upsert block` update mode. - There is no public standalone `move` command. Moving a block uses `upsert block --id|--uuid` with `--target-*` and `--pos`. - There is no `server status` command. Use `server list` for status-like inspection and `server cleanup` for revision-mismatched CLI-owned daemons. - There is no current `--data-dir` global flag. Use `--root-dir`; graph storage is derived from it. - `~/.logseq`, `~/logseq/cli-graphs`, and `~/.logseq/cli-graphs` are not current default CLI storage paths. - Positional search queries are not supported. Use `search --content `. ## 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 `--profile` orchestration. - `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`, and `log.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 page` - `list tag` - `list property` - `list task` - `list node` - `list asset` - `upsert block` - `upsert page` - `upsert task` - `upsert asset` - `upsert tag` - `upsert property` - `remove block` - `remove page` - `remove tag` - `remove property` - `query` - `query list` - `search block` - `search page` - `search property` - `search tag` - `show` ### Graph and server management - `graph list` - `graph create` - `graph switch` - `graph remove` - `graph validate` - `graph info` - `graph export` - `graph import` - `graph backup list` - `graph backup create` - `graph backup restore` - `graph backup remove` - `server list` - `server cleanup` - `server start` - `server stop` - `server restart` - `doctor` - `sync status` - `sync start` - `sync stop` - `sync upload` - `sync download` - `sync asset download` - `sync remote-graphs` - `sync ensure-keys` - `sync grant-access` - `sync config set` - `sync config get` - `sync config unset` ### Authentication and utilities - `login` - `logout` - `completion` - `debug pull` - `skill show` - `skill install` - `example ` `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 ` | none | Path to `cli.edn`; default is `/cli.edn`. | | `--graph ` | `-g` | Target graph name. | | `--root-dir ` | none | CLI root directory; default is `~/logseq`. | | `--timeout-ms ` | none | Request timeout in milliseconds; default is `10000`. | | `--output ` | `-o` | Output format; default is human output. | | `--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 | `/graphs` | | CLI config file | `/cli.edn` | | Server list file | `/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 by `graph switch` or `graph create`. - `:root-dir` - CLI root directory. - `:output-format` or `:output` - output mode. - `:timeout-ms` - transport request timeout. - `:login-timeout-ms` and `:logout-timeout-ms` - browser callback timeouts. - `:list-title-max-display-width` - human table title truncation width; default `40`. - `:ws-url` and `:http-base` - sync runtime endpoints, also managed with `sync config`. - `:custom-queries` - named query definitions consumed by `query --name` and listed by `query list`. Graph directories live under `/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: - `login` starts a temporary callback server at `http://localhost:8765/auth/callback`, opens a browser, exchanges the authorization code, and writes `~/logseq/auth.json`. - `logout` removes the auth file, opens the hosted logout endpoint, and waits for `http://localhost:8765/logout-complete`. - The auth file contains Cognito token state such as `id-token`, `access-token`, `refresh-token`, `expires-at`, `sub`, `email`, and `updated-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 list` discovers running db-worker-node servers for the current root-dir and rewrites the server-list file to drop dead entries. - `server cleanup` terminates revision-mismatched servers only when they are CLI-owned. - `server start --graph ` starts or reuses a graph worker. - `server stop --graph ` stops a graph worker when ownership allows it. - `server restart --graph ` 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.js` in debug builds and `../dist/db-worker-node.js` in 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-source` values such as `:cli`, `:electron`, and `:unknown`. - CLI can manage CLI-owned workers and legacy `:unknown` workers; it returns `server-owned-by-other` for another owner. - Startup cleans stale locks and waits for lock creation, server-list publication, and worker readiness. - `server list` human output includes `OWNER` and `REVISION` columns and prints a warning when any server revision differs from the local CLI revision. - `server cleanup` checks discovered servers, counts mismatches, skips non-CLI owners, and reports `checked`, `mismatched`, `eligible`, `skipped-owner`, `killed`, and `failed` data 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 ` 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 page` supports page metadata expansion, built-in inclusion, journal filters, hidden pages, and created/updated time filters. - `list tag` supports expanded metadata, built-in inclusion, tag properties, and tag extends. - `list property` supports expanded metadata, built-in inclusion, classes, type, and cardinality. Type is included by default. - `list task` filters by runtime-resolved task status, priority, and title content. - `list node` requires at least one of `--tags` or `--properties`; the CSV selectors are trimmed, empty tokens are rejected, and combined filters use all-of semantics. - `list asset` lists nodes tagged with `:logseq.class/Asset` and includes asset metadata fields when requested. ### Upserting `upsert` is the current write surface: - `upsert block` creates blocks from `--content`, `--blocks`, or `--blocks-file`, and updates existing blocks when `--id` or `--uuid` is 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 page` creates or updates a page by `--page`, or updates a page by `--id`. It supports tag/property add and remove options. - `upsert task` creates or updates task pages/blocks/nodes, ensures the `#Task` tag, sets task status/priority/scheduled/deadline properties, and supports `--no-status`, `--no-priority`, `--no-scheduled`, and `--no-deadline` clears. Generic tag/property mutation options are intentionally not supported on `upsert task`; use `upsert block` when generic mutation is needed. - `upsert asset` creates an asset node from a local file path, attaches `#Asset`, stores file metadata, and copies the file into the graph `assets/` directory. Update mode accepts `--id` or `--uuid` and can update the title content; update mode rejects `--path`. - `upsert tag` creates/upserts a tag by `--name`; with `--id`, it validates the target tag and optionally renames it. - `upsert property` creates 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 ` or `remove block --uuid ` removes blocks. An EDN vector of IDs is supported for multi-remove. - `remove page --page ` or `remove page --id ` removes a page. - `remove tag --name ` or `remove tag --id ` removes a public non-built-in tag. - `remove property --name ` or `remove property --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 ` searches block titles. - `search page --content ` searches page names. - `search property --content ` searches property titles. - `search tag --content ` 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 [--inputs ]` runs an inline EDN query. - `query --name [--inputs ]` runs a built-in or custom named query. - `query list` lists built-in and `:custom-queries` entries from config. Built-in query names currently defined in `command/query.cljs` are: - `task-search` - `recent-updated` - `list-status` - `list-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 ` shows a page tree. - `show --id ` shows one or more entities by db/id. - `show --uuid ` shows one entity by UUID. - `--level ` limits tree depth and must be at least `1`. - `--linked-references` defaults to true and includes linked references unless set false. - `--ref-id-footer` defaults to true and shows referenced-entity ID footer rows unless set false. - `show --id` can read IDs from stdin when `--id` is 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 list` lists canonical graph names and legacy graph directory diagnostics. - `graph create --graph ` creates or opens a graph and persists it as current graph. - `graph switch --graph ` checks that the graph exists, starts/reuses its worker, and persists it as current graph. - `graph remove --graph ` stops the graph worker when possible and unlinks the graph directory. - `graph validate --graph [--fix]` delegates validation to the worker. - `graph info --graph ` reads graph metadata and `logseq.kv/*` values; human output redacts sensitive KV keys matching token/secret/password. - `graph export --graph --type edn|sqlite --file ` exports EDN graph data or a SQLite snapshot. - For `--type edn`, the CLI also accepts `--include-timestamps`, `--exclude-built-in-pages`, and `--exclude-namespaces `. - `--exclude-namespaces` is normalized as trimmed CSV values with empty segments removed and duplicates collapsed; the worker receives the final value as a keyword set. - `--exclude-namespaces` intentionally 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-sqlite` so the worker writes the snapshot directly to the requested file path. - `graph import --graph --type edn|sqlite --input ` 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 list` lists backups for the selected graph. - `graph backup create [--name