You have reached the home page of the Taskeristl service. It tracks tasks across people and tools in one shared MySQL database, behind a small HTTP API and a Model Context Protocol (MCP) endpoint for LLM clients. Two front doors, one task list.
Where would you like to go?
Quick links: openapi.yaml · openapi.json · SKILL.md · healthz
Every task carries the following fields:
| Field | Type | Notes |
|---|---|---|
| id | integer | Auto-assigned. Read-only. |
| title | string | Required. 1–500 characters. |
| owner | string | Required. Who the task belongs to, e.g. juan.perez. |
| assignee | string or null | Optional. Who is currently working on it. Distinct from owner. |
| status | enum | One of open, in_progress, waiting, deferred, closed. Defaults to open. See Status meanings. |
| description | string or null | Free-form long text. |
| labels | array of strings | Up to 64 tags, ≤ 100 chars each. |
| metadata | object | Arbitrary JSON for extras. |
| notes | string or null | Free-form notes. |
| is_meeting | boolean | Defaults to false. Set true when a row represents a meeting rather than a unit of work. |
| is_starred | boolean | Defaults to false. Set true to flag a task as important. Drives the starred workflow. |
| hours | number or null | Estimated units of effort in hours. null when unknown. |
| customer | string or null | Free-text customer this task is for. null when internal or unspecified. |
| created_at | ISO-8601 datetime | Read-only. |
| last_updated_at | ISO-8601 datetime | Read-only. Auto-updates on every content change. Not bumped by /touch. |
| closed_at | ISO-8601 datetime or null | Auto-stamped when status becomes closed; cleared on transition away. Writable on create/PATCH for backdating (must be ≤ now; only with status=closed). May be earlier than created_at for retroactive ingestion. |
| last_checked_at | ISO-8601 datetime or null | Bumped to now by POST /v1/tasks/{id}/touch for polling agents to mark "I reviewed this." Writable on create/PATCH for backdating (must be ≤ now). Unlike /touch, a PATCH also bumps last_updated_at. |
| Status | Meaning |
|---|---|
| open | Ready to be worked on; no progress yet. |
| in_progress | Some work has been started. |
| waiting | Blocked on action from a third party. |
| closed | Successfully completed. Sets closed_at automatically. |
| deferred | Created for the owner but does not belong to them; no work needs to be done or tracked on it. |
Canonical filter combinations callers compose from primitives. Replace ME with the user's identifier (e.g. juan.perez).
| Workflow | What it answers | Filters |
|---|---|---|
| active | Open or in-progress tasks assigned to me. | status=open,in_progress&assignee=ME |
| mine | Everything on my plate (open + in_progress + waiting), assigned to me. | status=open,in_progress,waiting&assignee=ME |
| triage | Open tasks I own that nobody is doing yet. | status=open&owner=ME&assignee_is_null=true |
| waiting | Tasks I own that are blocked on a third party. | status=waiting&owner=ME |
| on_others | Open, in-progress, or waiting tasks I own that someone else is doing. | status=open,in_progress,waiting&owner=ME&assignee_not=ME |
| closed | Everything I've completed. | status=closed&owner=ME |
| recently_closed | Closed tasks I own from the last 3 workdays (caller computes cutoff). | status=closed&owner=ME&closed_after=<ISO> |
| deferred | Tasks created for me but not mine to do. | status=deferred&owner=ME |
| starred | Tasks I own that I've flagged as important. | is_starred=true&owner=ME |
The server has no concept of workdays or holidays. For recently_closed, the caller computes the ISO cutoff and passes it as closed_after.
Authentication is one header on every request:
X-API-Key: your-key-here
Endpoints:
| Method | Path | What it does |
|---|---|---|
| GET | /v1/tasks | List tasks. Filters: status, owner, assignee, customer, label, is_meeting, is_starred, closed_after/closed_before, updated_after/updated_before, checked_after/checked_before, plus limit and offset. |
| POST | /v1/tasks | Create a task. Body must include title and owner. |
| GET | /v1/tasks/{id} | Fetch one task by id. |
| PATCH | /v1/tasks/{id} | Partial update. Pass null to clear nullable fields. |
| POST | /v1/tasks/{id}/touch | Bump last_checked_at without changing content (no body). |
| DELETE | /v1/tasks/{id} | Permanently delete a task. |
| GET | /v1/tasks/{id}/subtasks | List a task's subtasks (ordered by seq). |
| POST | /v1/tasks/{id}/subtasks | Create a subtask. Body must include title; seq is assigned automatically. |
| GET | /v1/tasks/{id}/subtasks/{seq} | Fetch one subtask. |
| PATCH | /v1/tasks/{id}/subtasks/{seq} | Partial update of a subtask. |
| DELETE | /v1/tasks/{id}/subtasks/{seq} | Permanently delete a subtask. |
Large tasks can hold a checklist of subtasks: lightweight children with just a title, a simple lifecycle (open / in_progress / done), and tracking timestamps (created_at, last_updated_at, closed_at). closed_at is stamped when a subtask becomes done and cleared if reopened.
Subtasks are numbered per parent — seq starts at 1 for each task and each subtask gets a display name like #43-2 (#<task-id>-<seq>). Seqs are stable: deleting one leaves a gap and never renumbers the rest. Deleting a task deletes its subtasks.
Create a task:
curl -X POST http://localhost:3000/v1/tasks \
-H "X-API-Key: your-key-here" \
-H "Content-Type: application/json" \
-d '{
"title": "Wire up the MCP client",
"owner": "juan.perez",
"labels": ["mcp","setup"]
}'
List tasks you own:
curl -H "X-API-Key: your-key-here" \ "http://localhost:3000/v1/tasks?owner=juan.perez"
Filter by label:
curl -H "X-API-Key: your-key-here" \ "http://localhost:3000/v1/tasks?label=mcp"
Move a task forward:
curl -X PATCH http://localhost:3000/v1/tasks/42 \
-H "X-API-Key: your-key-here" \
-H "Content-Type: application/json" \
-d '{"status":"in_progress","notes":"started today"}'
Transfer ownership:
curl -X PATCH http://localhost:3000/v1/tasks/42 \
-H "X-API-Key: your-key-here" \
-H "Content-Type: application/json" \
-d '{"owner":"new.owner"}'
Delete:
curl -X DELETE http://localhost:3000/v1/tasks/42 \ -H "X-API-Key: your-key-here"
The full machine-readable contract lives at /openapi.yaml (and /openapi.json). Feed it to your favorite client generator and you are off.
Have an LLM driving the work? Point any MCP-aware client (Claude Code, Claude Desktop, custom agents) at POST /mcp. The transport is Streamable HTTP (JSON-RPC over HTTP); authentication is the same X-API-Key header used by the plain API.
The MCP server exposes seven tools:
| Tool | Purpose |
|---|---|
| health_check | Confirm the service is reachable. |
| list_tasks | List tasks. Filters: status, owner, assignee, customer, label, is_meeting, is_starred, closed_after/closed_before, updated_after/updated_before, checked_after/checked_before, plus limit and offset. |
| get_task | Fetch a single task by id. |
| create_task | Create a new task. title and owner are required. |
| update_task | Partial update. Pass null to clear nullable fields. |
| touch_task | Bump last_checked_at for a task without changing content. |
| delete_task | Permanently delete a task by id. |
Add this to ~/.claude/settings.json (global) or your project's .mcp.json:
{
"mcpServers": {
"taskeristl": {
"type": "http",
"url": "http://localhost:3000/mcp",
"headers": {
"X-API-Key": "your-key-here"
}
}
}
}
Or via the Claude Code CLI:
claude mcp add task-database \ --transport http \ --url http://localhost:3000/mcp \ --header "X-API-Key: your-key-here"
Same JSON, dropped into the mcpServers section of:
Restart the client and the six tools above will appear in the tool catalog. Speak to them by name (or just describe what you want — the model will pick the right tool).
Tip: when the server is deployed remotely, swap http://localhost:3000 for the real address and use https:// in any non-local environment.
Want Claude to know how to drive taskeristl — the data model, the workflow filters, subtasks, backdating — without you explaining it each time? Download the Skill and drop it into your Claude skills directory. Claude loads it automatically when a task-management request comes up.
Install it as a personal skill (available across all your projects):
mkdir -p ~/.claude/skills/taskeristl curl -s https://gkeakzm5hy.us-east-1.awsapprunner.com/SKILL.md \ -o ~/.claude/skills/taskeristl/SKILL.md
Or commit it to a project at .claude/skills/taskeristl/SKILL.md to share it with your repo. Either way, pair it with the MCP endpoint (preferred) or the HTTP API and an X-API-Key.
All errors return JSON with this shape:
{
"error": {
"code": "validation_error",
"message": "Request body failed validation",
"details": [ ... ]
}
}
The HTTP status code is the source of truth.
| Status | Meaning |
|---|---|
| 400 | Validation error or malformed input. |
| 401 | Missing or invalid X-API-Key. |
| 404 | Task id (or path) does not exist. |
| 405 | Wrong method on /mcp (must be POST). |
| 500 | Something exploded server-side. |