Persistent, ordered, shared task lists for Pi agents and MCP clients.
pi-tasks ships:
- a Pi package/extension exposing task tools directly inside Pi;
- a Pi skill explaining when and how to use the task tools;
- a local stdio MCP server exposing the same tool surface to MCP hosts.
The product specification is kept in pi-tasks.md.
- Node.js 24.15.0 exactly.
.node-versionis the runtime source of truth used by GitHub Actions;package.json,package-lock.json,.nvmrc, and.npmrckeep local installs strict and synchronized because the implementation uses the built-innode:sqlitemodule. - Pi for the extension use case.
- An MCP-compatible host for the stdio server use case.
From npm, using the latest published release:
pi install npm:@micka33/pi-tasks@latestFor project-local installation:
pi install -l npm:@micka33/pi-tasks@latestReleases are also mirrored to GitHub Packages so they appear on the repository Packages page. To install from GitHub Packages instead of npmjs.org, configure npm's @micka33 registry to https://npm.pkg.github.com first; GitHub may require a token depending on package visibility and client settings.
From this repository instead of npm:
pi install git:git@github.com:Micka33/pi-tasks.git@latestDuring development:
pi -e ./src/pi/index.tsDefault database path:
.pi/pi-tasks/tasks.sqlite
Override it to share one queue between workspaces, Pi sessions, and MCP clients:
export PI_TASKS_DB_PATH=/absolute/path/to/tasks.sqliteSame SQLite database + same list_id = same shared task list.
The Pi extension derives agent_id from the Pi session file:
pi-session:<sha256(session-file)[0..16]>
You can override it with:
export PI_TASKS_AGENT_ID=my-agentMCP has no Pi session, so set a stable identity explicitly:
export PI_TASKS_AGENT_ID=mcp-worker-1If omitted, the MCP server uses a process-scoped fallback; set PI_TASKS_AGENT_ID for stable claims across restarts.
Build first:
npm install
npm run buildRun:
PI_TASKS_AGENT_ID=mcp-worker-1 \
PI_TASKS_DB_PATH=/absolute/path/to/tasks.sqlite \
node dist/src/mcp/cli.jsExample MCP config shape:
{
"mcpServers": {
"pi-tasks": {
"command": "node",
"args": ["/absolute/path/to/pi-tasks/dist/src/mcp/cli.js"],
"env": {
"PI_TASKS_AGENT_ID": "mcp-worker-1",
"PI_TASKS_DB_PATH": "/absolute/path/to/tasks.sqlite"
}
}
}
}The Pi extension shows a compact framed pi-tasks widget above the editor when visible task lists exist, including lists that currently contain no tasks.
It summarizes visible lists, status counts, and tasks assigned to or claimed by the current Pi session. The widget puts the current agent's work first, uses readable counters such as todo 2 · run 1 · blocked 0 · done 0, and labels blocked tasks as paused. It never bypasses private-list protection automatically.
Control it with:
/task-widget on
/task-widget off
/task-widget compact
/task-widget full
/task-widget refresh
Useful commands:
/task-lists # compact: only name + id
/task-lists full # complete JSON metadata
/tasks <list_id> # readable task details, including ids, agents, times, descriptions, notes, outcome
/tasks <list_id> full # complete JSON for the list and tasks
/task-audit [list_id] # readable private-list bypass audit events visible to this agent
/task-audit [list_id] full # complete JSON audit events
/task-list-delete <list_id> # soft-delete a list and all active tasks in it
/task-language en|fr # change Pi UI language for this session
/tasks <list_id>, /task-audit <list_id>, and /task-list-delete <list_id> support Pi TUI autocomplete for visible task-list ids. Type /tasks then trigger completion, or start typing a list id/name to filter suggestions. /task-widget autocompletes its actions: on, off, compact, full, refresh. /task-language autocompletes supported UI languages: en, fr, de, es, it, pl, ru, jp, cn.
The widget refreshes on session start, after task_* tool calls, and periodically every 10 seconds to catch updates made by other agents or MCP clients.
Pi currently renders at most 10 widget lines. pi-tasks stays under that limit itself to avoid Pi's generic widget truncated message: compact mode uses up to 8 lines, full mode uses up to 10 lines, and hidden content is summarized with explicit … masquée(s) lines plus /tasks <list_id> hints.
Human-facing Pi UI text is localized. Supported locales are en, fr, de, es, it, pl, ru, jp, and cn.
Change it for the current Pi session with autocomplete:
/task-language fr
/task-language en
/task-language de
/task-language es
/task-language it
/task-language pl
/task-language ru
/task-language jp
/task-language cn
You can also choose a startup default with:
export PI_TASKS_LANG=fr
# or
export PI_TASKS_LANG=enIf PI_TASKS_LANG is unset, pi-tasks tries LC_ALL, LC_MESSAGES, then LANG, and falls back to en. The /task-language command overrides that fallback for the current process/session. Use /task-widget refresh after changing language to redraw the widget; command/tool labels already registered by Pi may require /reload. Tool names, action names, JSON fields, status values, IDs, and structured tool results stay stable and are not translated.
pi-tasks exposes a compact tool surface. Each tool takes an action plus an optional action-specific params object:
task_lists—create,find,get,deletetask lists.task_items—create,add_many,update,reorder,deletetasks.task_claims—claim_next,refresh,release_expiredclaims.task_audit—getprivate-list bypass audit events visible to the current agent.task_help— required reference tool for workflow rules, action schemas, and examples (action:all,workflow,schemas, orexamples).
Structured results are wrapped to make compact actions obvious in the model-visible tool content, Pi details, and MCP output. Every compact tool+action combination has a dedicated short Pi UI renderer, without removing full ids or fields from the data available to agents/MCP:
✓ 2 listes trouvées
NAME VISIBILITY ID
• Task flow demo shared task-flow-demo-20260510
Task flow demo · shared · 3 tâches
todo 2 · run 1
# STATUS ID TITLE
• 1 run d813c1f6 Préparer le contexte
• 2 todo 8d55eb15 Exécuter le traitement
• 3 todo c5fbf6bf Contrôler le résultat
▶ Tâche claimée: #1 Préparer le contexte
status: in_progress · expires: ~2h · id: d4fb8a30
✓ Claim rafraîchi: #1 Préparer le contexte
status: in_progress · expires: ~2h · id: d4fb8a30
Private access audit · 1 événement
TIME LIST ACTOR TOOL
• 2026-01-01 00:30:00Z private-list agent-b task_lists.get
reason: User confirmed bypass
Full structured envelope:
{
"operation": "task_items.add_many",
"tool": "task_items",
"action": "add_many",
"result": []
}Examples:
{ "action": "find", "params": { "scope_type": "workspace", "scope_key": "/repo" } }
{ "action": "claim_next", "params": { "list_id": "release-work" } }
{ "action": "update", "params": { "task_id": "task-id", "status": "done", "outcome": "Decision: ship. Actions: tests. Final state: green." } }task_claims with action="claim_next" is the only normal way to move a task to in_progress.
task_items with action="update" and status="in_progress" is rejected intentionally to avoid multi-agent conflicts.
For long tasks, call task_claims with action="refresh" periodically. The default TTL is 2 hours.
When pausing a task with task_items action="update" and status="blocked", the active claim is cleared but responsibility is kept by default: if assigned_to_agent_id is omitted, pi-tasks sets it to the agent that paused the task. To fully release the paused task, pass assigned_to_agent_id: null in the same update call. To hand it off, pass another agent id.
Use notes as task-local working memory while a task is in progress: important context, choices in progress, blockers, assumptions, and next steps belong there.
outcome is the final deliverable, conclusion, or summary for a completed or canceled task. Closing a task with status="done" or status="canceled" requires a non-empty outcome; summarize the choices/decisions made, actions taken, and final state obtained.
Private lists are enforced strictly:
- shared lists are visible to all agents using the database;
- private lists are accessible only to
owner_agent_id, or tocreated_by_agent_idwhen no owner is set; - Pi can bypass after an explicit user confirmation dialog;
- MCP tries form elicitation when the host supports it, otherwise returns an access error.
Bypasses are audited in SQLite in private_access_events. Read them with /task-audit [list_id] [full] in Pi, or task_audit with action="get" in Pi/MCP. Reading audit events follows the same privacy model: list-specific reads require access to that list or an explicit user-confirmed bypass; global reads return only events for lists visible to the current agent.
Use Node.js 24.15.0 before installing dependencies. With nvm:
nvm use
npm install
npm run typecheck
npm test
npm run coveragenpm run coverage calls scripts/check-coverage.mjs, the same helper used by GitHub CI. It builds the project, runs the Node test runner with coverage enabled, and enforces 100% thresholds for lines, branches, and functions.
The test suite covers SQLite persistence, claim uniqueness, claim refresh, soft-delete, private-list enforcement, status rules, command formatting, widget formatting, and autocomplete helpers.
A GitHub Release and npm publication are created automatically when a semver tag is pushed. The package version used in npm and in the release artifact is derived from the tag, so releasing does not require committing a package version bump.
git tag -a v0.0.1 -m "pi-tasks 0.0.1"
git push origin v0.0.1The workflow reads Node.js from .node-version, builds dist/ on the runner, tests, runs npm pack, publishes that exact tarball to the public npm registry as @micka33/pi-tasks using the NPM_ACCESS_TOKEN GitHub secret, publishes the same tarball to GitHub Packages using the workflow GITHUB_TOKEN, updates the latest dist-tag on both registries, uploads the .tgz artifact and its SHA256 checksum to the GitHub Release, and force-updates the movable git tag latest to the released commit. NPM_ACCESS_TOKEN must be an npm token allowed to publish packages in the micka33 npm organization (for accounts with 2FA, use an automation/granular publish token). The workflow also requires packages: write permission so GITHUB_TOKEN can publish to https://npm.pkg.github.com. dist/ is intentionally ignored by git; release artifacts include the generated runtime build.
The npm tarball is intentionally minimal: bin/pi-tasks-mcp.js, dist/, README.md, and package.json. package-lock.json stays in git for reproducible development installs; npm excludes package locks from published package tarballs.
