Obsidian Plugin Plan
Goal
Build an Obsidian community plugin that lets users fetch, edit, and publish markdown documents to demarkus servers directly from their vault.
Architecture
Bridge: Shell out to demarkus CLI via Node.js child_process.execFile. Obsidian runs in Electron with full Node.js access, so no HTTP proxy or new infra needed. Users must have demarkus installed (detected on plugin load).
Plugin type: Standard Obsidian community plugin (TypeScript, esbuild, manifest.json).
Location: plugins/obsidian/ in the demarkus monorepo. Published separately to the Obsidian community plugin registry.
MVP Scope
Commands
- Demarkus: Fetch Document — Prompt for
mark://URL, fetch via CLI, create/update note in vault - Demarkus: Publish Note — Publish current note to a configured demarkus server
- Demarkus: List Documents — Show documents on a server, pick one to fetch
Settings
- Server URL — default
mark://host (e.g.,mark://soul.demarkus.io) - Token — capability token for publish operations (stored in Obsidian settings, never in vault files)
- CLI Path — path to
demarkusbinary (auto-detected, override in settings) - Insecure — allow self-signed certs (for local dev servers)
Frontmatter Handling
Demarkus responses include YAML frontmatter (status, version, modified, etag, content-hash). On fetch:
- Store
mark-url,mark-version, andmark-etagin note frontmatter - Strip protocol metadata (status, content-hash) — not useful in vault
On publish:
- Read
mark-urlfrom frontmatter to know where to publish - Use
mark-versionfor optimistic concurrency (expected-version) - Update frontmatter with new version after successful publish
CLI Integration
// Fetch
execFile('demarkus', ['fetch', url], callback)
// Publish
execFile('demarkus', ['publish', url, '--expected-version', version, '--token', token], {
input: noteContent // pipe body via stdin
}, callback)
// List
execFile('demarkus', ['list', url], callback)
Parse CLI output (YAML frontmatter + markdown body) to extract metadata and content.
File Structure
plugins/obsidian/
├── src/
│ ├── main.ts — Plugin class, command registration
│ ├── settings.ts — Settings tab
│ ├── cli.ts — demarkus CLI wrapper (execFile + output parsing)
│ └── frontmatter.ts — Frontmatter read/write helpers
├── manifest.json
├── package.json
├── tsconfig.json
├── esbuild.config.mjs
└── README.md
Implementation Steps
- Scaffold from obsidian-sample-plugin template
- Implement CLI wrapper (
cli.ts) — execFile, parse YAML frontmatter + body from stdout - Implement settings tab — server URL, token, CLI path, insecure flag
- Implement "Fetch Document" command — prompt for URL, fetch, create/update vault note
- Implement "Publish Note" command — read frontmatter, publish via CLI, update frontmatter
- Implement "List Documents" command — list, show in modal, fetch selected
- Test with local demarkus server
- Test with remote server (soul.demarkus.io)
Future (Post-MVP)
- Sidebar panel with server browser
- Auto-sync on save (opt-in)
- Version history viewer (VERSIONS verb)
- Diff between local and remote
- Multiple server profiles
- Link resolution (
mark://links clickable in Obsidian)
Open Questions
- Should the plugin live in this monorepo or a separate repo? (Monorepo for now, extract later if needed for Obsidian plugin registry submission)
- Obsidian community plugin review requires a separate GitHub repo — will need to extract before submission