Deploy and run Ntasks
How to deploy Ntasks to your own Cloudflare account, set it up the first time, and run it on your machine.
Deploy your own
npx ntasks deployThis deploys the latest Ntasks release to your Cloudflare account: one Worker, its D1 database and the Durable Object that holds the tasks.
- You need Node.js and a Cloudflare account, and no copy of this repository.
- It ships the npm package
ntasks, which holds the built Worker, the web app and the D1 migrations, and deploys them with wrangler.
The first run:
- Opens Cloudflare's login in your browser (
wrangler login), unless wrangler is logged in already orCLOUDFLARE_API_TOKENis set. - Creates a D1 database named
ntasks, or uses the one of that name the account already has, as after a first run that stopped, and applies the D1 migrations it lacks.--dry-runnames the database first; when it is not Ntasks's, choose another name with--name. - Makes an
AUTH_SECRETand deploys a Worker namedntaskswith it. - Prints the Worker's address and the
AUTH_SECRET. Keep a copy: the setup page asks for it, and the command shows it only on this run.
| Option | What it does |
|---|---|
--dry-run | Prints the plan and changes nothing in the account. |
--name <name> | Names the Worker and its D1 database, when ntasks is taken. |
--account <id or name> | Chooses the Cloudflare account when your login reaches several. |
The command stops without changing anything when:
- your login reaches several accounts and none is chosen;
- the account's Worker of that name is not an Ntasks deployment: its deployed version lacks the
TASK_STOREDurable Object binding to the classTaskStoreor the D1 bindingDB, or it has no deployed version and no D1 database of its name.
An update replaces the Worker's code and applies migrations to its database. When the account holds other Workers, run it with --dry-run first: the plan names the account, the Worker, the database and the migrations.
Update
Run npx ntasks deploy again. It:
- finds the Worker in the account by name, and keeps the D1 database the Worker is bound to;
- applies the D1 migrations that database lacks;
- deploys the latest release, and prints the release before and after.
The Worker's secrets stay as they are, and each workspace's task store applies its own migrations when it next starts. npx ntasks@<version> deploy deploys that release in place of the latest.
Nothing is kept on your machine between runs: each deploy tags the Worker's version with its release, such as v0.1.0, and the next run reads the tag.
Moving to npx ntasks deploy. A deployment made with the button or from a checkout can move to it, with --name set to its Worker's name when that is not ntasks; the first run shows its current release as unknown. A Worker connected to a repository still deploys that repository on each push, so disconnect it in the Cloudflare dashboard under Workers & Pages, the Worker, Settings, Builds.
Deploy with the button
The button copies this repository into your GitHub or GitLab account and deploys that copy to your Cloudflare account. The copy has no link back to this repository, so new releases reach it only when you bring them into it yourself.
- It asks for one secret,
AUTH_SECRET: a random value of at least 32 characters. Make one withopenssl rand -base64 32, and keep a copy for the setup page below. - On Cloudflare's deploy page, the build command is
pnpm run buildand the deploy command ispnpm run deploy; set them if the page shows others. The build command builds the web app. The deploy command applies the D1 migrations to the database, then deploys the Worker. - Each push to your copy's
mainbranch runs both again.
Deploy from a checkout
To deploy a change of your own from a checkout of this repository, run these from its root after pnpm install:
pnpm run build
pnpm --filter @ntasks/api exec wrangler login
pnpm --filter @ntasks/api exec wrangler secret put AUTH_SECRET
pnpm --filter @ntasks/api exec wrangler deploy
pnpm --filter @ntasks/api exec wrangler d1 migrations apply DB --remoteThese deploy a Worker named ntasks with a D1 database named ntasks.
- Names already taken. If your Cloudflare account already has a Worker or a D1 database by that name that is not this deployment, change
nameanddatabase_nameinwrangler.jsoncfirst:wrangler secret putwould set the secret on the existing Worker, and the deploy would bind the existing database. Adatabase_idleft inwrangler.jsoncby an earlier deployment wins over the name, so remove it too when you want a separate database. - What each command creates.
wrangler secret putasks for the secret and offers to create the Worker when it does not exist yet. The firstwrangler deploycreates the D1 database, or connects to one of that name, creates the Durable Object that holds the tasks, and writes the database's id intowrangler.jsoncasdatabase_id; the migrations step then finds the database by that id. - Before you commit. The repository's
wrangler.jsoncleaves the id out so it works in any account, so remove thatdatabase_idline before you commit anything in the file. - Deploying on each push. Commit any
nameanddatabase_nameyou changed, without thedatabase_id, to the branch you deploy from. Then connect the Worker to the repository in the Cloudflare dashboard under Workers & Pages, the Worker, Settings, Builds, with the build and deploy commands above.
To update a deployment made from a checkout, bring the checkout to the latest main and run pnpm install, pnpm run build and pnpm run deploy from its root. pnpm run deploy applies any new D1 migrations, then deploys the Worker. A deployment connected to Builds updates on each push instead.
Set up sign-in
When the deploy finishes, set up sign-in with GitHub on the deployment's setup page:
- Open
/sign-inat the Worker's address, such ashttps://ntasks.<your subdomain>.workers.dev/sign-in.npx ntasks deployprints the address, and the Workers & Pages page of the Cloudflare dashboard shows it.- Sign-in is bound to the address the setup runs at, so use the one people will use.
- On a custom domain, use one that Google Safe Browsing does not list as unsafe: Chrome blocks GitHub's return to the sign-in callback on a domain it lists, even when the deployment's own address is not listed.
- Enter
AUTH_SECRET, the onenpx ntasks deployprinted or the one you made, and choose Create the GitHub App. - GitHub shows the app it will create under your GitHub account. Create it.
- GitHub returns to Ntasks and asks you to authorize the app. You are signed in as the deployment's admin.


The setup page describes what each step checks, and Settings the optional secrets that replace it with a GitHub OAuth app you register yourself. How an AI agent connects describes the steps an MCP client takes.
First run
A new deployment, or pnpm dev, needs AUTH_SECRET first (Sign-in). Then:
- Set up sign-in. Open
/sign-inat the deployment's address and run the setup page. The GitHub account that creates the app is the deployment's admin. - Create a workspace. An admin who belongs to no workspace sees one step, New workspace, and owns the workspace it creates. A workspace keeps its own projects, tasks and members apart from every other. Its owner renames it on the Settings page.
- Create a project. The Projects page opens with New project: a name and a prefix, the letters and digits that start every task id in the project (
webgivesweb-a1b2). On the Members page, an owner invites people by GitHub username; each joins when they first sign in. - Connect an agent. Run
curl -fsSL https://raw.githubusercontent.com/notice-cx/Ntasks/main/install.sh | bashon the agent's machine, or add the MCP endpoint,<address>/api/mcp, to an MCP client by hand (Connect an agent). The client signs in with OAuth, and you allow it and choose its projects on the approval page (How an AI agent connects).
A person in two or more workspaces switches between them from the workspace name at the top of the sidebar.
Run it locally
You need Node.js at the version in .node-version and pnpm at the version in package.json's packageManager field; CONTRIBUTING.md shows how to install them. No Cloudflare account is needed: local runs and tests use a local database.
pnpm install
pnpm --filter @ntasks/api exec wrangler d1 migrations apply DB --local
pnpm devThe second command creates the local D1 database's tables. Run it again after pulling a change that adds a D1 migration.
pnpm dev builds the web app and starts the Worker at http://localhost:8787. The health check at /healthz answers {"ok":true}.
To check a change the way CI does:
pnpm lint
pnpm format:check
pnpm typecheck
pnpm test
pnpm build