Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Agentic Tasks

FreeMaintained

Task boards where people and agents claim and finish work.

GitHubEmbed

About

Task boards where people and agents claim and finish work.

README

npm version MIT license

Package · Source · Support

Task boards where people and agents claim and finish work.

Status: early (0.13.1). The library, CLI, and MCP server use the shared Store port from agentic-identity. The CLI keeps data in a local JSON file. The HTTP API runs as a Worker on a D1 database. Board roles come from agentic-identity. The Worker reads a bearer credential from the same D1 store. The package is on npm as agentic-tasks.

[!CAUTION] The Worker does not issue credentials. Run the agentic-identity Worker on the same D1 database to sign people in and to make keys. TASKS_UNSAFE_LOCAL_TEST_AUTH=1 swaps the credential for the X-Principal-Id and X-Principal-Kind headers. Nothing checks them. It serves only a request that names a loopback host and a loopback client address, and answers 403 to any other. Both are headers, not the socket. Keep wrangler dev on its default loopback address, or a caller on your network can forge them. Use it for local dev and tests only. TASKS_UNSAFE_LOCAL_REGION=1 skips the region check of the database. Use it for local dev only.

Install and quick start

Node 22 or later. Install the package, or run it with npx:

npm install agentic-tasks

Make a board, add a task, claim it, and finish it. The data goes to ./agentic-tasks.json. Every command needs --as and --kind. The kind is never defaulted.

tasks() { npx agentic-tasks "$@"; }
tasks board "Sprint" --columns "Todo,Doing,Done" --as ana --kind human

The output is the board as JSON. Copy its id and the id of the first column:

tasks new <board id> "Write the spec" --column <column id> --as ana --kind human
tasks claim <task id> --ttl-ms 600000 --as ana --kind human
tasks progress <task id> "Draft is done" --as ana --kind human
tasks close <task id> --as ana --kind human
tasks boards --as ana --kind human
tasks export --as ana --kind human

A <board id>, <task id>, <title>, or <name> argument also has a flag form: board --title Sprint, new --board <board id> --title "Write the spec", list --board <board id> (or list <board id>), column --board <board id> --name Done, and get --task <task id>. Every <task id> takes --task and every <board id> takes --board. The subject, role, and note of share, unshare, and progress are arguments only. Give a value as the argument or as the flag, not both. A word, flag, or missing value that a command does not accept fails with exit code 2 and a message that names it. tasks --help lists the commands, tasks <command> --help shows one command, and tasks --version prints the version. Use --file <path> or AGENTIC_TASKS_FILE to pick another store file.

Access

Every call has a principal from agentic-identity: who acts, the chain it acts for, and its scopes. A board is a resource with roles. A call needs a role:

Role Can
viewer read the board, its tasks, and progress notes
commenter also add progress notes
editor also add columns, make, move, edit, claim, release, and close tasks
owner also share the board, invite, make share links, list access, and take access away

Rename a board with renameBoard(id, title, ctx) on the store API, client.renameBoard(id, title) on the HTTP client, tasks rename <board id> "<title>" --as ana --kind human, or the rename_board MCP tool with boardId, title, and principal. The HTTP route is PATCH /api/v1/tasks/boards/:boardId with { "title": "New title" }. Each call returns the saved board. An owner or editor can rename. A viewer or commenter gets FORBIDDEN (HTTP 403). Titles are trimmed and must have 1–200 UTF-16 code units. Invalid titles get INVALID_INPUT (HTTP 400). A missing board gets NOT_FOUND (HTTP 404). Store calls throw TaskError; client calls throw TasksApiError. Rename updates updatedAt and records the actor in the access audit. Columns, tasks, and sharing stay the same.

The person who makes a board owns it. An agent that acts for a person gets that person's role, cut down by the scopes that its chain leaves. Every check writes an audit entry that keeps the chain and labels an agent action as machine-made. Share with the SDK (shareBoard, unshareBoard), the CLI (share, unshare), the MCP tools (share_board, unshare_board), or PUT and DELETE on /boards/:id/members/:kind/:subjectId. A role belongs to a kind (human or agent) and an id, so a person and an agent with one id are two subjects. The CLI needs --subject-kind. Erase a board, with its tasks, notes, and grants, with eraseBoard, erase, erase_board, or DELETE /boards/:id. Only an owner can. Listing tasks needs a boardId.

Every sharing call needs the owner role:

Action SDK CLI MCP tool HTTP
Give a role shareBoard share share_board PUT /boards/:id/members/:kind/:subjectId
Take a role unshareBoard unshare unshare_board DELETE /boards/:id/members/:kind/:subjectId
List grants, invites, links listAccess access list_access GET /boards/:id/access
Invite by email or handle inviteToBoard invite create_invite POST /boards/:id/invites
Make a share link createBoardLink link create_link POST /boards/:id/links
Revoke a share link revokeBoardLink unlink revoke_link DELETE /boards/:id/links/:linkId

An invite or a link gives viewer, commenter, or editor, never owner. Only a grant makes an owner. An invite names an email (a person) or a handle (an agent). A list shows no email. A link token shows once, in the reply that makes it. A list shows the link id, role, expiry, and revoke time, and never the token. expiresInMs (--expires-in-ms) sets how long an invite or link lives. signedInOnly (--signed-in-only true) limits a link to signed-in people. A link or an invite on its own does not change the board: accepting an invite and opening a link are part of agentic-identity.

Lifecycle

  • Delete one task and its notes with deleteTask, delete <task id>, delete_task, or DELETE /tasks/:id. It needs the editor role. While another principal holds a live claim, only the holder or a board owner can delete.
  • List the boards you hold a role on with listBoards, boards, list_boards, or GET /boards.
  • Export your own data with exportData, export, export_data, or GET /export. The JSON has each board you hold a role on, your role, the tasks you made, last changed, hold, or are assigned to, and the notes you wrote. A task is the whole task: it names the other people and agents on it and holds text that they wrote. The notes are only yours. Share the file with care. An agent exports its own tasks and notes, from the boards it can reach. The role is the grant of the person or agent at the root of its chain.

Account export and erase

Import tasksAccount from agentic-tasks/account. It implements the AccountPackage<TasksAccountDeps> registry contract of agentic-identity/account.

import { tasksAccount } from "agentic-tasks/account";
import { createAccountRegistry } from "agentic-identity/account";

const registry = createAccountRegistry().register(tasksAccount, { store });
const data = await tasksAccount.exportAccount({ id: "ana", kind: "human" }, { store });
const counts = await tasksAccount.eraseAccount({ id: "ana", kind: "human" }, { store });

The host authenticates the subject and gives the contributor a trusted Store. Stop writes before export and keep them stopped through erase. The contributor reads all stored boards to find authorship after access is revoked. The export has plain JSON in boards, tasks, notes, grants, invites, links, and audit. Owned boards include all their tasks, notes, and sharing data. Other boards include the subject's authored data and grants. Link token hashes stay private. This package stores no versions, attachments, or blob bytes. Progress notes and identity audit entries are its stored history.

Erase deletes sole-owned boards and their data. Shared boards keep other owners. The subject's grants and invites go. Its notes go, its assignments and claims go, and its author stamps become (erased). Author kinds and audit machine labels stay. Counts include deleted and scrubbed records. Each board changes in one transaction. A failed commit leaves that board available for retry. A completed erase counts zero on retry. Damaged records, grants, and parent paths stop both calls before data changes.

This replaces the provisional { tasks, ctx } dependency with { store }. Call once for each principal kind that wrote data. Delegated agent kinds and user tokens hold roles as agent and human, as the task API does. Invites have no creator kind, so use unique ids across kinds. An invite made by someone else for the subject's email stays; the package has no verified address mapping. Run this contributor before the identity account erase, which removes parent folder grants and identity records outside task boards.

SDK

agentic-tasks/client is a typed client for the Worker HTTP API. It uses only fetch, so it runs in Workers and Node 22, and in a browser on the same origin as the Worker.

import { createClient, TasksApiError } from "agentic-tasks/client";

const tasks = createClient({ baseUrl: "https://tasks.example.com", token });
const board = await tasks.createBoard({ title: "Sprint" });
try {
  await tasks.getTask(taskId); // read a task before you claim it
  await tasks.claim(taskId, { ttlMs: 600_000 }, { signal: AbortSignal.timeout(5000) });
} catch (error) {
  if (error instanceof TasksApiError) console.error(error.code, error.status);
  else throw error;
}
  • baseUrl is the Worker URL, http or https, with no query, hash, or credentials. The client adds /api/v1/tasks after any path prefix.
  • token is a bearer credential that the Worker accepts. fetch is optional.
  • One method for each route: createBoard, getBoard, renameBoard, addColumn, shareBoard, unshareBoard, listAccess, inviteToBoard, createBoardLink, revokeBoardLink, eraseBoard, listBoards, exportData, deleteTask, createTask, listTasks, getTask, updateTask, moveTask, claim, release, closeTask, progress, and listProgress.
  • A refused call throws TasksApiError with the API error code and the HTTP status. A reply that is not an API error, or a success reply with the wrong shape, has the code UNKNOWN.
  • Each method takes { signal } last. An aborted call rejects with the signal reason: AbortError, or TimeoutError for AbortSignal.timeout. A write that was aborted after it was sent may still have applied. Read the task before you try again.
  • The client does not follow redirects: a 3xx reply fails as UNKNOWN.
  • The Worker sends no CORS headers. A browser page can call it only from the same origin.
  • The client never retries. A refused claim stays refused: wait for the holder or the expiry.

createClient(options: ClientOptions): TasksClient creates the client. ClientOptions holds baseUrl, token, and optional fetch. CallOptions holds an optional abort signal. ListTasksFilter selects a board and optionally a column or status. ApiErrorCode names API error codes; MemberKind and BoardRole name sharing subjects and roles. The client also exports the Board, ProgressEntry, Task, TaskStatus, BoardAccess, ClaimOptions, InviteInput, LinkInput, LinkSummary, MoveTarget, NewTask, TaskPatch, and TasksExport types described under Library.

Live demo

A demo Worker runs at https://agentic-tasks-demo.hello-fd1.workers.dev. GET /api/v1/tasks/health answers 200. The web UI loads on /. The demo holds no credentials, so any other API call answers 401. It uses its own D1 database in the EU. It is a staging demo. Do not store real data in it.

Redeploy it with your own Cloudflare account. Log in with wrangler login, or export CLOUDFLARE_API_TOKEN in your shell. Do not put a token in the repo or in CI.

npx wrangler d1 create agentic-tasks-demo --location weur
# Put the database id in wrangler.demo.jsonc, then:
export WRANGLER_SEND_METRICS=false
npx wrangler d1 migrations apply DB --remote --config wrangler.demo.jsonc
npm run deploy:demo

Features

  • Boards with columns that you name.
  • Tasks with a title, a description, labels, a due date, and assignees.
  • People and agents claim a task for up to one day. The holder or a board owner can release the claim.
  • Progress notes on a task.
  • Agent tools over MCP: create, get, list, move, update, claim, release, and close tasks, and add and list progress notes.
  • Board roles: viewer, commenter, editor, and owner. Share a board with a role, invite by email or handle, and make share links.

Not yet

  • Real-time updates. A person or an agent sees a change by someone else only when it reads the task or the list again.
  • Accepting an invite and opening a share link in this package. Make and list them here. agentic-identity takes them.

Surfaces

One package gives you each way in:

  • Library and SDK: import { ... } from "agentic-tasks". The remote client is agentic-tasks/client.
  • CLI: npx agentic-tasks --help. See the quick start above.
  • MCP server: npx agentic-tasks mcp, for Claude Code and other MCP clients.
  • HTTP API: a Cloudflare Worker at /api/v1/tasks. Read the caution above first.
  • Worker export: import { createApp } from "agentic-tasks/worker". A host Worker calls createApp(resolve, auth?) to serve the HTTP API. resolve(env) returns the Tasks object from createTasks. auth is an Auth from agentic-identity 0.10, or a function of the Worker env (the DB and TASKS_REGION bindings). It replaces the default credential check on D1, and passing it turns off TASKS_UNSAFE_LOCAL_TEST_AUTH. The Worker still binds a D1 database as DB and sets TASKS_REGION (eu or us). The default export is the ready-made app on D1.
  • Web UI: a small app served by the same Worker.

Exports

The package has these entries. The build writes each one to dist/.

Entry or bin What it is Where it is described
agentic-tasks/account The typed account contributor. Account export and erase
agentic-tasks The library: createTasks, createFileStore, tasksAccount, trustedContext, types, TaskError, PRINCIPAL_KINDS, and VERSION. Library
agentic-tasks/client A typed client for the Worker HTTP API. SDK
agentic-tasks/worker The HTTP API as a Hono app for a Cloudflare Worker. Worker
agentic-tasks/ui mount, which renders the task UI in your page, with its option types and the TasksClient type. Mount the UI
agentic-tasks/ui.css The styles for agentic-tasks/ui. Mount the UI
agentic-tasks (bin, dist/cli.js) The CLI. agentic-tasks mcp serves the MCP tools. CLI and MCP

There is no agentic-tasks/mcp entry. Start the MCP server with npx agentic-tasks mcp.

Library

The library reads no environment variables. Give it a store.

Every Tasks method takes a principal context from agentic-identity. trustedContext(id, kind) makes one from a principal id and a kind. It does not check the id or the kind. Use it only in local code that you control.

import { createFileStore, createTasks, trustedContext } from "agentic-tasks";

const tasks = createTasks({ store: createFileStore("./agentic-tasks.json") });
const ana = trustedContext("ana", "human"); // no check: local code only

const board = await tasks.createBoard({ title: "Sprint" }, ana);
await tasks.addColumn(board.id, "Todo", ana);
const task = await tasks.createTask({ boardId: board.id, title: "Write the spec" }, ana); // no columnId: the first column
await tasks.getTask(task.id, ana); // read a task before you claim it
await tasks.claim(task.id, ana, { ttlMs: 600_000 });
  • createTasks({ store, now? }) returns the Tasks methods. store is any Store from agentic-identity that passes its contract suite. now is a () => Date clock, for tests.
  • createFileStore(path, options?) is the JSON file adapter. options are the adapter options of agentic-identity.
  • tasksAccount has exportAccount and eraseAccount, for a host that runs account export and erase. See Account export and erase.
  • A refused call throws TaskError. Its code is one of NOT_FOUND, FORBIDDEN, INVALID_INPUT, CLAIM_HELD, NOT_HOLDER, or TASK_CLOSED.
  • PRINCIPAL_KINDS lists the kinds: human, agent_of_human, agent_of_agent, agent, and user_token. VERSION is the package version.

The library also exports these TypeScript types:

  • Board, Column, Task, Claim, and ProgressEntry describe stored records.
  • Principal and PrincipalKind describe an actor; TaskStatus describes a task state.
  • TaskErrorCode names the error codes of TaskError.
  • Tasks is the library API; TasksOptions supplies its store and optional clock.
  • NewBoard, NewTask, TaskPatch, and MoveTarget describe write inputs.
  • ClaimOptions sets a claim TTL; TaskFilter selects tasks to list.
  • InviteInput and LinkInput describe sharing inputs; LinkSummary and BoardAccess describe access results.
  • TasksExport describes exported boards and their data.
  • TasksAccount describes the account lifecycle API; TasksAccountDeps supplies its Store.

Worker

The default export of agentic-tasks/worker is the HTTP API at /api/v1/tasks. It is a Hono app with a fetch handler. It stores data in the D1 database bound as DB. The package does not serve the web UI. This repo's own Worker serves the UI.

Export the app from your Worker's entry file:

// src/index.ts
export { default } from "agentic-tasks/worker";

Add this to your Wrangler config. It sets the nodejs_compat flag. The Worker needs this flag because agentic-identity uses Node built-ins such as Buffer:

{
  "name": "my-tasks",
  "main": "src/index.ts",
  "compatibility_date": "2026-01-01",
  "compatibility_flags": ["nodejs_compat"],
  "vars": { "TASKS_REGION": "eu" },
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "agentic-tasks",
      "database_id": "<id from wrangler d1 create>",
      "migrations_dir": "migrations"
    }
  ]
}

The package does not ship the schema. Set up the database in this order:

  1. Create the database in the EU: npx wrangler d1 create agentic-tasks --location weur. For us, use --location wnam or --location enam, and set TASKS_REGION to us.
  2. Put the id that d1 create prints in database_id in the config above.
  3. Copy every file in this repo's migrations/ folder into your migrations/ folder.
  4. Run npx wrangler d1 migrations apply DB --remote.
Binding or variable Needed What it does
DB Yes The D1 database. Without it every route under /api/v1/tasks except health answers 503 STORE_NOT_CONFIGURED.
TASKS_REGION Yes eu or us, where the database lives. You set it. The Worker does not detect it. Without a valid value, every route under /api/v1/tasks except health answers 503 REGION_NOT_CONFIGURED.
TASKS_UNSAFE_LOCAL_TEST_AUTH No 1 trusts the X-Principal-Id and X-Principal-Kind headers, on loopback requests only. Use it only for local dev and tests. A request that is not on loopback gets 403 LOCAL_TEST_AUTH_NOT_LOOPBACK.
TASKS_UNSAFE_LOCAL_REGION No 1 lets TASKS_REGION be unknown, because local D1 reports no region. Set it only for local dev. Never set it in production.

Without test auth, the default export takes a bearer token, or a session cookie, from the request and checks it against the same D1 database. Run the agentic-identity Worker on that database to issue credentials. The responses are:

  • No credential, or a malformed Authorization header: 401 UNAUTHENTICATED. The Worker does not read the store.
  • A token that is unknown, expired, or revoked: 401 UNAUTHENTICATED, after a store read.
  • A write that sends a valid session cookie and no bearer token: 403 FORBIDDEN.
  • The store cannot do the credential check: 503 STORE_BUSY with retry-after: 1. A retry can succeed.
  • Region mismatch: a request with a well-formed bearer token or a session cookie gets 503 STORE_BUSY too, with retry-after: 1. The client sees the same response as a busy store. So if STORE_BUSY keeps coming back after a few retries, check TASKS_REGION and the database location.

The module also has these named exports:

  • createApp(resolve, auth?) builds the app. resolve(env) returns the Tasks to use. env holds the Worker bindings. The Bindings type is not exported, so type env as unknown in your own code. auth is an Auth from agentic-identity, or a function of env that returns one. When you pass auth, TASKS_UNSAFE_LOCAL_TEST_AUTH has no effect.
  • tasksOnD1(env): Tasks returns the default Tasks on DB.
  • authOnD1(env): Auth returns the default credential check on DB.
  • localTestAuth: Auth reads the local test principal headers on loopback requests.
  • isLoopbackRequest(request: Request): boolean checks the request URL host and cf-connecting-ip for loopback values.

To use another store or credential check, call createApp yourself. It still needs the DB binding and a valid TASKS_REGION. Without them it answers 503 before it calls your store.

Your auth decides what a region mismatch looks like:

  • If your auth reads the database and throws, the response is 503 STORE_BUSY, as above.
  • If your auth passes the request and the task store then hits a region mismatch, the response is 500 INTERNAL.

Install the required peer agentic-identity at >=0.10.0 <1.0.0 in your app. The example imports its types:

import { createApp } from "agentic-tasks/worker";
import { createTasks } from "agentic-tasks";
import type { Auth, Store } from "agentic-identity";

declare const myStore: (env: unknown) => Store;  // your Store
declare const myAuth: Auth;                      // your Auth

export default createApp(
  (env) => createTasks({ store: myStore(env) }),
  myAuth,
);

CLI and MCP

npx agentic-tasks runs the CLI. npx agentic-tasks mcp serves the MCP tools over stdio.

Both use the store file that --file names, then AGENTIC_TASKS_FILE, then ./agentic-tasks.json. A relative path starts at the current directory of the shell that runs the CLI, or at the directory where the MCP client starts the server. An MCP client config:

{
  "mcpServers": {
    "agentic-tasks": {
      "command": "npx",
      "args": ["agentic-tasks", "mcp", "--file", "./agentic-tasks.json"]
    }
  }
}

UI

This repo's Worker serves a small web app on /. It uses the agentic-design package from npm for tokens, controls, and overlays, and the typed client from agentic-tasks/client to call the API.

Run it on your machine:

npm ci
export WRANGLER_SEND_METRICS=false
npm run build
npx wrangler d1 migrations apply DB --local
npx wrangler dev --var TASKS_UNSAFE_LOCAL_TEST_AUTH:1 --var TASKS_REGION:unknown --var TASKS_UNSAFE_LOCAL_REGION:1

Open http://127.0.0.1:8787. Give a principal id and a kind. The UI never defaults the kind. Leave the token empty: the local Worker trusts that name on loopback requests only. A deployed Worker needs a bearer token in the token field.

What it does:

  • Create a list. The UI adds the columns To do, Doing, and Done.
  • Add a task with the quick add field at the foot of a column: type a title, press Enter.
  • Drag a card to another column. Without a pointer, press Alt and the left or right arrow on a card, or use the card menu: "Move to" a column. Press F2 on a card, or use "Rename" in the card menu, to rename it in place.
  • Open a card to edit it in the side panel: description, labels, due date, column, assignees, and claim. A card shows the due date, the assignees, and the claim as small chips. A late due date has its own tone.
  • Show tasks as a board or a list. Filter by text, status, and column, or show only tasks that an agent created or last changed.
  • Mark each task that an agent created, or that an agent changed last. The mark is words and an icon.
  • Show loading, empty, and error states. A refused call shows its error code.

It works with a keyboard, shows a focus ring, and follows the system light or dark theme or your pick. An axe check for WCAG 2.2 AA runs on each view in both themes. Screenshots are in docs/screenshots. The screenshots from before the 0.11.0 redesign are in docs/screenshots/before. The calm look follows the agentic-design 0.10 tokens, which take their style from Tiny Little Office (MIT). No code is copied.

Run the browser tests. They start wrangler dev on port 18743:

npx playwright install chromium
npm run test:e2e
SCREENSHOTS=1 npm run test:e2e   # writes docs/screenshots

The UI limits:

  • A drop puts the card at the end of the target column. The UI does not reorder cards inside a column.
  • The API has no call that lists lists. The UI remembers the lists that this browser opened. Open another list by its id.
  • The session (id, kind, token) stays in sessionStorage until the tab closes.
  • The API keeps only the last writer of a task. If a person changes a task after an agent did, the mark for the agent change goes away. An agent that created a task stays marked.
  • The UI does not show progress notes or manage sharing.

Mount the UI in your app

agentic-tasks/ui renders the task UI inside your own page. Your app does not need React code. It must install react and react-dom (version 19), because agentic-tasks/ui imports them. You give it an element, the Worker origin, a function that returns the bearer token, and the principal who uses the UI. mount returns a handle.

import { mount } from "agentic-tasks/ui";
import "agentic-tasks/ui.css";   // the design styles and the task styles

const ui = mount(document.getElementById("tasks")!, {
  baseUrl: "https://tasks.example.com",
  getToken: async () => await myAuth.token(),   // called before every request
  principal: { id: "ada", kind: "human" },
  // boardId: "b_123",                          // open this list first
});

ui.update({ baseUrl, getToken, principal, boardId: "other" });  // show another list
ui.unmount();                                                   // remove the UI

mount(element: HTMLElement, options: TasksUiOptions): MountedTasks renders the UI. TasksUiOptions holds the connection and principal options. EmbedPrincipal holds the principal id and kind. MountedTasks provides update and unmount. The entry also exports the client API type TasksClient.

ui.css is global. It holds the design tokens and base rules for html, body, headings, and links, and it uses plain class names such as .card and .row. Load it on a page that can take those styles. The UI does not change the theme of the page: set data-theme on <html> yourself. The UI shows one h1, the list or board name.

The principal needs an id and a kind. A missing or unknown kind throws a TypeError. An empty token fails the call, and the UI shows the error. The server still checks every write against the token. The UI remembers the lists it opened in localStorage, under one key for the page origin. It does not separate Workers or principals.

agentic-identity is a required peer dependency. Install a version in >=0.10.0 <1.0.0.

react and react-dom (version 19) are optional peer dependencies. Install them to use agentic-tasks/ui. The CLI, the MCP server, and agentic-tasks/client do not need them. The web UI that the Worker serves uses the same components.

Run locally

git clone https://github.com/pooriaarab/agentic-tasks
cd agentic-tasks
npm install && npm run dev

You can also use bun install && bun run dev. The dev script calls npm, so npm must be installed. The scripts need macOS, Linux, or WSL. The dev script builds the package, then starts wrangler dev on http://localhost:8791. Wrangler keeps a local D1 database. The dev script turns off Wrangler telemetry. Set WRANGLER_SEND_METRICS=false when you run other wrangler commands.

curl -i http://localhost:8791/api/v1/tasks/health   # 200

The API needs a credential. To call it with test auth, stop npm run dev and use the commands in "Develop". They start the server with test auth on port 8787.

npm run dev:smoke runs the same check by itself. It starts the dev server. It waits for /api/v1/tasks/health to answer 200. It stops the server. CI runs it as the "dev smoke" step. To use another port, change 8791 in the dev and dev:smoke scripts.

Develop

npm ci
npm run build && npm run typecheck && npm test

Run the HTTP API on your machine only. Wrangler keeps a local D1 database:

export WRANGLER_SEND_METRICS=false
npx wrangler d1 migrations apply DB --local
npx wrangler dev --var TASKS_UNSAFE_LOCAL_TEST_AUTH:1 --var TASKS_REGION:unknown --var TASKS_UNSAFE_LOCAL_REGION:1

Local D1 reports no served region, so the store cannot check a region claim there. TASKS_UNSAFE_LOCAL_REGION=1 lets the Worker run with region unknown. Use it for local dev only. Never set it in production.

Deploy to a database in the EU. The location cannot change later:

npx wrangler d1 create agentic-tasks --location weur
# Put the database id in wrangler.jsonc, then:
npx wrangler d1 migrations apply DB --remote

TASKS_REGION in wrangler.jsonc is your claim about where the database lives (eu or us). The Worker answers 503 until it holds a valid region. The store also refuses a query that D1 reports as served outside that region. Production D1 reports the region for each query. Local D1 does not. Every Worker instance reads the same database, so a claim taken in one instance is refused in all of them.

Limits

  • The Worker reads credentials but does not issue them. Use the agentic-identity Worker for that.
  • The CLI and the MCP server trust the principal that you name, as git trusts user.name. Anyone who can open the store file can name any principal.
  • A role check and the action that follows are two steps. A role that is taken away at that moment can still finish the call that began before.
  • The JSON file store works on one machine. Do not put the file on a network share.
  • The CLI file format changed. It does not read files from earlier releases.
  • A move with a position that you name can share it with another task. Ids break the tie. Positions and note numbers that the package picks are always different.
  • Tasks use any Store that passes the agentic-identity contract suite. Pass a Store to createTasks. createFileStore is the file adapter. Use createMemoryStore from agentic-identity in tests.
  • A live claim blocks other claims and closes, except from a board owner. A claim lasts at most one day. Moves, edits, and progress notes do not check the claim.

License

MIT.

from github.com/pooriaarab/agentic-tasks

Install Agentic Tasks in Claude Desktop, Claude Code & Cursor

Recommended · one command, every IDE
unyly install agentic-tasks

Installs into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.

First time? Get the CLI: curl -fsSL https://unyly.org/install | sh

Or configure manually

Run in your terminal:

claude mcp add agentic-tasks --env SCREENSHOTS="" --env WRANGLER_SEND_METRICS="" -- npx -y agentic-tasks

Step-by-step: how to install Agentic Tasks

FAQ

Is Agentic Tasks MCP free?

Yes, Agentic Tasks MCP is free — one-click install via Unyly at no cost.

Does Agentic Tasks need an API key?

Yes, it requires environment variables: SCREENSHOTS, WRANGLER_SEND_METRICS. Unyly injects them into the config during install.

Is Agentic Tasks hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Agentic Tasks in Claude Desktop, Claude Code or Cursor?

Open Agentic Tasks on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Agentic Tasks with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All productivity MCPs