A self-hosted, open source, git-native whiteboard for collaborative planning.
Tack cards, issues and ideas to a shared board, change tack together, and say tack to the people who got you there.
Try it in your browser, or read the docs at tack.social.
- Live GitHub cards: paste any issue or pull request link and it stays live via webhooks; lists and other widgets keep searches live
- Freeform canvas: move, group and sort stickies, issues and PRs around freely without affecting GitHub
- Staged pushes: create issues from stickies, label, link, and write decisions back, reviewed and pushed as one batch
- Async welcome: "since you were here", history replay, open voting windows
- Decisions: recorded on the board and written back as ADR PRs or Discussion posts
- GitHub identity: log in with GitHub; repo permissions decide what you can do
- Vite+ (
vp) — dev server, build, test, lint, format, and type checking in one toolchain cf— the Cloudflare CLI (technical preview), for deploys and everything Cloudflare@cloudflare/vite-plugin2.0, withcloudflare.config.tsfromcf/config- Vitest in Node, with integration tests running the built Worker in Miniflare. No Wrangler
- TypeScript, pnpm
- The canvas is built on React Flow (MIT), and sync on Yjs with y-partyserver
pnpm dev # dev server (with the Cloudflare local explorer at /cdn-cgi/local/explorer)
pnpm test # unit and integration tests (the built Worker in Miniflare)
pnpm e2e # Playwright smoke tests over /play (starts its own dev server)
pnpm check # format, lint, and type check
pnpm fix # same, but auto-fix
pnpm build # production build
pnpm run deploy # build and deploy via cf (`pnpm deploy` is a different, built-in pnpm command)
pnpm --filter site dev # the docs site (site/, Astro Starlight)
pnpm --filter site build # build the docs, failing on broken linksTack runs as one Worker on your Cloudflare account, with a GitHub App you own. tack.social has the full guide (its source is site/); in short:
- Deploy with the button above. It copies Tack into a new repository of yours and deploys it with Workers Builds. Keep the Worker's name,
tack. - Give it
TACK_SECRETwhen the button asks: a long random value (openssl rand -base64 32). It signs session cookies and encrypts the GitHub App's credentials, so keep a copy somewhere safe and never change it. - Visit
/setupon your instance straight away. Its checklist walks you through the rest: choose Create GitHub App, and GitHub fills in the permissions, events, webhook and callback URLs from a manifest; you confirm, and you're sent back signed in as the instance's first admin. - Install the app on the repositories you plan with (
/setuplinks to it). Public repos work without it; installing makes cards live and private repos visible./setupchecks webhooks arrive, and lists every repository the app's on and any on boards it isn't. - Decide who can use it: on
/setup, admins add other admins, allowed GitHub users and allowed organisations. Everyone else who signs in sees an "invite-only" page.
Or deploy from your machine: fork and clone, pnpm install, pnpm exec cf auth login, then give the first deploy its secret (a new Worker needs it from the start):
echo "TACK_SECRET=$(openssl rand -base64 32)" > .env.secrets # keep a copy of it somewhere safe
pnpm run deploy --secrets-file .env.secrets
rm .env.secretsLater deploys are just pnpm run deploy, or connect the Worker to Workers Builds. Upgrading is pulling from ascorbic/tack and deploying: boards and storage migrate themselves when they next load.
Or have a coding agent set it up: point it at tack.social/setup.md, which forks, configures and deploys Tack from your terminal and stops for the steps you do in a browser.
Previews (and any instance without TACK_SECRET) have no sign-in: boards work anonymously.
Copy .dev.vars.example to .dev.vars (gitignored) and fill it in:
TACK_SECRET=<any random string>
TACK_DEV_AUTH=1 # fake sign-in at /auth/dev?login=octocat&admin=1, local onlyA GitHub App made from /setup on localhost works for sign-in and installation tokens, but GitHub can't deliver webhooks to it; use scripts/send-webhook.ts.
- cloudflare.config.ts — the Worker itself: name, entrypoint, compatibility, bindings.
Envtypes are inferred from the bindings you declare here and generated into.cloudflare/types/bycf workers types(run on install, or withpnpm types). - compatibility.ts — compatibility date and flags, shared with the test runtime.
- wrangler.jsonc — generated from
cloudflare.config.ts(pnpm run wrangler-config) for the Deploy to Cloudflare button, which only reads Wrangler configuration. Nothing else uses it; don't edit it by hand. - vite.config.ts — everything else: Vite, Vitest, oxlint, and oxfmt in one file.
- site/ — tack.social: the docs, the landing page and the
/trydemo (built from the app's own client). You don't need it to run your own Tack, and the Deploy button andpnpm run deployleave it out.