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 (recommended)
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, andtasuku-review-batches, plus their dead-letter queues - Durable Objects
Scheduler,RunEvents,CodexDeviceAuth,Mutex,UsageCache,Migrator,AgentContainerStandard, andAgentContainerLarge - Workflows
tasuku-run-attemptandtasuku-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 withopenssl rand -hex 32TASUKU_MASTER_KEY— generate withopenssl 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_TOKENor 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 deploybun 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 --cachedCloudflare 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.