---
name: taskeristl
description: >-
  Create, list, update, close, and track tasks (and their subtasks) in
  taskeristl — a centralized, shared task API/MCP server. Use whenever the user
  wants to capture a to-do, organize their work queue (active / mine / triage /
  waiting / starred), record that work happened, manage subtask checklists, or
  query who owns or is doing what. Covers the MCP tools, the HTTP API, the data
  model, canonical workflow filters, subtasks, and backdating.
---

# Using taskeristl

**taskeristl** is a centralized task tracker shared by a team of people and
agents. Tasks live in one MySQL database behind a Node service that exposes two
equivalent front doors over the same store: a **Model Context Protocol endpoint
(`/mcp`)** and a **plain HTTP API (`/v1/tasks*`)**. There is no sync layer —
both see the same data immediately.

Base URL: `https://taskeristl.cs.incodesmile.com` (production) — or the host you
downloaded this skill from. Use `https://` anywhere non-local.

## When to use this skill
- The user asks to add / capture / "remember" a task or to-do.
- The user wants their queue: "what's on my plate", "what am I waiting on",
  "what's unassigned", "what did I close recently".
- The user wants to update status, reassign, close, or star a task.
- The user wants a checklist under a task → **subtasks**.
- An agent is logging work it did on someone's behalf.

## Choosing a front door
- **Prefer the MCP tools** (`mcp__taskeristl__*`) when they're available — they
  return structured results and need no manual auth handling.
- **Use the HTTP API** for scripts, dashboards, or when MCP isn't wired up.

## Authentication
Every HTTP request needs a header `X-API-Key: <key>`. The MCP transport carries
the same key during stream initialization. Keys are issued by the team — ask an
owner if you don't have one. Never invent keys.

## Data model
Required on create: `title`, `owner`. Read-only: `id`, `created_at`,
`last_updated_at`. `closed_at` / `last_checked_at` are server-managed but
writable for backdating (see below).

| Field | Type | Notes |
|-------|------|-------|
| `id` | integer | Auto-assigned. |
| `title` | string | 1–500 chars. |
| `owner` | string | Whose row this is (e.g. `armando.arias`). |
| `assignee` | string \| null | Who is working it. Distinct from owner. |
| `status` | enum | `open` / `in_progress` / `waiting` / `deferred` / `closed`. Defaults to `open`. |
| `description` | string \| null | Free-form long text. |
| `labels` | string[] | ≤ 64 tags, ≤ 100 chars each. |
| `metadata` | object | Arbitrary JSON for extras (use for source provenance). |
| `notes` | string \| null | Free-form notes (single string — no native append). |
| `is_meeting` | boolean | True when the row is a meeting, not a unit of work. |
| `is_starred` | boolean | True when flagged important. Drives the `starred` workflow. |
| `hours` | number \| null | Estimated effort in hours. |
| `customer` | string \| null | Free-text customer this task is for. |
| `closed_at` | timestamp \| null | Auto-stamped when status becomes `closed`; cleared on transition away. |
| `last_checked_at` | timestamp \| null | Bumped by `/touch` (no `last_updated_at` change). |

### Status meanings
- `open` — ready to work; no progress yet.
- `in_progress` — some work started.
- `waiting` — blocked on a third party.
- `deferred` — created for the owner but not theirs to do; no work expected.
- `closed` — completed. `closed_at` set automatically.

## Canonical workflows
Substitute `ME` with the user's identifier (e.g. `armando.arias`). Filters AND
together; `status` accepts a comma-separated list. The server has no concept of
workdays — compute date cutoffs yourself.

| Workflow | Filter |
|----------|--------|
| `active` — open or in-progress, assigned to me | `status=open,in_progress & assignee=ME` |
| `mine` — everything on my plate | `status=open,in_progress,waiting & assignee=ME` |
| `triage` — I own these, nobody is doing them yet | `status=open & owner=ME & assignee_is_null=true` |
| `waiting` — I own these; blocked on a third party | `status=waiting & owner=ME` |
| `on_others` — I own these; someone else is doing them | `status=open,in_progress,waiting & owner=ME & assignee_not=ME` |
| `closed` — everything I've completed | `status=closed & owner=ME` |
| `recently_closed` — closed by me since `<ISO>` | `status=closed & owner=ME & closed_after=<ISO>` |
| `deferred` — created for me but not mine to do | `status=deferred & owner=ME` |
| `starred` — tasks I own that I've flagged important | `is_starred=true & owner=ME` |

## MCP tools
```
mcp__taskeristl__health_check
mcp__taskeristl__list_tasks(owner=, status=, assignee=, assignee_is_null=, label=, is_meeting=, is_starred=, customer=, *_before/*_after, limit, offset)
mcp__taskeristl__create_task(title, owner, ...)
mcp__taskeristl__get_task(id)
mcp__taskeristl__update_task(id, ...)        # PATCH semantics; pass null to clear nullable fields
mcp__taskeristl__touch_task(id)              # bump last_checked_at only
mcp__taskeristl__delete_task(id)             # permanent; prefer status=closed
```

## HTTP API
```
GET    /v1/tasks                  list (same filters as list_tasks)
POST   /v1/tasks                  create (title + owner required)
GET    /v1/tasks/{id}             show
PATCH  /v1/tasks/{id}             partial update; null clears nullable fields
POST   /v1/tasks/{id}/touch       bump last_checked_at, no body
DELETE /v1/tasks/{id}             delete
GET    /healthz                   liveness probe
GET    /openapi.yaml              machine-readable contract
```

Example:
```bash
curl -s -X POST https://taskeristl.cs.incodesmile.com/v1/tasks \
  -H "X-API-Key: $TASKERISTL_KEY" -H "Content-Type: application/json" \
  -d '{"title":"Draft Q3 plan","owner":"armando.arias"}'
```

## Subtasks
A big task 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` = 1, 2, 3…) and shown as
`#<task-id>-<seq>` (e.g. `#43-2`). Seqs are stable — deleting one leaves a gap,
never renumbers. Deleting a task deletes its subtasks (cascade).

```
mcp__taskeristl__list_subtasks(task_id)
mcp__taskeristl__get_subtask(task_id, seq)
mcp__taskeristl__create_subtask(task_id, title, status?, closed_at?)
mcp__taskeristl__update_subtask(task_id, seq, ...)   # PATCH semantics
mcp__taskeristl__delete_subtask(task_id, seq)
```
```
GET    /v1/tasks/{id}/subtasks         list (ordered by seq)
POST   /v1/tasks/{id}/subtasks         create (title required; seq auto-assigned)
GET    /v1/tasks/{id}/subtasks/{seq}   show
PATCH  /v1/tasks/{id}/subtasks/{seq}   partial update
DELETE /v1/tasks/{id}/subtasks/{seq}   delete
```

## Conventions when writing rows
- **Set `owner` to the user the row is for.** The DB is shared; `owner` is how
  individuals scope their queues. An agent acting for a user uses that user's
  identifier as `owner`.
- **Leave `assignee=null` for triage rows** awaiting a decision.
- **`status=waiting`** when blocked by a third party.
- **`is_meeting=true`** for meetings rather than work units.
- **`is_starred=true`** to flag importance (pairs with the `starred` workflow).
- **`notes` is a single string** — to append, read the row, concatenate, PATCH back.
- **`metadata` is for source provenance** — `source_ref` (Slack/Outlook/Notion
  link), `requester`, `source_excerpt`, etc.

## Backdating
To record work that happened earlier than now (closing something completed
yesterday, ingesting history), pass `closed_at` and/or `last_checked_at`:
```
PATCH /v1/tasks/42  { "status": "closed", "closed_at": "2026-05-25T14:00:00Z" }
```
Rules:
- Both must be ≤ now (no future-dating); they may be earlier than `created_at`.
- `closed_at` is only valid when the effective status is `closed`; setting it on
  an `open` task → 400. `closed_at: null` on a `closed` task → 400.
- On `POST`, pass `closed_at` with `status: "closed"` to land an already-closed row.
- `/touch` is the no-bump shortcut for "I reviewed this just now."
