Files
logseq/libs/SKILL.md
Charlie 3c2359a79e enhance(plugins): libs improvements (#12588)
* enhance(libs): add Commands proxy and unified command APIs

* enhance(plugin): improve unregistering of simple and palette commands

* enhance(plugin): add unregister functionality for plugin commands

* chore(libs): add logseq.Commands API guide and implementation

* enhance(libs): introduce LSPluginNet for HTTP client functionality

* fix(ipc): ensure proper handling of IPC messages and improve plugin call structure

* enhance(libs): add HTTP methods (GET, HEAD, POST, PUT, PATCH, DELETE) and error handling

* enhance(api): support additional identifier types for opening blocks in sidebar

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-07 15:21:48 +08:00

9.0 KiB

name, description
name description
logseq-plugin-sdk Build, debug, or review Logseq plugins with the `@logseq/libs` SDK (TypeScript/JavaScript, iframe/shadow sandboxed). Use when the task involves writing plugin entry code, registering slash/command/UI items, provideUI/provideStyle/provideModel, settings schema, macro renderers, DB-graph properties & tags, Datascript/DSL queries, experimental APIs, theme plugins, or the `logseq/*` CLJS facade generated under this package.

Logseq Plugin SDK Skill

This skill governs work inside libs/ — the source of the npm package @logseq/libs and its CLJS facade under cljs-sdk/. Use it whenever the user is authoring, upgrading, or debugging a Logseq plugin, or extending the SDK itself.

When to use

Trigger this skill when the task mentions any of:

  • @logseq/libs, logseq.App, logseq.Editor, logseq.DB, logseq.UI, logseq.Assets, logseq.Git, logseq.Experiments
  • provideUI / provideStyle / provideModel / useSettingsSchema / onMacroRendererSlotted
  • registerSlashCommand, registerBlockContextMenuItem, registerCommandPalette, registerUIItem
  • Plugin package.json logseq block, themes, effect plugins, iframe/shadow sandbox
  • DB-graph properties, tags/classes, property idents (:logseq.property/*, :plugin.property.<id>/*)
  • Datascript / DSL queries through logseq.DB.q / logseq.DB.datascriptQuery
  • Regenerating the CLJS SDK (yarn run generate:schema, bb libs:generate-cljs-sdk)

If the user is editing core Logseq app code (not a plugin), prefer the repo-root AGENTS.md instead.

Golden rules

  1. Always await logseq.ready(main) before touching any API. Most SDK calls are async RPC over postMessage.
  2. Detect graph mode before using DB-only APIs: await logseq.App.checkCurrentIsDbGraph(). IBatchBlock.properties is not supported for DB graphs — use Editor.upsertBlockProperty / upsertProperty instead.
  3. Clean up listeners in logseq.beforeunload (collect the off functions returned by every onXxx hook).
  4. Batch mutations (Editor.insertBatchBlock) and debounce DB.onChanged / onBlockChanged handlers — they fire on every keystroke.
  5. Prefer CSS variables (--ls-primary-text-color, --ls-primary-background-color, --ls-border-color, …) over hard-coded colors so plugins follow the active theme.
  6. Unique plugin id in package.json > logseq.id; keep it lowercase-kebab. main/entry must point at a built HTML file.
  7. Experimental APIs (logseq.Experiments.*) are unstable — only use when no stable API exists and document the reason.
  8. Idents are identity. For built-in or cross-graph stable references, use idents (:logseq.property/created-at, :plugin.property.<plugin-id>/<key>) instead of display names.

Canonical plugin skeleton

import '@logseq/libs'

const offHooks: Array<() => void> = []

async function main() {
  logseq.useSettingsSchema([
    { key: 'enabled', type: 'boolean', default: true, title: 'Enabled', description: '' },
  ])

  logseq.Editor.registerSlashCommand('My Command', async () => {
    await logseq.Editor.insertAtEditingCursor('Hello from my plugin!')
  })

  offHooks.push(
    logseq.DB.onChanged(({ blocks }) => {
      // debounce in real code
    }),
  )

  logseq.beforeunload(async () => {
    offHooks.forEach((off) => off())
  })
}

logseq.ready(main).catch(console.error)

Workflow

  1. Scope the request. Is it a new plugin, a change to an existing plugin, SDK-internal work, or the CLJS facade?
  2. Load the right reference file(s) from ./guides/ (see table below) before proposing code.
  3. For SDK-internal changes, open the matching TypeScript under ./src/ (LSPlugin.ts for types, LSPlugin.user.ts for the proxy implementation, modules/ for Experiments/Storage/Request).
  4. For CLJS facade changes, regenerate with:
    yarn run generate:schema          # dist/logseq-sdk-schema.json
    bb libs:generate-cljs-sdk         # target/generated-cljs/logseq/*.cljs
    
    Non-proxy methods land in logseq.core; each IXxxProxy gets its own namespace (logseq.app, logseq.editor, …).
  5. Validate. Build the plugin (npm run build / parcel build) and load it via Settings → Developer mode → t pLoad unpacked plugin. Use DevTools (Cmd+Shift+I) and logseq.UI.showMsg for quick feedback.
  6. Respect the package.json rules (see guides/AGENTS.md §Configuration Fields).

Reference map (./guides/)

Load these on demand — do not dump their full contents unless needed:

File Load when…
guides/AGENTS.md Authoritative overview of SDK namespaces, package.json > logseq schema, theme plugins, UI injection, macro renderers, lifecycle. Start here for most plugin tasks.
guides/custom_theme_guide.md Building or reviewing Logseq theme plugins, custom theme CSS, logseq.themes, provideTheme, theme variables, light/dark mode styling, or UI selector/theme-token guidance.
guides/starter_guide.md Bootstrapping a new plugin project (Node/TS toolchain, desktop dev-mode loading, hello-world).
guides/commands_api_guide.md logseq.Commands unified command bus, placements, command execution, unregister handlers, and migration from legacy command APIs.
guides/db_properties_guide.md Conceptual model: file-graph vs DB-graph properties, schema vs values, tag/class modeling.
guides/db_properties_references.md API reference for upsertProperty, upsertBlockProperty, property schemas/types/cardinality.
guides/db_tag_property_idents_guide.md Ident naming rules (:logseq.property/*, :logseq.class/*, :plugin.property.<id>/*, :plugin.class.<id>/*) and when to use them.
guides/db_query_guide.md DSL (logseq.DB.q) vs Datascript (logseq.DB.datascriptQuery) queries, parameters, change watchers.
guides/experiments_api_guide.md logseq.Experiments.* — React/ReactDOM reuse, internal components, CLJS interop, custom fenced-code / route / sidebar / property / block-body renderers.

Core API quick index

Full code examples live in guides/AGENTS.md — use this table to jump to the right namespace:

  • logseq.App — info, graph, navigation, registerUIItem, registerCommandPalette, lifecycle hooks (onCurrentGraphChanged, onThemeModeChanged, onRouteChanged, onMacroRendererSlotted), checkCurrentIsDbGraph.
  • logseq.Editor — slash & context-menu commands, block CRUD, insertBatchBlock, pages, cursor/selection, upsertBlockProperty / getBlockProperties (DB).
  • logseq.DBq, datascriptQuery, onChanged, onBlockChanged, getFileContent / setFileContent.
  • logseq.UIshowMsg, closeMsg, queryElementRect, queryElementById.
  • logseq.AssetslistFilesOfCurrentGraph, makeSandboxStorage, makeUrl, builtInOpen.
  • logseq.GitexecCommand, loadIgnoreFile, saveIgnoreFile (file graphs / desktop only).
  • logseq.Experiments — unstable; see the Experiments guide before using.
  • Top-level — provideUI, provideStyle, provideModel, useSettingsSchema, onSettingsChanged, updateSettings, showMainUI / hideMainUI / toggleMainUI / setMainUIInlineStyle, beforeunload, ready.

Common pitfalls

  • Forgetting await — nearly every API is async.
  • Using IBatchBlock.properties in a DB graph (silently ignored).
  • Treating block.content as current — it is deprecated; use block.title.
  • Registering the same key twice in provideUI / provideStyle without intending to replace.
  • Hard-coding colors instead of --ls-* CSS variables.
  • Leaking listeners (no cleanup in beforeunload).
  • Shipping plugins without logseq.id or with a non-unique id.
  • Assuming Git APIs exist on mobile / DB graphs.

When editing SDK source

  • Type definitions: src/LSPlugin.ts. Keep IAppProxy, IEditorProxy, IDBProxy, IUIProxy, IAssetsProxy, IGitProxy, IExperimentsProxy and the ILSPluginUser surface in sync.
  • User proxy implementation: src/LSPlugin.user.ts.
  • Modules: src/modules/ (Experiments, Storage, Request).
  • After changing the public surface, regenerate the CLJS facade (see Workflow step 4) and update CHANGELOG.md.
  • Follow the repo commit style: short imperative subjects, optional scope (e.g. enhance(libs): …, fix(libs): …).

Resources