Tasuku
Start here

Install Tasuku

Deploy Tasuku into your own Cloudflare account and verify its health.

Tasuku deploys as a single Cloudflare Worker. There is no separate database, queue, or runtime host to stand up first — the Worker's wrangler.jsonc declares every binding it needs, and both installation paths below provision them for you.

Deploy to Cloudflare

The button reads the repository's root wrangler.jsonc and provisions every binding it declares:

  • a D1 database (tasuku)
  • an R2 bucket (tasuku-artifacts)
  • a KV namespace (CACHE)
  • Queues tasuku-inbox, tasuku-effects, and tasuku-review-batches, plus their dead-letter queues
  • Durable Objects Scheduler, RunEvents, CodexDeviceAuth, Mutex, UsageCache, Migrator, AgentContainerStandard, and AgentContainerLarge
  • Workflows tasuku-run-attempt and tasuku-secret-rotation
  • Containers, pointed at the prebuilt docker.io/amalshaji/tasuku-agent-runtime:<version> image

Because the container classes default to that prebuilt image rather than a local Dockerfile build, the button works with no Docker involved at all — Workers Builds cannot build a container image for you.

Secrets

The button prompts for every key in .dev.vars.example:

  • TASUKU_BOOTSTRAP_TOKEN — generate with openssl rand -hex 32
  • TASUKU_MASTER_KEY — generate with openssl rand -base64 32 (must decode to exactly 32 bytes)

Store both generated values outside the repository; you need them again for Backup and recovery. TASUKU_PREVIOUS_MASTER_KEYS also lives in .dev.vars.example, defaulting to {} — leave it alone until you rotate the master key, see Master-key rotation.

First request applies migrations

Tasuku does not ship a separate migration step. The Migrator Durable Object applies every pending server/drizzle/*.sql file the first time any request reaches an /api/* route or /readyz (both run behind the same migrations-gate middleware), and at the start of every Workflow — so the deployment is ready to bootstrap as soon as the button finishes. Requests outside /api/*//readyz (/healthz, /artifact/*, the dashboard SPA shell) never trigger this check.

Bootstrap the organization

Create the first organization by calling POST /api/v1/bootstrap with the bootstrap token, either from a local clone:

bun run bootstrap --url https://<your-worker>.workers.dev --token $TASUKU_BOOTSTRAP_TOKEN

or with curl:

curl -X POST https://<your-worker>.workers.dev/api/v1/bootstrap \
  -H "Authorization: Bearer $TASUKU_BOOTSTRAP_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"organization_name":"Acme"}'

Then open https://<your-worker>.workers.dev/setup/github-app and continue with Create the GitHub App.

Deploy from the CLI

Prefer the CLI when you want the code on your machine before it touches Cloudflare, or when the repository isn't public.

git clone https://github.com/amalshaji/tasuku.git
cd tasuku
bun install
bunx wrangler login
bun run deploy

bun run deploy builds the dashboard and runs wrangler deploy, which provisions the same bindings the button does and deploys the Worker using the prebuilt docker.io/amalshaji/tasuku-agent-runtime image pinned in wrangler.jsonc — still no local Docker required.

Faster cold starts with --cached

bun run deploy --cached

Cloudflare only caches a locally built container image in your account's registry; an image referenced by a docker.io (or any other external registry) tag is pulled fresh on every container cold start instead. --cached needs Docker running locally: it rewrites containers[].image to build from runtime/Dockerfile.cloudflare (FROM docker.io/amalshaji/tasuku-agent-runtime:<pin>), so wrangler deploy builds — really just re-tags — that image locally and pushes it into your account's container registry, where Cloudflare does cache it. Run it once after every deploy that changes the pinned runtime image; skip it if a slower first pull per container class is acceptable.

Pass a specific image instead with bun run deploy --image=docker.io/amalshaji/tasuku-agent-runtime:0.2.0, or forward flags straight to wrangler deploy after --, e.g. bun run deploy --env staging -- --dry-run.

Developing locally

bun run dev starts wrangler dev (port 8787) and the dashboard's Vite dev server (port 5173) together, writing a .dev.vars file with a random bootstrap token and master key on first run. Pass --no-containers to skip local container support (this also happens automatically if docker info fails).

Verify the deployment

curl --fail https://<your-worker>.workers.dev/healthz
curl --fail https://<your-worker>.workers.dev/readyz

/healthz reports process liveness. /readyz additionally confirms migrations are applied and D1 is reachable.

Public URL

Bootstrap persists the request's Origin header (validated: absolute, HTTPS unless localhost, no credentials) into D1 as the instance's public URL — the same origin used to build webhook, OAuth, and setup URLs. You do not need to set anything for this to work, including on a workers.dev URL you don't know in advance. This capture happens exactly once, at the single bootstrap call — there is currently no supported way to change the persisted value afterward. TASUKU_PUBLIC_URL in wrangler.jsonc is a fallback only: it's used if that bootstrap request's Origin header isn't a valid public URL, and is otherwise ignored, including on every later request — it never overrides an already-persisted value.

Continue with Create and install the GitHub App.

On this page