Manage Joplin notes via the Joplin Server REST API (based on joppy).
NEVER assume or hallucinate results. You MUST:
Credentials can be configured in two ways:
Create ~/.joplin-server-config:
bash
JOPLIN_SERVER_URL=https://your-joplin-server.com
JOPLIN_EMAIL=your-email@example.com
JOPLIN_PASSWORD=your-password
# Optional: skip TLS verification for self-signed certificates (security risk!)
# JOPLIN_SKIP_TLS_VERIFY=true
If user prefers 1Password, retrieve credentials and create the config:
bash
# Get credentials from 1Password (adjust vault/item name as needed)
JOPLIN_URL=$(op read "op://Private/Joplin Server/url" 2>/dev/null)
JOPLIN_EMAIL=$(op read "op://Private/Joplin Server/username" 2>/dev/null)
JOPLIN_PASS=$(op read "op://Private/Joplin Server/password" 2>/dev/null)
# Write config file
cat > ~/.joplin-server-config << EOF
JOPLIN_SERVER_URL=$JOPLIN_URL
JOPLIN_EMAIL=$JOPLIN_EMAIL
JOPLIN_PASSWORD=$JOPLIN_PASS
EOF
chmod 600 ~/.joplin-server-config
Ask user for their 1Password vault name and item name if different from "Private/Joplin Server".
All commands use the bundled JavaScript client:
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js <command> [args...]
CommandDescriptionpingHealth check (no auth required)loginAuthenticate and verify connectionlist-notebooksList all notebookslist-notesList all notesget-note <id>Get note contentadd-notebook <title>Create a new notebookadd-note <title> [parent_id] [body]Create a new notemodify-note <id> <field> <value>Modify a note fielddelete-note <id>Delete a notesearch <query>Search notes by title/content
All commands return JSON. Errors include an error field:
json
{"id": "abc123", "title": "My Note"} // Success
{"ok": false, "error": "..."} // Failure
When user first invokes this skill:
bash
# Step 1: Check if config exists
cat ~/.joplin-server-config 2>/dev/null || echo "CONFIG_MISSING"
# Step 2: If config exists, test connection
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js ping
If config is missing, ask user which setup method they prefer:
1Password - Ask for vault/item name, then run: bash
JOPLIN_URL=$(op read "op://VAULT/ITEM/url")
JOPLIN_EMAIL=$(op read "op://VAULT/ITEM/username")
JOPLIN_PASS=$(op read "op://VAULT/ITEM/password")
cat > ~/.joplin-server-config << EOF
JOPLIN_SERVER_URL=$JOPLIN_URL
JOPLIN_EMAIL=$JOPLIN_EMAIL
JOPLIN_PASSWORD=$JOPLIN_PASS
EOF
chmod 600 ~/.joplin-server-config
Manual - User creates ~/.joplin-server-config with:
text
JOPLIN_SERVER_URL=https://your-server.com
JOPLIN_EMAIL=your-email
JOPLIN_PASSWORD=your-password
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js list-notebooks
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js list-notes
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js get-note <note_id>
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js add-notebook "My Notebook"
bash
# Basic note
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js add-note "My Note Title"
# Note in a specific notebook
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js add-note "My Note Title" <notebook_id>
# Note with body content
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js add-note "My Note Title" <notebook_id> "Note body here"
bash
# Update title
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js modify-note <note_id> title "New Title"
# Update body
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js modify-note <note_id> body "New body content"
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js search "search term"
bash
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js delete-note <note_id>
The API client automatically handles Joplin's sync lock protocol:
TypeValueDescriptionNote1Markdown notesFolder2NotebooksResource4AttachmentsTag5TagsNoteTag6Note-tag links
Notes are returned as objects with these fields:
json
{
"id": "abc123def456",
"parent_id": "parent-folder-uuid",
"title": "My Note Title",
"body": "Note content in markdown...",
"created_time": "2024-01-15T10:30:00.000Z",
"updated_time": "2024-01-15T10:30:00.000Z",
"type_": "1",
"markup_language": "1"
}
All TODOs go into the "TODOs" notebook.
Daily planning notes follow this naming format:
text
TODO#dd.mm.yy <Wd>
Where <Wd> is a 2-letter weekday: Mo, Tu, We, Th, Fr, Sa, Su
Examples:
TODO#16.03.26 Su (Sunday, March 16, 2026)TODO#17.03.26 Mo (Monday, March 17, 2026)Content format: One checkbox per line for individual tasks:
markdown
- [ ] Morning standup
- [ ] Review PR #123
- [ ] Deploy to staging
- [x] Send weekly report
Non-daily TODOs (projects, ideas, recurring tasks) also go in the "TODOs" notebook but:
TODO#dd.mm.yy naming formatWhen editing kanban-formatted notes:
# - Keep exact names: # Backlog, # In progress, # Done##kanban-settings code block at the endErrorMeaningCONFIG_MISSINGNo ~/.joplin-server-config fileAuthentication failedWrong credentials or server unreachableRequest timeoutServer not responding (check URL)Sync target has exclusive lockAnother client is syncing404Item not found
If auth fails:
bash
# Test server reachability
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js ping
# Test login
node ${CLAUDE_SKILL_DIR}/scripts/joplin-server-api.js login
# Check config file
cat ~/.joplin-server-config