Manage your Obsidian vault from the terminal. AI-enhanced, AI-optional.
obsidian-curator connects directly to the CouchDB database that powers Obsidian LiveSync, letting you capture notes, process them with AI, file them into the right folders, manage tasks, and keep your vault tidy — all from the command line or your own Node.js scripts.
No AI? No problem. Capture, audit, tidy, and task features all work rule-based without any API key.
| Feature | Command | AI required? |
|---|---|---|
| Quick capture to inbox | capture |
No |
| Enrich inbox notes with tags/summary | process |
Yes |
| Route notes to canonical folders | file |
Yes |
| Check vault structure | audit |
No |
| Clean up duplicates, dead notes | tidy |
Optional (triage) |
| List and create tasks | tasks, task |
No |
| Mark tasks complete | done |
No |
- Node.js 18+
- CouchDB (local or remote) configured for Obsidian LiveSync
- The Obsidian LiveSync plugin installed and connected to that CouchDB instance
E2EE (end-to-end encryption) must be disabled — obsidian-curator reads document content directly from CouchDB.
npm install -g obsidian-curatorobsidian-curator initThe wizard walks you through:
- CouchDB connection (host, port, database, credentials) — tests the connection live
- Vault structure preset (PARA / Zettelkasten / Johnny Decimal / Flat / Custom)
- AI provider (OpenAI / Anthropic / Ollama / None)
- Task projects (optional)
Config is saved to ~/.obsidian-curator/config.json.
obsidian-curator capture "Check out the new Obsidian graph view features"
# ✓ Captured to inbox/check-out-the-new-20260219-143022.mdobsidian-curator process
# Processing 3 inbox notes...
# ✓ check-out-the-new.md — tagged: [obsidian, productivity], folder: Resources
# ✓ meeting-notes.md — tagged: [work, meetings], folder: Projects
# Done. 3 processed, 0 skipped.obsidian-curator file
# Filing 3 processed notes...
# ✓ check-out-the-new.md → Resources/Obsidian/check-out-the-new.md (confidence: 0.91)
# Done. 3 filed.Interactive setup wizard.
obsidian-curator initCapture text to your inbox with a timestamp.
obsidian-curator capture "Note text here"
obsidian-curator capture "Ideas for the project" --source meetingOptions:
--source <label>— tag the source (default:cli)
Enrich inbox notes with AI-generated frontmatter (tags, summary, suggested folder).
obsidian-curator process
obsidian-curator process --limit 5
obsidian-curator process --dry-run
obsidian-curator process --force # re-process already-processed notesOptions:
--limit <n>— max notes to process (default: 10)--dry-run— show what would happen without writing--force— re-process notes that already have AI suggestions
Requires AI provider (not none).
Route processed inbox notes to their canonical folders.
obsidian-curator file
obsidian-curator file --limit 5
obsidian-curator file --dry-run
obsidian-curator file --min-confidence 0.8Options:
--limit <n>— max notes to file (default: 10)--dry-run— preview without moving--min-confidence <0-1>— minimum AI confidence to auto-file (default: 0.7)
Requires AI provider (not none).
Check vault structure against your configured canonical folders.
obsidian-curator auditExample output:
Vault Structure Audit
─────────────────────
✓ 142 notes in canonical locations
⚠ 3 notes at vault root (not in rootExceptions)
⚠ 1 non-canonical top-level folder: "Dump"
ℹ Detected methodology: PARA
Vault housekeeping — find duplicates, structure violations, dead notes.
obsidian-curator tidy
obsidian-curator tidy --dry-run
obsidian-curator tidy --checks dupes,stubsOptions:
--dry-run— report issues without fixing anything--checks <list>— comma-separated:dupes,structure,stubs, orall(default:all)
Works without AI — ambiguous cases are flagged for manual review. With AI, ambiguous cases are triaged automatically.
List open tasks.
obsidian-curator tasks
obsidian-curator tasks --project Work
obsidian-curator tasks --priority high
obsidian-curator tasks --status doneOptions:
--project <name>— filter by project--priority high|normal|low— filter by priority--status open|done— filter by status (default: open)
Create a task from natural language.
obsidian-curator task "call dentist next Tuesday"
obsidian-curator task "urgent: submit invoice before March 1st"
obsidian-curator task "write project proposal for Work in 2 weeks"The parser understands:
- Relative dates: "tomorrow", "next Tuesday", "in 2 weeks", "before March 1st"
- Priority: "urgent", "asap", "important" → high; "no rush", "whenever" → low
- Projects: matched from your configured keyword lists
Mark a task complete.
obsidian-curator done "dentist" # partial title match
obsidian-curator done "Tasks/call-dentist-next-tuesday.md" # exact pathView or update configuration.
obsidian-curator config show
obsidian-curator config set ai.provider openai
obsidian-curator config set ai.apiKey sk-...
obsidian-curator config set vault.host 192.168.1.100const { VaultClient, Curator, createAIAdapter, loadConfig } = require('obsidian-curator');
// Load config (searches ~/.obsidian-curator/config.json and .obsidian-curator.json)
const config = loadConfig();
// Or use a specific file:
// const config = loadConfig('/path/to/config.json');
// Connect to vault
const vault = new VaultClient(config.vault);
await vault.ping(); // throws if unreachable
// Set up AI (uses config.ai.provider)
const ai = createAIAdapter(config);
// Create curator
const curator = new Curator({ vault, ai, config });
// Capture a note
const path = await curator.capture('Quick thought about project X');
console.log('Saved to', path);
// Process inbox
const result = await curator.process({ limit: 5 });
console.log(result); // { processed: 5, skipped: 0, errors: [] }
// File notes
await curator.file({ dryRun: true });
// Create a task
const task = await curator.createTask('call Alice next Friday');
console.log(task.title, task.due, task.project);
// List tasks
const tasks = await curator.tasks({ status: 'open', project: 'Work' });
// Task brief (markdown summary)
const brief = await curator.taskBrief();
console.log(brief);
// Audit vault structure
const report = await curator.audit();
// Tidy vault
await curator.tidy({ checks: ['dupes', 'stubs'], dryRun: true });| Provider | Cost | Privacy | Best for |
|---|---|---|---|
none |
Free | Local | Rule-based features only |
ollama |
Free | Local | Full features, private |
openai |
Pay-per-use | Cloud | Best quality (GPT-4o-mini default) |
anthropic |
Pay-per-use | Cloud | High quality (Haiku default) |
custom |
Varies | Varies | OpenRouter, LM Studio, etc. |
See docs/AI-PROVIDERS.md for full setup instructions and cost estimates.
No AI (rule-based only):
{ "ai": { "provider": "none" } }Ollama (local, free):
{ "ai": { "provider": "ollama", "model": "llama3.2" } }OpenAI:
{ "ai": { "provider": "openai", "apiKey": "sk-...", "model": "gpt-4o-mini" } }Anthropic:
{ "ai": { "provider": "anthropic", "apiKey": "sk-ant-...", "model": "claude-haiku-4-5" } }OpenRouter (OpenAI-compatible):
{
"ai": {
"provider": "openai",
"apiKey": "sk-or-...",
"baseUrl": "https://openrouter.ai/api/v1",
"model": "anthropic/claude-haiku-4-5"
}
}Choose a preset with obsidian-curator init or set structure.preset in config.
inbox/ ← new captures land here
Projects/ ← active projects
Areas/ ← ongoing responsibilities
Resources/ ← reference material
Archives/ ← completed/inactive
inbox/ ← fleeting notes
Slipbox/ ← permanent atomic notes
References/ ← literature notes
Projects/ ← project-specific work
Archives/ ← inactive
inbox/ ← new captures
00-09/ ← Meta (user-defined)
10-19/ ← (user-defined)
...
inbox/ ← everything starts here
(everything else at root — no enforced structure)
Config is stored at ~/.obsidian-curator/config.json (global) or .obsidian-curator.json (project-local). Local overrides global.
{
"vault": {
"host": "localhost", // CouchDB hostname or IP
"port": 5984, // CouchDB port
"database": "obsidian", // CouchDB database name
"username": "", // CouchDB username (leave blank if no auth)
"password": "", // CouchDB password
"protocol": "http" // "http" or "https"
},
"structure": {
"preset": "para", // "para" | "zettelkasten" | "johnny-decimal" | "flat" | "custom"
"folders": {
"inbox": "inbox", // Override preset folder names
"projects": "Projects"
},
"customFolders": [], // Additional canonical top-level folders
"rootExceptions": [ // Files allowed at vault root
"Index.md", "Welcome.md", "README.md"
],
"systemPaths": [ // Paths to never touch
"logs/", "ix:"
]
},
"ai": {
"provider": "none", // "none" | "openai" | "anthropic" | "ollama" | "custom"
"model": null, // Model name (provider default if null)
"apiKey": null, // API key
"baseUrl": null // Custom base URL (OpenAI-compatible)
},
"tasks": {
"folder": "Tasks", // Vault folder for task notes
"projects": { // Keyword → project mapping
"Work": ["work", "office", "meeting", "invoice", "client"],
"Home": ["house", "garden", "clean", "fix", "repair"]
},
"defaultPriority": "normal"
},
"tidy": {
"autoDeleteConfidence": 0.8, // Confidence threshold for auto-delete (0-1)
"testPatterns": [ // Filename patterns to auto-delete
"test-*", "Test*", "Untitled*"
],
"protectedPaths": [], // Paths that tidy will never touch
"maxAutoActions": 50 // Safety cap on automatic changes per run
}
}See docs/SETUP.md for detailed CouchDB setup, LiveSync configuration, and troubleshooting.
See docs/API.md for the full programmatic API.
PRs and issues welcome at github.com/philmossman/obsidian-curator.
This project follows a "practical first" philosophy: no TypeScript, no bundler, plain CJS Node.js. Keep dependencies minimal.
git clone https://github.com/philmossman/obsidian-curator.git
cd obsidian-curator
npm install
npm testMIT © Phil Mossman