23 KiB
Logseq CLI Skill Update Warning Implementation Plan
Goal: When Logseq CLI prints the global help information, check whether the user already has an installed logseq-cli agent skill. If an installed skill file exists and its content differs from the built-in skill bundled with the current CLI, append a warning to the end of the global help output.
Architecture: Keep this feature entirely in the Logseq CLI help path and existing skill command support. Do not involve graph commands, db-worker-node lifecycle, or db-worker :thread-api calls.
Architecture: Reuse the existing built-in skill source resolution and install-target conventions from logseq.cli.command.skill, which currently supports logseq skill show, logseq skill install, and logseq skill install --global.
Architecture: Append the warning only for global help output: logseq, logseq --help, logseq -h, and equivalent leading-global-option forms such as logseq --output json --help. Do not append it to command help such as logseq show --help, group help such as logseq graph, parse errors, version output, or normal command output.
Architecture: Treat the warning as a local filesystem comparison. The CLI should compare UTF-8 skill markdown content exactly. No network request, no graph open, no db-worker-node start, and no new :thread-api/* method are required.
Tech Stack: ClojureScript, Node fs/os/path APIs, babashka.cli, existing Logseq CLI command parsing, existing logseq.cli.command.skill, logseq.cli.main, CLI unit tests, and the Logseq review workflow.
Related: Builds on the current implementation in /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/main.cljs, /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs, /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/core.cljs, /Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/skill.cljs, and the db-worker-node boundary in /Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_worker_node.cljs.
Problem statement
The Logseq CLI ships a built-in agent skill at:
.agents/skills/logseq-cli/SKILL.md
The CLI exposes this built-in skill through:
logseq skill show
logseq skill install
logseq skill install --global
logseq skill install copies the bundled skill into the current working directory under:
<cwd>/.agents/skills/logseq-cli/SKILL.md
logseq skill install --global copies it into the user's home directory under:
~/.agents/skills/logseq-cli/SKILL.md
After the CLI is upgraded, a user may still have an older installed copy of the logseq-cli skill. Agents that use the installed skill can then follow stale command guidance even though the CLI binary has newer behavior.
The requested behavior is:
- When showing global help, also check whether the installed
logseq-cliskill is up to date. - If the user has not installed the skill, show no warning.
- If the user has installed the skill and the installed content differs from the bundled content, append a warning to the end of the help info.
- Avoid adding a new db-worker
:thread-apiunless implementation work proves it is absolutely necessary. - After implementation, review the finished change with
logseq-review-workflow.
This feature is a CLI self-maintenance hint. It should not change graph data, command behavior, db-worker-node behavior, or skill installation behavior.
Current implementation snapshot
Global help generation
Global help is generated in:
src/main/logseq/cli/command/core.cljs
The key function is:
logseq.cli.command.core/top-level-summary
It returns a markdown-like/plain-text help string containing:
- usage line
- grouped commands
- global options
- command options hint
Command parsing lives in:
src/main/logseq/cli/commands.cljs
logseq.cli.commands/parse-args builds the top-level summary before dispatching:
(let [summary (command-core/top-level-summary table)
{:keys [opts args]} (command-core/parse-leading-global-opts raw-args)
...]
...)
Global help is returned by command-core/help-result in at least these cases:
logseqlogseq --helplogseq -h- exhausted input that falls back to the top-level summary
Group help and command help also use help-result, but with different summary strings.
CLI run path
The entrypoint is:
src/main/logseq/cli/main.cljs
logseq.cli.main/run! parses args first:
(commands/parse-args args)
If (:help? parsed) is true, it returns immediately without resolving config, ensuring root dir, building command actions, starting db-worker-node, or invoking graph APIs.
Current human help output path:
{:exit-code 0
:output (:summary parsed)}
Current structured help output path:
(format/format-result {:status :ok
:data {:message (:summary parsed)}}
{:output-format mode})
This means the right place to append a dynamic warning is in logseq.cli.main/run! after parsing and before formatting the help result. That keeps command.core/top-level-summary deterministic and avoids a namespace cycle between command.core and command.skill.
Skill command implementation
The skill utility command lives in:
src/main/logseq/cli/command/skill.cljs
Current constants:
skill-dir-name "logseq-cli"
skill-file-name "SKILL.md"
relative-skill-path [".agents" "skills" "logseq-cli" "SKILL.md"]
Current public helpers include:
resolve-install-target
resolve-skill-source-path
Current private helpers include:
source-path-candidates
resolve-action-source-path
resolve-install-destination
Current command behavior:
skill showresolves the bundled source skill and prints it.skill installresolves the bundled source skill, resolves a destination under<cwd>/.agents/skills/logseq-cli/SKILL.md, and writes the source payload.skill install --globalresolves the destination under~/.agents/skills/logseq-cli/SKILL.md.
This code already knows the built-in source path and supported install destinations. The implementation should extend this namespace with reusable status helpers instead of duplicating path logic in main.cljs.
db-worker-node boundary
The db-worker-node server lives in:
src/main/frontend/worker/db_worker_node.cljs
It exposes HTTP endpoints such as:
/healthz
/v1/events
/v1/invoke
/v1/shutdown
/v1/invoke forwards existing :thread-api/* calls to the worker runtime after repo validation and write-lock checks.
Global CLI help currently exits before config resolution and before any db-worker-node lifecycle path. The skill update warning only needs to compare local files, so it should preserve that boundary:
- no graph selection
- no root-dir creation
- no server discovery
- no worker start
- no
/v1/invoke - no new
:thread-api/*
If an implementation attempt appears to require db-worker-node, re-check the design. That would likely mean the check has accidentally been coupled to graph/runtime state instead of the filesystem skill files.
Desired behavior
No installed skill
If neither supported installed skill file exists, global help should be unchanged.
Supported installed locations should match the existing install command semantics:
<cwd>/.agents/skills/logseq-cli/SKILL.md
~/.agents/skills/logseq-cli/SKILL.md
Examples that should not show a warning when no installed file exists:
logseq
logseq --help
logseq -h
logseq --output json --help
Installed skill matches bundled skill
If an installed skill file exists and its UTF-8 content exactly equals the bundled skill content, global help should be unchanged.
This preserves a quiet help experience for users who already updated their installed skill.
Installed skill differs from bundled skill
If one or more installed skill files exist and at least one installed file differs from the bundled skill content, append a warning to the end of the global help information.
Recommended warning text:
Warning: Installed logseq-cli skill is out of date. Run `logseq skill install` or `logseq skill install --global` to update it.
If implementation can safely identify stale scopes, prefer a more specific warning:
Warning: Installed logseq-cli skill is out of date at <path>. Run `logseq skill install` to update it.
or for global scope:
Warning: Installed logseq-cli skill is out of date at <path>. Run `logseq skill install --global` to update it.
If both local and global installed files exist and either differs, a single concise warning is enough. The warning may include both update commands, but it should remain at the end of help and avoid turning global help into a long diagnostic report.
Scope of global help
Append the warning for top-level/global help only:
logseq
logseq --help
logseq -h
logseq --output human --help
logseq --output json --help
logseq --output edn --help
Do not append the warning for group help:
logseq graph
logseq graph --help
logseq list
logseq example
Do not append the warning for command help:
logseq show --help
logseq skill install --help
logseq query --help
Do not append the warning for non-help output:
logseq --version
logseq skill show
logseq skill install
logseq graph list
Structured output
Structured help modes currently wrap the help string in :data :message.
When global help is requested with structured output, append the same warning to that message field:
logseq --output json --help
logseq --output edn --help
Do not add a separate structured field unless there is a strong reason. Keeping the warning in message preserves the existing help-result shape and satisfies the requirement that the warning appears at the end of the help info.
Design
1. Add skill status helpers in logseq.cli.command.skill
Add public, unit-testable helpers to src/main/logseq/cli/command/skill.cljs.
Suggested API:
(defn installed-skill-targets
[{:keys [cwd home-dir]}]
...)
(defn installed-skill-update-status
[{:keys [cwd home-dir source-path]}]
...)
(defn format-installed-skill-warning
[status]
...)
The exact names can change during implementation, but the responsibilities should remain separate:
- Resolve candidate installed paths.
- Resolve/read the bundled source skill.
- Read only installed files that actually exist.
- Compare content.
- Return data describing whether a warning is needed.
- Format the user-facing warning in one place.
Suggested status shape:
{:installed? true
:outdated? true
:outdated-targets [{:scope :local
:path "/work/.agents/skills/logseq-cli/SKILL.md"
:update-command "logseq skill install"}]}
For no installed skill:
{:installed? false
:outdated? false
:outdated-targets []}
For installed and current:
{:installed? true
:outdated? false
:outdated-targets []}
For source resolution/read failures, return a typed error instead of throwing from the status helper:
{:installed? true
:outdated? false
:error {:code :skill-source-not-found ...}}
The top-level help path can then avoid showing a false warning if comparison cannot be completed. Unit tests should still assert the typed error behavior so packaging/path bugs are visible to developers.
Implementation notes:
- Keep exact UTF-8 string equality as the freshness check.
- Do not normalize whitespace or line endings unless tests prove packaging changes introduce platform-only newline differences.
- Use
fs/existsSyncbefore reading installed files. - Read source once.
- Reuse
resolve-skill-source-pathand the existing candidate logic. - Reuse
resolve-install-targetfor local/global paths where practical. - Preserve existing
skill showandskill installbehavior.
2. Detect global help in logseq.cli.main
Add a small helper in src/main/logseq/cli/main.cljs to identify top-level help from the original argv and parse result.
Suggested behavior:
global-help-info? = parsed is help AND leading global option parsing leaves no command args
This matches:
[]["--help"]["-h"]["--output" "json" "--help"]
It does not match command or group help because those have command args after leading global options.
Suggested helper responsibilities:
(defn- global-help-info?
[args parsed]
...)
Use existing command-core/parse-leading-global-opts to avoid introducing a second argv parser.
Do not add dynamic filesystem checks to command-core/top-level-summary. Keeping the check in main.cljs avoids making parse-only tests depend on local user files and prevents a circular dependency with logseq.cli.command.skill.
3. Append warning before formatting help
In the (:help? parsed) branch of logseq.cli.main/run!:
- Resolve output mode as today.
- Compute
summaryfrom(:summary parsed). - If
global-help-info?is true, call the skill status helper and append the formatted warning when needed. - Use the final summary for both human and structured output.
Suggested flow:
(let [mode (resolve-output-format args parsed nil nil)
summary (maybe-append-installed-skill-warning args parsed (:summary parsed))]
...)
Keep the function synchronous unless implementation work finds a strong reason otherwise. The comparison reads two or three local files at most and happens only when global help is requested.
4. Warning formatting
Keep the warning concise, stable, and easy to test.
Recommended baseline:
Warning: Installed logseq-cli skill is out of date. Run `logseq skill install` or `logseq skill install --global` to update it.
Optional scope-specific rendering:
Warning: Installed logseq-cli skill is out of date at <path>. Run `<command>` to update it.
If there are multiple stale installed targets, either:
- render one generic warning with both install commands, or
- render one warning line with comma-separated paths.
Do not render a multi-paragraph report.
Do not warn when the installed file is missing. Missing means the user has not installed the skill through the supported install location, and the requirement explicitly says not to show a warning in that case.
5. Avoid db-worker-node and new thread APIs
This feature should be implemented without changing:
src/main/frontend/worker/db_worker_node.cljs
src/main/logseq/cli/server.cljs
src/main/logseq/cli/transport.cljs
Do not add a new :thread-api/* for skill status. The information is already available from local files in the CLI process.
If a future implementation wants to expose skill status to a graph-aware command, prefer a normal CLI helper or command action first. A db-worker thread API would only be justified if the worker owns the data or side effect, which is not true here.
Implementation tasks
Task 1: Add skill content status helpers
Files:
src/main/logseq/cli/command/skill.cljs
src/test/logseq/cli/command/skill_test.cljs
Steps:
- Add a helper to resolve local and global installed skill targets using existing install semantics.
- Add a helper to resolve and read the built-in source skill.
- Add a helper to read installed skill files only when they exist.
- Compare installed content with built-in content.
- Return status data that distinguishes:
- no installed skill
- installed and current
- installed and outdated
- comparison error
- Add unit tests for each status case.
Acceptance criteria:
- No existing
skill showorskill installtests regress. - No installed file means
:installed? falseand no warning. - Matching installed file means no warning.
- Different installed file means
:outdated? true. - Local and global install paths match current install command semantics.
Task 2: Append warning only for global help
Files:
src/main/logseq/cli/main.cljs
src/test/logseq/cli/main_test.cljs
Steps:
- Add a private global-help detector based on raw args and parse result.
- Add a private warning append helper that calls
skill-command/installed-skill-update-status. - In the
(:help? parsed)branch, replace direct use of(:summary parsed)with the possibly augmented summary. - Add tests with
p/with-redefsor temporary files so the tests do not depend on the developer's real~/.agentsfiles. - Cover human, JSON, and EDN help modes if feasible.
Acceptance criteria:
logseq --helpappends the warning when the mocked/temporary installed skill is stale.logseqwith no args follows the same global help behavior.logseq show --helpdoes not append the warning.logseq graphgroup help does not append the warning.logseq --versiondoes not append the warning.logseq --output json --helpkeeps the warning insidedata.messageand preserves the existing structured result shape.
Task 3: Keep parsing deterministic
Files:
src/main/logseq/cli/commands.cljs
src/main/logseq/cli/command/core.cljs
src/test/logseq/cli/commands_test.cljs
Expected change: ideally none.
If implementation needs parse metadata, prefer adding metadata in commands.cljs rather than adding filesystem checks to command.core.cljs.
Acceptance criteria:
commands/parse-argsremains deterministic and does not read user skill files.- Existing help output tests in
commands_test.cljsremain stable. - Any new metadata does not change the public command/action behavior unless explicitly tested.
Task 4: Verify no db-worker-node changes are needed
Files:
src/main/frontend/worker/db_worker_node.cljs
src/main/logseq/cli/server.cljs
src/main/logseq/cli/transport.cljs
Expected change: none.
Acceptance criteria:
- No new
:thread-api/*keyword is introduced for this feature. - Global help still returns before config/root-dir/db-worker work.
- Existing db-worker-node tests are not affected.
Task 5: Review with logseq-review-workflow
After implementation and tests, run the Logseq review workflow before considering the feature complete.
Scope to review:
src/main/logseq/cli/main.cljs
src/main/logseq/cli/command/skill.cljs
src/test/logseq/cli/main_test.cljs
src/test/logseq/cli/command/skill_test.cljs
Likely review rule modules:
.agents/skills/logseq-review-workflow/rules/common.md.agents/skills/logseq-review-workflow/rules/libraries/clojure-cljs.md.agents/skills/logseq-review-workflow/rules/libraries/babashka-cli.md.agents/skills/logseq-review-workflow/rules/libraries/shadow-cljs-node.md.agents/skills/logseq-review-workflow/rules/modules/logseq-cli.md
Review acceptance criteria:
- The workflow is explicitly applied after implementation.
- Any findings are fixed or documented before handoff.
- The final response mentions the review scope and whether findings remain.
Test plan
Targeted unit tests:
bb dev:test -v logseq.cli.command.skill-test/test-installed-skill-update-status
bb dev:test -v logseq.cli.main-test/test-global-help-appends-stale-skill-warning
bb dev:test -v logseq.cli.main-test/test-global-help-skill-warning-structured-output
Existing related tests to keep green:
bb dev:test -v logseq.cli.command.skill-test/test-execute-skill-show
bb dev:test -v logseq.cli.command.skill-test/test-execute-skill-install
bb dev:test -v logseq.cli.commands-test/test-help-output
bb dev:test -v logseq.cli.main-test/test-help-output-respects-structured-modes
Broader verification before submitting:
bb dev:lint-and-test
Manual checks, if a built CLI is available:
logseq --help
logseq --output json --help
logseq skill install
logseq --help
# then modify the installed SKILL.md or switch to a newer build
logseq --help
logseq show --help
Expected manual results:
- No installed skill: no warning.
- Installed current skill: no warning.
- Installed stale skill: warning appears at the end of global help.
- Command help and group help: no warning.
Edge cases and decisions
Local vs global installed skill
The CLI currently supports both local and global installation. The warning check should inspect both supported destinations.
If neither exists, do not warn.
If one exists and differs, warn.
If both exist and either differs, warn once. The warning can mention both install commands unless scope-specific formatting is implemented.
User-edited installed skill
A user may intentionally customize their installed logseq-cli skill. Exact content comparison will treat that as different and show an update warning.
This is acceptable for the first implementation because there is no skill version metadata today. The warning says the installed skill differs from the bundled current skill; it does not overwrite anything.
Do not introduce a skill metadata format or migration in this task unless explicitly requested.
Missing source skill
If the bundled source skill cannot be resolved/read, that is a packaging or runtime bug. The status helper should return a typed error that unit tests can cover.
The global help path should not show an update warning unless comparison succeeds and proves that an installed skill is outdated. This avoids false positives in help output.
File permissions
If an installed skill file exists but cannot be read, return a typed comparison error from the helper. Do not claim the skill is outdated unless content comparison succeeds.
If future work wants to expose this to users, add a separate diagnostic command or a verbose-only diagnostic. Do not add noisy errors to normal global help in this task.
Color/styling
Existing help uses logseq.cli.style for bold headings/options. The warning can be plain text for test stability.
If styling is added, ensure tests strip ANSI where needed and the warning remains readable when color is disabled.
Performance
The global help path should read at most:
- the bundled source skill once
- the local installed skill if it exists
- the global installed skill if it exists
No recursive directory scan is needed.
Compatibility
This change does not need backward compatibility shims. It adds a warning only when a supported installed skill file exists and differs from the bundled content.
Do not add default values that mask invalid state inside the status helper. Return explicit status data instead.
Non-goals
- Do not automatically reinstall or overwrite the user's skill.
- Do not add a new
logseq skill statuscommand in this task. - Do not add a new db-worker
:thread-api/*. - Do not start db-worker-node during help.
- Do not check remote versions or network state.
- Do not add skill version metadata unless requested separately.
- Do not show the warning for users who have not installed the skill.
Final acceptance criteria
The implementation is complete when all of the following are true:
- Global help checks installed
logseq-cliskill freshness using local filesystem content comparison. - No warning is shown when no installed skill exists.
- No warning is shown when installed skill content matches the bundled skill.
- A warning is appended to the end of global help when an installed skill differs from the bundled skill.
- The warning appears in structured help inside the existing help message field.
- Group help, command help, version output, and normal command output do not show the warning.
- No new
:thread-api/*is added. - db-worker-node is not started or invoked for global help.
- Targeted CLI tests pass.
logseq-review-workflowhas been applied to the final implementation and any findings have been addressed or documented.