Skip to content

cyberCharl/obsidian-task-bridge

Repository files navigation

obsidian-task-bridge

An Obsidian community plugin that exposes the Obsidian Tasks plugin as a local HTTP REST API.

This lets external tools — AI agents, scripts, CLIs — query and manage your tasks programmatically via plain HTTP. No MCP, no special protocol, just REST.

Why

AI agents (and scripts) need a reliable way to read and write tasks. Grepping markdown files doesn't cut it: it misses recurrence logic, completion semantics, and requires re-parsing all the emoji syntax. Task Bridge wraps the Tasks plugin's own internals and exposes them as a clean JSON API with an OpenAPI spec.

Prerequisites

  • Obsidian 1.4.0+
  • Obsidian Tasks plugin installed and enabled
    • Task Bridge falls back to direct markdown parsing if Tasks is unavailable, but full recurrence support requires the plugin

Installation (manual)

Until this plugin is listed in the Obsidian Community Plugins directory:

  1. Download main.js and manifest.json from the latest release
  2. In your vault, create the folder: .obsidian/plugins/obsidian-task-bridge/
  3. Copy both files into that folder
  4. Open Obsidian → Settings → Community plugins → enable Task Bridge

Configuration

Open Settings → Task Bridge:

Setting Default Description
Enable server On Start/stop the HTTP server
Port 27124 Port to listen on (localhost only)
API key (none) Optional Bearer token. Leave blank to disable auth.
Allowed origins localhost Comma-separated CORS origins

The server only binds to 127.0.0.1 — it is not accessible from other machines.

API reference

Base URL: http://localhost:27124/api/v1

Full OpenAPI 3.1 spec: openapi.yaml

Authentication

If an API key is configured, include it as a Bearer token:

Authorization: Bearer your-api-key

Endpoints

GET /health

curl http://localhost:27124/api/v1/health
{
  "status": "ok",
  "port": 27124,
  "version": "0.1.0",
  "tasksPluginAvailable": true
}

GET /tasks

List tasks with optional filters.

# All open tasks
curl "http://localhost:27124/api/v1/tasks?status=open"

# High priority AISSA tasks due this week
curl "http://localhost:27124/api/v1/tasks?tag=%23aissa&priority=high&due_before=2026-04-13"

# Search by text
curl "http://localhost:27124/api/v1/tasks?text=grant+proposal"

# Paginate
curl "http://localhost:27124/api/v1/tasks?limit=20&offset=40"

Query params:

Param Type Description
status open|done|cancelled|in_progress Filter by status
tag string Filter by tag (e.g. #aissa)
priority highest|high|medium|low|lowest Filter by priority
due_before YYYY-MM-DD Tasks due on or before date
due_after YYYY-MM-DD Tasks due on or after date
file string File path substring filter
text string Description search (case-insensitive)
limit integer Max results (default 200)
offset integer Pagination offset (default 0)

Response:

{
  "tasks": [
    {
      "id": "5 - Periodic/Daily/2026-04-07.md:42",
      "description": "Fix admin date selector on events",
      "status": "open",
      "priority": "high",
      "tags": ["#aissa"],
      "dueDate": "2026-04-10",
      "scheduledDate": null,
      "startDate": null,
      "createdDate": "2026-04-07",
      "doneDate": null,
      "recurrence": null,
      "filePath": "5 - Periodic/Daily/2026-04-07.md",
      "lineNumber": 42,
      "rawLine": "- [ ] Fix admin date selector on events {task} ⏫ #aissa 📅 2026-04-10 ➕ 2026-04-07"
    }
  ],
  "total": 1
}

GET /tasks/:id

Get a single task by ID. The ID is filepath:lineNumber, URL-encoded.

ID="5 - Periodic/Daily/2026-04-07.md:42"
curl "http://localhost:27124/api/v1/tasks/$(python3 -c "import urllib.parse; print(urllib.parse.quote('$ID'))")"

POST /tasks

Create a new task. Appends to the specified file or today's daily note.

curl -X POST http://localhost:27124/api/v1/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Review AISSA grant proposal",
    "priority": "high",
    "dueDate": "2026-04-15",
    "tags": ["#aissa", "#commitment"]
  }'

Body:

Field Required Description
description Task text
filePath Vault-relative path (default: today's daily note)
dueDate YYYY-MM-DD
scheduledDate YYYY-MM-DD
startDate YYYY-MM-DD
priority highest|high|medium|low|lowest
tags Array of tags (with or without #)
recurrence e.g. "every week"

PATCH /tasks/:id

Update task fields. Only provided fields are changed.

curl -X PATCH "http://localhost:27124/api/v1/tasks/5%20-%20Periodic%2FDaily%2F2026-04-07.md%3A42" \
  -H "Content-Type: application/json" \
  -d '{"status": "done", "priority": "medium"}'

DELETE /tasks/:id

Remove a task line from the file.

curl -X DELETE "http://localhost:27124/api/v1/tasks/5%20-%20Periodic%2FDaily%2F2026-04-07.md%3A42"

Returns 204 No Content on success.


Error responses

All errors return structured JSON:

{
  "error": "Task not found",
  "code": "NOT_FOUND"
}
Code HTTP Status Meaning
NOT_FOUND 404 Task or route not found
MISSING_FIELD 400 Required field missing
UNAUTHORIZED 401 Invalid or missing API key
INTERNAL_ERROR 500 Unexpected server error

Task format

Task Bridge uses the standard Obsidian Tasks emoji syntax. The global filter for this vault is {task} — only tasks containing {task} are tracked.

Emoji Meaning
High priority
🔺 Highest priority
🔼 Medium priority
🔽 Low priority
⬇️ Lowest priority
📅 Due date
Scheduled date
🛫 Start date
Created date
Done date
🔁 Recurrence rule

Development

git clone https://github.com/cyberCharl/obsidian-task-bridge.git
cd obsidian-task-bridge
npm install
npm run build   # production build → main.js
npm run dev     # watch mode

Then symlink or copy main.js and manifest.json into your vault's .obsidian/plugins/obsidian-task-bridge/ directory.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors