jacobinwwey_obsidian-NotEMD/docs/maintainer/notemd-cli-capability-matrix.md

30 KiB

Notemd CLI Capability Matrix

Updated: 2026-07-02

Status Call (2026-05-25)

Short answer: current main now carries a deliberate two-tier CLI story, not a single widened surface.

What is landed on current main:

  • registry-backed operation metadata
  • typed capability / invocation export
  • a bounded public-safe export slice
  • a repo-local maintainer helper that covers the same export slice plus explicit path-based maintainer operations with JSON/file payload input

What is intentionally not claimed:

  • broad user-facing CLI support for active-file, selection, or preview flows
  • promotion of the current path-based maintainer operations into the public-safe slice
  • a broad public CLI API over mutable note-processing flows

This matrix is a maintainer control document. It distinguishes:

  • commands that the official obsidian CLI can already trigger today
  • commands that are safe for automation versus only safe for manual invocation
  • lower-level Notemd capabilities that should become first-class operations before wider CLI exposure

2026-07-02 Cross-Platform Process Closeout

This closeout does not widen the public CLI surface. It fixes the process-launch layer used by the maintainer helper, release helpers, repo-saga helpers, package-manager calls, and Slidev export environment probing.

Root cause:

  • POSIX direct execution worked because executable scripts and shebangs resolve through the normal execve path.
  • Windows failed on bare commands and .cmd / .bat shims when the code tried to use direct execFile-style spawning. That failure surfaced in Obsidian as spawn EINVAL during "检测演示导出环境".
  • A blanket Windows shell: true fallback is not acceptable because it changes argument parsing and can corrupt arguments that contain JSON, quotes, or code fragments such as code=...=>....

Current resolution model:

Platform / command kind Execution strategy
Linux / macOS Direct exec first; no shell layer added for normal commands
Windows .exe / .com Direct exec
Windows .cmd / .bat Explicitly resolved batch shim, then cmd.exe /d /s /c call "<shim>" ... with Windows argv quoting
Windows .js / .mjs / .cjs Run through process.execPath
Bare Windows command names Resolve through PATH + PATHEXT, then dispatch by resolved extension

Evidence captured in this batch:

  • process-level tests cover fake git.cmd, gh.cmd, obsidian-cli.cmd, pnpm.cmd, Node script execution, stderr passthrough, JSON input, and unparseable native-eval failures without depending on a live desktop session;
  • the Obsidian runtime path was checked with obsidian command id=notemd:probe-slide-export-environment;
  • standalone obsidian-cli is not installed in the local Windows environment, while the official obsidian CLI trigger surface is available.

Boundary:

  • obsidian command id=<command-id> remains a trigger surface, not a typed public API;
  • maintainer path-based operations remain maintainer-only until side effects, output schemas, failure modes, and user-facing docs are promoted together;
  • this fix only makes existing maintainer and export checks portable across Windows, Linux, and macOS.

Automation Levels

Level Meaning
safe Non-interactive, deterministic enough for scripted triggering
requires-active-file Needs an active note/file context and should not be treated as a general automation endpoint yet
requires-selection Depends on editor selection or interactive editor state
interactive-ui Depends on modal, picker, preview, split-pane, or human-facing UI flow

Official CLI Trigger Surface

Observed host facts:

  • obsidian commands filter=notemd lists current plugin commands
  • official CLI can trigger them with obsidian command id=<command-id>
  • this is a trigger surface only, not a mature typed integration layer
  • the registry-backed capability export now keeps command palette, hotkey, and official CLI trigger surfaces attached to the same command bindings

Current Bounded Public Slice

The current public-safe slice is intentionally narrow. It only includes commands that are:

  • safe
  • requiredContext=none
  • mappingKind=exact
  • exposed on the official CLI trigger surface
  • backed by an empty-object input schema

Current command IDs in this slice:

  • notemd:export-provider-profiles-redacted
  • notemd:export-cli-capability-manifest
  • notemd:export-cli-invocation-contract
  • notemd:export-cli-public-surface

Guardrails:

  • raw provider export is excluded because it carries outputHandlingTags=contains-provider-credentials
  • redacted provider export is intentionally non-importable, so sanitized payloads cannot be mistaken for live settings snapshots
  • redacted export still may reveal private/custom baseUrl infrastructure, so it is safer than raw export, not automatically safe for public sharing

Repo-Local Maintainer Helper

The repo now also carries a small maintainer helper over obsidian-cli native eval:

  • help: npm run cli:help
  • invoke: npm run cli:invoke -- --vault <vault> --operation <operation-id> [--input-file <path> | --input-json '<json>'] [--pretty]
  • supported operation ids:
    • content.batch-generate-from-titles
    • content.split-note-by-chapters
    • research.summarize-topic
    • diagram.generate
    • local-knowledge.inspect
    • provider.profile.export-redacted
    • cli.capability-manifest.export
    • cli.invocation-contract.export
    • cli.public-surface.export

Boundary:

  • this is maintainer-grade repo tooling, not a public CLI API
  • the operation catalog lives in scripts/lib/maintainer-cli-operation-help.js as shared maintainer helper metadata, including compact example payloads for the path-based operations
  • the checked-in scripts/invoke-maintainer-cli-operation.js entrypoint is now also process-level regression-locked: --help, --input-json, --input-file, --pretty, child stderr passthrough, and unparseable obsidian-cli native eval failures are covered without depending on a live desktop session
  • export operations remain empty-payload only; bounded content operations accept explicit JSON input
  • minimal inspect example: npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"diagramGeneration","sourcePath":"index.zh-CN.md","knowledgePaths":["maintainer","superpowers"]}' --pretty
  • for --vault docs, all sourcePath and knowledgePaths values are vault-relative; use index.zh-CN.md and maintainer, not docs/index.zh-CN.md or docs/maintainer
  • local-knowledge.inspect is intentionally maintainer-only explainability surface: it exposes task scope, effective knowledge-base path resolution, derived or explicit query, query diagnostics, current-file exclusion inputs, retrieval options, candidate file paths, raw formatted context, structured contextBlocks evidence, and the structured retrieval summary without widening the public CLI contract
  • local-knowledge.inspect currently makes three query-derivation paths visible and test-backed: explicit (for direct research queries), basename (for title/batch-title task scopes), and diagram-source (for diagram generation derived from source basename plus stripped note content). The inspect result now also surfaces bounded query diagnostics, including generic navigation-basename cautions for low-signal sources such as index.*
  • local-knowledge.inspect now also accepts a temporary knowledgePaths override array, so maintainers can inspect task-scoped retrieval against ad hoc file/folder path lists without mutating the saved settings snapshot
  • local-knowledge.inspect also keeps failure-state explainability explicit instead of collapsing every miss into the same empty result: retrieverBuildStatus distinguishes no-paths, no-candidate-files, no-retrievable-sections, and ready, while candidateFilePaths and the structured retrieval summary stay available for debugging
  • additional inspect examples now cover the real task-scoped retrieval lanes, plus reproducible failure-state probes, not only the diagram lane:
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"batchGenerateFromTitles","sourcePath":"index.zh-CN.md"}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"task-scoped retrieval behavior","knowledgePaths":["maintainer"]}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"chapter split TOC managed artifacts guarded reruns","knowledgePaths":["chapter-split-toc.md","chapter-split-toc.zh-CN.md"]}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"real-note query diversity beyond chapter split showcase","knowledgePaths":["brainstorms","maintainer"],"topK":2,"slidingWindowSize":1}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"MiniSearch ragas RAGPerf execution chain maintainer-only offline evidence","knowledgePaths":["brainstorms/2026-06-09-local-kb-rag-quality-and-execution-truth.md"],"topK":2,"slidingWindowSize":1,"maxSnippetChars":640}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"managed-artifact kpm markdown-toc active-file scoped stable block refs","knowledgePaths":["brainstorms/2026-06-09-chapter-split-knowledge-management-and-toc-comparison-truth.md"],"topK":2,"slidingWindowSize":1,"maxSnippetChars":640}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"batchGenerateFromTitles","sourcePath":"brainstorms/2026-05-28-mainline-progress-audit-and-next-level-direction.md","knowledgePaths":["brainstorms","maintainer"],"topK":2,"slidingWindowSize":1}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"diagramGeneration","sourcePath":"index.zh-CN.md","knowledgePaths":["brainstorms","maintainer"],"topK":2,"slidingWindowSize":1}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"missing path coverage","knowledgePaths":[]}' --pretty
    • npm run cli:invoke -- --vault docs --operation local-knowledge.inspect --input-json '{"taskScope":"researchSummarize","query":"svg-only repo saga scope","knowledgePaths":["repo-saga"]}' --pretty
  • content.split-note-by-chapters also accepts optional splitHeadingLevel (auto, h1-h6) so scripts can avoid depending on the current settings snapshot
  • content.split-note-by-chapters results now also expose requestedSplitHeadingLevel, chapterNotePaths, managedArtifactPaths, removedStalePaths, deterministic tocMetadata, and stable nestedHeadings[].blockId values so automation can reason about the managed artifact set, TOC front-matter metadata, and repeated-heading-safe TOC targets without re-deriving them from filenames or ambiguous heading text; reruns now also refuse to overwrite or delete manifest-managed artifacts whose contents drifted from the last generated snapshot
  • path-based maintainer operations stay maintainer-only until their side effects, output schemas, and failure semantics are promoted as part of a public contract batch

Current Command Matrix

Command ID Current Purpose Automation Level Why It Is Not Yet a Stable Engineering API Registry Operation Mapping
notemd:test-llm-connection Test active provider connectivity safe Typed input/result schemas now exist, but the interactive busy/reporter path and notice wording still belong to the host UI provider.connection.test (exact)
notemd:run-developer-provider-diagnostic Run long-request provider diagnostic safe Typed input/result schemas now exist, but long-running network behavior and report persistence still make this a maintainer-grade surface rather than a stable public API provider.diagnostic.run (exact)
notemd:run-developer-provider-stability-diagnostic Run repeated provider stability diagnostic safe Typed input/result schemas now exist, but repeated live-provider execution still behaves like a maintainer-grade diagnostic surface rather than a stable public API provider.diagnostic.stability-run (exact)
notemd:export-provider-profiles Export raw provider profile snapshot safe Deterministic and machine-readable, but the exported file contains provider credentials and remains a maintainer-sensitive surface rather than part of the public-safe slice provider.profile.export
notemd:export-provider-profiles-redacted Export redacted provider profile snapshot safe Part of the bounded public-safe slice. Deterministic, machine-readable, strips API keys, and is intentionally non-importable, but may still expose private/custom endpoint metadata provider.profile.export-redacted
notemd:import-provider-profiles Import provider profile snapshot safe Machine-readable, but mutates active provider state and plugin settings provider.profile.import
notemd:export-cli-capability-manifest Export command capability manifest safe Part of the bounded public-safe slice. Deterministic export, but still tied to plugin config-path write semantics cli.capability-manifest.export
notemd:export-cli-invocation-contract Export typed invocation contract safe Part of the bounded public-safe slice. Deterministic export, but still tied to plugin config-path write semantics cli.invocation-contract.export
notemd:export-cli-public-surface Export bounded public CLI surface safe Part of the bounded public-safe slice. Self-describes the currently supported official-CLI-safe subset cli.public-surface.export
notemd:notemd-generate-diagram Generate spec-first artifact from active file requires-active-file Typed result now exposes the wrapper envelope plus explicit follow-through details (kind, executionMode, sourcePath, actionLabel, operationInput, generation, followThrough, outputPath, previewOpened) and a machine-readable local-KB retrieval summary (localKnowledgeContextUsed, localKnowledgeRetrieval) for artifact-generation modes, but active-file dependency, plugin state, and save/open side effects still keep this below a stable public API diagram.generate (exact, defaultInput.outputMode=artifact)
notemd:notemd-summarize-as-mermaid Save Mermaid output for active file requires-active-file Typed result now exposes the wrapper envelope plus explicit follow-through details (kind, executionMode, sourcePath, actionLabel, operationInput, generation, followThrough, outputPath, previewOpened), but active-file dependency plus plugin-managed save/output semantics still keep this below a stable public API diagram.generate (exact, defaultInput.outputMode=mermaid)
notemd:notemd-preview-diagram Preview saved/sourced diagram interactive-ui Typed input/result schemas now describe the preview artifact boundary, but opening the preview modal is still UI-bound and not automation-stable diagram.preview (exact)
notemd:process-with-notemd Process current file and add links requires-active-file Structured file result now exists, but active-file dependency, concept-note creation, output-path policy, and vault mutation still block stable automation file.process-add-links
notemd:process-folder-with-notemd Batch process folder interactive-ui Structured batch result now exists with savedCount / errors / cancelled, but folder selection, mutating batch execution, and post-process Mermaid auto-fix remain host driven file.process-folder-add-links
notemd:generate-content-from-title Generate note content from title requires-active-file Structured result now also exposes localKnowledgeContextUsed plus a machine-readable localKnowledgeRetrieval summary (matchedSectionCount, returnedHitCount, sourcePaths, sliding-window/current-file-exclusion telemetry, index/query timing, context-char count), but active-file dependency, writeback semantics, and optional research side effects still bind it to the plugin host content.generate-from-title
notemd:batch-generate-content-from-titles Batch title generation interactive-ui Structured batch result now carries the same per-file local-KB retrieval summary, including timing/size telemetry, in addition to complete-folder move semantics and aggregated errors, but folder selection, progress UI, and vault mutation still require host coordination content.batch-generate-from-titles
notemd:split-note-by-chapters Split the active note into chapter files plus TOC/manifest requires-active-file Registry/contract coverage now exists and the maintainer helper can invoke the same operation with explicit sourcePath plus optional splitHeadingLevel; the typed result now also describes the managed artifact set directly, exposes deterministic TOC front-matter metadata plus stable nested block refs for repeated-heading-safe TOC targets, and guards reruns against silently overwriting manually edited generated files, but the user-facing command trigger is still active-file-bound and remains a write-heavy mutation flow content.split-note-by-chapters
notemd:research-and-summarize-topic Research selected text / active note title requires-selection The path-based result now exposes outputPath, sourceLabel, researchContextUsed, localKnowledgeContextUsed, and a machine-readable localKnowledgeRetrieval summary with timing/size telemetry, but the user-facing command still depends on active editor or active note state research.summarize-topic
notemd:translate-file Translate current active note requires-active-file Structured result and host-owned success notice now exist, but active-file dependency, settings-driven output-path policy, and vault-write side effects still block stable automation translate.file
notemd:batch-translate-folder Batch translate a folder interactive-ui Folder selection remains interactive; structured batch results and host-owned success notices now exist, but folder-picker dependency and mutating batch execution still keep it out of stable automation translate.folder-batch
notemd:extract-concepts-from-current-file Extract concepts from active file requires-active-file Active file + note-creation side effects concept.extract-file
notemd:batch-extract-concepts-from-folder Extract concepts across folder interactive-ui Folder selection and progress UI still host-bound concept.extract-folder
notemd:extract-original-text Extract configured source snippets from active file requires-active-file Structured result now exists, but active-file dependency and output-path persistence remain host/settings bound content.extract-original-text
notemd:extract-concepts-and-generate-titles Compound extract+generate flow requires-active-file Composite workflow without explicit typed contract workflow.extract-and-generate
notemd:create-wiki-link-and-generate-from-selection Selection-driven concept note generation requires-selection Editor selection is intrinsic editor.create-link-and-generate
notemd:batch-mermaid-fix Batch Mermaid repair interactive-ui Structured batch result now exists, but folder selection, mutable repair flow, report generation, and optional error-file moves still require interactive host semantics mermaid.batch-fix
notemd:fix-formula-formats Fix formulas in current file requires-active-file Structured file result now exists, but active-file dependency and inline vault mutation still block stable automation formula.fix-file
notemd:batch-fix-formula-formats Batch formula repair interactive-ui Structured batch result now exists, but folder selection and mutating batch execution still require interactive host semantics formula.batch-fix
notemd:check-for-duplicates Check current note duplicates requires-active-file Result is console/notice-oriented duplicate.check-file
notemd:check-and-remove-duplicate-concept-notes Remove duplicate concept notes interactive-ui Structured scan/delete result now exists and confirmation is host-owned, but destructive confirmation plus folder-scoped mutation still keep it out of stable automation concept.dedupe

Registry Status

  • src/operations/registry.ts is now the central metadata source for extracted operations, command bindings, mapping kind, and selected input/result schemas.
  • src/operations/capabilityManifest.ts now flattens those command bindings into the exported capability manifest.
  • capability/public-surface metadata now also carries handling tags, so callers can distinguish secret-bearing exports from redacted/public-safe ones without a second hard-coded rule
  • src/cliContracts.ts now builds the invocation contract from the same registry, which removes one major drift path between docs, command discovery, and contract export.
  • The registry now includes the main note-processing, utility, selection, and export operation batches as well: editor.create-link-and-generate, file.process-add-links, file.process-folder-add-links, content.generate-from-title, content.batch-generate-from-titles, content.split-note-by-chapters, research.summarize-topic, translate.file, translate.folder-batch, concept.extract-file, concept.extract-folder, content.extract-original-text, workflow.extract-and-generate, duplicate.check-file, concept.dedupe, mermaid.batch-fix, formula.fix-file, formula.batch-fix, provider.profile.export, provider.profile.export-redacted, provider.profile.import, cli.capability-manifest.export, cli.invocation-contract.export, and cli.public-surface.export.
  • src/operations/publicCliSurface.ts now derives the bounded public-safe slice from the same registry/capability/contract pair instead of maintaining a parallel command allowlist.
  • file.process-add-links, file.process-folder-add-links, content.generate-from-title, content.batch-generate-from-titles, mermaid.batch-fix, concept.dedupe, translate.*, formula.*, and content.extract-original-text now form the current proof set for write-heavy contract enrichment: utility cores return structured results, host adapters own localized success/no-file/confirmation semantics, and the registry exports the richer schemas directly.
  • content.generate-from-title, content.batch-generate-from-titles, research.summarize-topic, and artifact-mode diagram.generate now also expose machine-readable local-KB retrieval summaries instead of reducing retrieval to a boolean-only side note. Current summaries include indexed counts, matched/returned section counts, expanded section counts, source paths, requested topK, sliding-window size, current-file exclusion telemetry, index-build ms, query ms, and final context-char count.
  • a dedicated offline retrieval-quality fixture now exists as npm run verify:local-kb-fixtures; it reuses the live MiniSearch-based runtime path against a small maintainer fixture set instead of introducing a separate evaluation-only retriever, and the current Stage-C slice now also covers task-scoped batch-title and research inspect cases, exact-file-vs-folder retrieval boundaries, noisy mixed-corpus scope handling with duplicate/whitespace override paths, non-Markdown distractions, unrelated folders, empty-section candidates, real-note-style chapter-split showcase retrieval, and cross-folder real-note/query diversity beyond the chapter-split showcase instead of only one diagram-oriented example.
  • content.split-note-by-chapters now follows the same direction more explicitly: the result shape names the requested heading level, chapter note paths, full managed artifact set, deterministic TOC front-matter metadata, stale removals, and stable nested-heading block-ref ids instead of forcing callers to infer them indirectly from counts, filenames, or duplicate heading text, and reruns now fail fast when previously generated artifacts were manually edited.
  • diagram.generate now carries an explicit typed follow-through layer beneath the host-neutral generation core: followThrough.kind differentiates Mermaid save, artifact save, and preview completion while preserving backward-compatible top-level outputPath / previewOpened, and artifact-generation modes now also surface the local-KB retrieval telemetry through the same structured result.
  • The first checked-in semantic-verification helper now exists as npm run verify:diagram-semantics; it turns the maintainer runbook into a reusable, secret-free checklist artifact instead of leaving semantic verification as prose-only guidance.
  • The next contract-deepening order is now more precise: keep diagram.generate as the host-neutral generation core, treat the follow-through shape beneath it as landed, then move to packaging/semantic-verification convergence and only after that revisit broader CLI/public-surface claims.
  • Legacy aliases remain registered for compatibility, but they are intentionally excluded from capability-manifest export.

Next Extraction Targets

These are the best remaining candidates for registry-backed or more host-neutral operations.

Priority Candidate Why First Existing Building Blocks
P0 Packaging source/build convergence around the latent render-host runtime lane Current source still contains reusable runtime helpers (src/rendering/runtime/renderHostEntry.ts, src/rendering/preview/renderHostRuntimeClient.ts), but build/audit truth still proves main.js-only shipping. Current main keeps that latent lane fail-closed by returning no default standalone runtime-module specifier unless one is configured explicitly, and the production build path keeps createRenderHostBundleBuildOptions() candidate-only outside esbuild.config.mjs. The next higher-leverage step is no longer to merely document source-only status; it is to preserve that executable guard until a future batch either keeps the lane source-only or ships a true multi-entry boundary with build, release assets, audit, and docs moving together esbuild.config.mjs, scripts/audit-render-host-bundle.js, scripts/lib/esbuild-bundle-config.js, src/rendering/runtime/renderHostEntry.ts, src/rendering/preview/renderHostRuntimeClient.ts
P1 Bounded public-CLI promotion for explicit path-based operations The maintainer helper already proves there is demand for path-based operations, but public promotion should happen only for operations whose write semantics and output contracts are stable enough to document and regression-lock src/maintainerCliBridge.ts, scripts/lib/maintainer-cli-operation-help.js, src/operations/registry.ts, src/tests/maintainerCliBridge.test.ts
P1 Contract/result hardening for retrieval and chapter-split writes Retrieval-dependent note-processing results, including artifact-mode diagram.generate, now expose machine-readable localKnowledgeRetrieval summaries with timing/size telemetry, the shared maintainer helper now carries compact payload examples plus a dedicated local-knowledge.inspect seam for effective path/query/context inspection, query-derivation visibility (explicit, basename, diagram-source), explicit failure-state explainability through retrieverBuildStatus, temporary knowledgePaths override arrays for task-scoped retrieval tuning, and npm run verify:local-kb-fixtures now locks a broader offline retrieval-quality fixture set across exact/prefix/current-file-exclusion classes, task-scoped batch-title and research inspect cases, noisy mixed-corpus scope handling with duplicate/whitespace override paths, non-Markdown distractions, unrelated folders, empty-section candidates, real-note-style chapter-split showcase retrieval, cross-folder task-contract retrieval, and low-signal navigation-source diagnostics. Chapter split also emits repeated-heading-safe nested block refs, deterministic TOC front-matter metadata, plus guarded rerun overwrite semantics. The next maturity gain is to keep expanding additional real-note/query diversity and chapter-split showcase alignment rather than broadening the surface count src/chapterSplit.ts, src/localKnowledgeBase.ts, src/fileUtils.ts, src/searchUtils.ts, src/main.ts, src/tests/localKnowledgeEvaluationFixture.test.ts, scripts/lib/maintainer-cli-operation-help.js, src/tests/chapterSplit.test.ts, src/tests/localKnowledgeTaskIntegration.test.ts, src/tests/diagramCommandArchitecture.test.ts, src/tests/localKnowledgeBase.test.ts, src/tests/maintainerCliBridge.test.ts
P2 Workflow/settings packaging Workflow DSL and output-path toggles remain useful metadata but not yet stable public interfaces src/workflowButtons.ts, settings-driven output controls

Settings Readiness

Setting / Area CLI Reuse Readiness Notes
Provider name / model High Explicit and already task-scoped
preferredDiagramIntent High Natural operation input
Developer diagnostic mode / timeout / runs High Already structured
localOnly semantics Medium-high Must be preserved in export/import/profile contract
Workflow DSL Medium Good metadata source, not yet stable public API
Output path toggles Medium Useful, but currently tangled with plugin writeback behavior
UI locale / notices / modal text Low UI-only concern

Do not promote a Notemd command to “CLI supported” only because obsidian command id=<id> works.

Do not promote it only because it is hotkey-bindable either. Command palette, hotkey, and official CLI triggering are useful surfaces, but they are still not the contract.

Promote it only when all of the following are true:

  1. inputs are explicit
  2. outputs are machine-readable
  3. side effects are documented
  4. progress/failure semantics are deterministic
  5. no hidden dependency on active editor/UI state remains