Marketplace building-logseq-plugins
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/c0ntr0lledcha0s/building-logseq-plugins" ~/.claude/skills/aiskillstore-marketplace-building-logseq-plugins && rm -rf "$T"
manifest:
skills/c0ntr0lledcha0s/building-logseq-plugins/SKILL.mdsource content
Building Logseq Plugins
When to Use This Skill
This skill auto-invokes when:
- User wants to create a Logseq plugin
- Questions about the Logseq Plugin API
- Working with logseq.Editor, logseq.DB, logseq.App namespaces
- Slash command registration
- Plugin settings schema definition
- DB vs MD version compatibility for plugins
- User mentions "logseq plugin", "logseq extension", "@logseq/libs"
You are an expert in Logseq plugin development, with special focus on DB-version compatibility.
Plugin Architecture Overview
Logseq plugins run in sandboxed iframes and communicate with the main app via the Plugin API.
Plugin Structure
my-logseq-plugin/ ├── package.json # Plugin manifest ├── index.html # Entry point ├── index.js # Main logic (or TypeScript) ├── icon.png # Plugin icon (optional) └── README.md # Documentation
package.json Manifest
{ "name": "logseq-my-plugin", "version": "1.0.0", "main": "index.html", "logseq": { "id": "my-plugin-id", "title": "My Plugin", "icon": "./icon.png", "description": "Plugin description" } }
Plugin API Basics
Initialization
import '@logseq/libs' async function main() { console.log('Plugin loaded') // Register commands, settings, etc. logseq.Editor.registerSlashCommand('My Command', async () => { // Command logic }) } logseq.ready(main).catch(console.error)
Key API Namespaces
| Namespace | Purpose |
|---|---|
| Block/page manipulation |
| Database queries |
| App-level operations |
| UI components |
| Plugin settings |
DB-Version Specific APIs
Working with Properties
// Get block with properties (DB version) const block = await logseq.Editor.getBlock(blockUuid, { includeChildren: true }) // Properties are structured differently in DB version // Access via block.properties object const author = block.properties?.author // Set property value await logseq.Editor.upsertBlockProperty(blockUuid, 'author', 'John Doe')
Working with Classes/Tags
// Get blocks with a specific tag/class const books = await logseq.DB.datascriptQuery(` [:find (pull ?b [*]) :where [?b :block/tags ?t] [?t :block/title "Book"]] `) // Add tag to block await logseq.Editor.upsertBlockProperty(blockUuid, 'tags', ['Book', 'Fiction'])
Enhanced Block Properties APIs (2024+)
// New APIs for DB version await logseq.Editor.getBlockProperties(blockUuid) await logseq.Editor.setBlockProperties(blockUuid, { author: 'Jane Doe', rating: 5, published: '2024-01-15' })
Datalog Queries in Plugins
Basic Query
const results = await logseq.DB.datascriptQuery(` [:find ?title :where [?p :block/title ?title] [?p :block/tags ?t] [?t :db/ident :logseq.class/Page]] `)
Query with Parameters
const results = await logseq.DB.datascriptQuery(` [:find (pull ?b [*]) :in $ ?tag-name :where [?b :block/tags ?t] [?t :block/title ?tag-name]] `, ['Book'])
DB vs MD Query Differences
// MD version - file-based queries const mdQuery = ` [:find ?content :where [?b :block/content ?content] [?b :block/page ?p] [?p :block/name "my-page"]] ` // DB version - entity-based queries const dbQuery = ` [:find ?title :where [?b :block/title ?title] [?b :block/tags ?t] [?t :block/title "My Tag"]] `
UI Components
Slash Commands
logseq.Editor.registerSlashCommand('Insert Book Template', async () => { await logseq.Editor.insertAtEditingCursor(` - [[New Book]] #Book author:: rating:: status:: To Read `) })
Block Context Menu
logseq.Editor.registerBlockContextMenuItem('Convert to Task', async (e) => { const block = await logseq.Editor.getBlock(e.uuid) await logseq.Editor.upsertBlockProperty(e.uuid, 'tags', ['Task']) await logseq.Editor.upsertBlockProperty(e.uuid, 'status', 'Todo') })
Settings Schema
logseq.useSettingsSchema([ { key: 'apiKey', type: 'string', title: 'API Key', description: 'Your API key for the service', default: '' }, { key: 'enableFeature', type: 'boolean', title: 'Enable Feature', default: true }, { key: 'theme', type: 'enum', title: 'Theme', enumChoices: ['light', 'dark', 'auto'], default: 'auto' } ])
DB-Version Compatibility Checklist
When building plugins for DB version:
- Use
instead of:block/title
for page names:block/content - Handle structured properties (not just strings)
- Support typed property values (numbers, dates, checkboxes)
- Use tag-based queries instead of namespace queries
- Test with both DB and MD graphs if supporting both
- Handle the unified node model (pages ≈ blocks)
- Use new block properties APIs when available
Common Patterns
Feature Detection
async function isDBGraph() { // Check if current graph is DB-based const graph = await logseq.App.getCurrentGraph() return graph?.name?.includes('db-') || graph?.type === 'db' } async function main() { const isDB = await isDBGraph() if (isDB) { // DB-specific initialization } else { // MD-specific initialization } }
Property Type Handling
function formatPropertyValue(value, type) { switch (type) { case 'date': return new Date(value).toISOString().split('T')[0] case 'number': return Number(value) case 'checkbox': return Boolean(value) case 'node': return `[[${value}]]` default: return String(value) } }
Development Workflow
- Setup: Clone logseq-plugin-template or start fresh
- Develop: Use
for hot reloadnpm run dev - Test: Load unpacked plugin in Logseq
- Build:
for productionnpm run build - Publish: Submit to Logseq Marketplace
Loading Development Plugin
Logseq > Settings > Advanced > Developer Mode: ON Logseq > Plugins > Load unpacked plugin > Select folder