Skip to main content
Glama

ziptask

MCP task tracker for AI agents. A pure state layer — statuses, dependencies, leases, versioning — over SQLite, served to agents over MCP.

Install

One-liner — downloads a compiled binary, writes default config, prints client setup:

curl -LsS https://raw.githubusercontent.com/zumik3-del/ziptask/main/scripts/install.sh | sh

Default install dir: ~/.ziptask/. Override with ZIPTASK_HOME=/some/path. Pin a version with ZIPTASK_VERSION=0.1.0. On systemd systems the installer provisions a background service on port 3005 (override with --port); skip it with --no-service.

Service mode

When systemd is detected and running, install.sh creates /etc/systemd/system/ziptask.service (Type=simple, Restart=on-failure, port 3005). Manage it with:

sudo systemctl start ziptask
sudo systemctl stop ziptask
sudo systemctl enable ziptask     # auto-start on boot
journalctl -u ziptask -f         # live logs

Remove with bash ~/.ziptask/scripts/uninstall.sh (use --keep-data to preserve the DB and settings).

MCP client config (stdio)

// Claude / Cursor / opencode — ~/.config/claude/settings.json or equivalent
{
  "mcpServers": {
    "ziptask": {
      "command": "~/.ziptask/bin/ziptask",
      "args": ["--stdio"]
    }
  }
}

Upgrade path is via bash ~/.ziptask/scripts/update.sh — it fetches the latest release, downloads the matching binary, and restarts the systemd service when active. To pin a version, pass --version <tag> (the script accepts tags with or without a v prefix):

bash ~/.ziptask/scripts/update.sh
bash ~/.ziptask/scripts/update.sh --version v0.2.0

The script prompts y/N before overwriting. Before swapping the binary it creates an online SQLite backup of ZIPTASK_DB (resolved from env → settings.json dbPath → ~/.ziptask/data/ziptask.db) into ~/.ziptask/backups/ziptask-<timestamp>.db via sqlite3 .backup; missing sqlite3 or a missing DB are handled as warnings and the update continues. The backup path is printed so a failed upgrade is reversible. On non-systemd systems the binary is replaced but you must restart manually.

Schema guard on startup: a fresh DB auto-initialises; an older DB (V < L) auto-migrates forward; a DB newer than the binary (V > L, i.e. you downgraded) refuses to start with SCHEMA: database schema version <V> is newer than this binary supports (<L>); upgrade ziptask or restore the database from backup, exit 1. Fix by re-upgrading to the newer binary or restoring the backup that update.sh wrote. --version does not touch the DB.

Related MCP server: Personal Task Manager MCP

Quick start (from source)

Requires Bun ≥ 1.4.

bun install
bun run start          # HTTP server on an ephemeral port (MCP endpoint + /health)
bun run start:stdio    # run over stdio

Build a binary

bun run build:bin        # produces dist/ziptask
dist/ziptask --version   # prints ziptask 0.1.0
dist/ziptask --stdio     # runs as stdio MCP server

Configuration

Variable

Default

Description

ZIPTASK_DB

./data/ziptask.db

SQLite path (directory auto-created)

ZIPTASK_HOST

127.0.0.1

HTTP listen host

ZIPTASK_PORT

0 (random)

HTTP listen port

ZIPTASK_LEASE_TTL_MIN

15

Claim lease length in minutes

MCP tools

Tool

What it does

create_task

Enqueue a task; always queuedblocked is a manual flag only. Fields: epic? (declare as epic, not claimable), epic_id? (attach as sub-task to an existing epic)

get_task

Read a task; description only via explicit fields. Epics: subtasks roll-up ({total,open,done,failed}) via fields:["subtasks"]; epic_id via fields when reading a sub-task

list_tasks

Filter by assignee/status/updated_since/epic_id (children of an epic). JSON result

claim_task

Claim a queued task (auto-pick or by id); returns {id, lease_ttl_min, version}. Epics are excluded from auto-pick and explicit claim returns INVALID: #N is an epic, not claimable

update_status

Transition status with optimistic version lock. Epic close-guard: done/failed rejected while non-terminal children exist → CHILDREN: N sub-tasks not terminal

batch_statuses

Pipe lines id|code (+ |assignee via include)

list_queue

Pipe lines of dep-satisfied queued tasks (epics excluded)

add_comment

Append a comment to a task

get_timeline

Merged audit log + comments feed. Epics show subtask_add/subtask_done/subtask_failed mirror rows — history reads as create → subtask_add… → subtask_done… → resolution

get_template

Fetch a markdown template (task description, comments)

metrics

Aggregated stats: done_count, status_time, bottleneck. Epics excluded from all metrics

Statuses

Codes (STATUS_CODES): 0 not_found, 1 queued, 2 in_progress, 3 review, 4 done, 5 failed, 6 blocked.

Flow: queued → in_progress → review → done (or failed / blocked). done and failed are terminal; lease expiry returns to queued and increments attempts. Tasks with unsatisfied depends_on stay queued but are hidden from list_queue and auto-claim.

Epic → sub-task workflow

Epics are structural containers, not work. They cannot be claimed and their status is manual.

Declaring an epic

create_task {title: 'Release v2', reporter: 'orchestrator', epic: true}

or attach the first sub-task to promote it automatically:

create_task {title: 'Sub-work', reporter: 'orchestrator', epic_id: <epic-id>}

The target is auto-promoted to is_epic=1 (audit row promote_epic).

Attaching sub-tasks

Sub-tasks are ordinary tasks with epic_id pointing at the epic. Use depends_on for ordering:

create_task {title: 'Implement auth', reporter: 'orchestrator', epic_id: <epic-id>}
create_task {title: 'Write docs', reporter: 'orchestrator', epic_id: <epic-id>, depends_on: [<auth-id>]}

Nested membership is rejected (epic cannot be a sub-task; sub-task cannot be an epic).

Roll-up and closure

  • get_task fields:["subtasks"] on the epic returns {total, open, done, failed} (open = queued+in_progress+review+blocked).

  • list_tasks epic_id:<epic-id> returns only children.

  • The epic timeline (get_timeline) mirrors terminal sub-task events: subtask_add, subtask_done, subtask_failed.

  • update_status(epic→done) is guarded: rejected with CHILDREN: N sub-tasks not terminal while any child is non-terminal.

Constraints

Rule

Error

epic: true + epic_id

INVALID: epic cannot have a parent epic

epic: true + depends_on

INVALID: epic cannot have depends_on

depends_on pointing at an epic

INVALID: dependencies on epic tasks not allowed (#N)

epic_id pointing at a terminal task

INVALID: cannot attach to a terminal task

epic_id pointing at a sub-task (nesting)

INVALID: cannot attach to a sub-task (no nesting)

Explicit claim_task on an epic

INVALID: #N is an epic, not claimable

Notes

  • epic_id is immutable after creation (no re-parent/detach). Manual SQL is the escape hatch.

  • blocked/failed on an epic are manual flags only; no cascade to children.

  • Metrics (metrics tool) exclude epics — an epic sitting in one status for days would distort bottleneck.

Architecture

Layered by carrier, no framework beyond the MCP SDK:

Layer

Location

Responsibility

MCP

src/mcp/

Tool schemas, registration, response shaping

Service

src/core/

Domain rules: transitions, leases, deps, versioning

Storage

src/db/

SQL (bun:sqlite, WAL) + migrations

Entry

src/index.ts, src/server.ts

Composition root, HTTP transport

Development

bun test               # unit tests (per-test temp DBs)
bunx tsc --noEmit      # type check
bunx biome check src/  # lint
bun run src/smoke.ts   # MCP end-to-end over HTTP (ephemeral port + temp DB)

Docker

docker build -t ziptask .
docker run -d --name ziptask \
  -p 3000:3000 \
  -e ZIPTASK_HOST=0.0.0.0 \
  -e ZIPTASK_PORT=3000 \
  -v /host/data:/var/lib/ziptask \
  -v /host/backups:/backups \
  ziptask

The container takes an online SQLite backup on a cron schedule; old archives are pruned.

Variable

Default

Description

ZIPTASK_BACKUP_DIR

/backups

Backup destination (mount a volume)

ZIPTASK_BACKUP_PREFIX

ziptask

Backup file prefix

ZIPTASK_BACKUP_RETAIN

7

Backups to keep (oldest pruned)

CRON_SCHEDULE

0 2 * * *

Cron expression for the backup job

License

MIT

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A local Model Context Protocol server providing backend tools for AI agents to manage projects and tasks with persistent storage in SQLite, enabling structured tracking of project tasks with dependencies, priorities, and statuses.
    12
    9
    25
    GPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to manage task state through MCP, including creating, updating, and tracking tasks, with support for client-side encryption and secure local credential storage.
    15
    MIT