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.
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.
- 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
Until this plugin is listed in the Obsidian Community Plugins directory:
- Download
main.jsandmanifest.jsonfrom the latest release - In your vault, create the folder:
.obsidian/plugins/obsidian-task-bridge/ - Copy both files into that folder
- Open Obsidian → Settings → Community plugins → enable Task Bridge
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.
Base URL: http://localhost:27124/api/v1
Full OpenAPI 3.1 spec: openapi.yaml
If an API key is configured, include it as a Bearer token:
Authorization: Bearer your-api-key
curl http://localhost:27124/api/v1/health{
"status": "ok",
"port": 27124,
"version": "0.1.0",
"tasksPluginAvailable": true
}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 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'))")"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" |
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"}'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.
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 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 |
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 modeThen symlink or copy main.js and manifest.json into your vault's .obsidian/plugins/obsidian-task-bridge/ directory.
MIT