SprintJam makes it easy to estimate stories in minutes with live voting, smart consensus insights, and a distraction-free room that keeps everyone focused. No sign-ups required, just share a link to start.
Note: This is somewhat of a passion project built in my spare time. While I strive to maintain and improve it, please be aware that it is provided "as is". A large amount of development has also been contributed with AI assistance. All contributions and feedback are welcome!
- Classic planning poker with Fibonacci, short Fibonacci, doubling, T-shirt sizes, hours, yes/no, simple, planet, or custom scales
- Structured voting with weighted scoring across complexity, confidence, volume, and unknowns
- Extra vote cards such as unknown, coffee break, and cannot complete
- The Judge analyses vote spread, suggests a consensus score, and flags when discussion is still needed
- Moderator controls for hidden voting, auto-reveal, locked votes, spectator mode, and passcode-protected rooms
- Shared timers, contextual room guidance, summary cards, and vote distribution views
- Jira, Linear, and GitHub integrations with workspace-managed team connections and room-level flows
- Import tickets, browse boards, sprints, cycles, repos, and milestones, then estimate without leaving SprintJam
- Sync estimates back to the source system and save rooms against workspace teams for later
- Magic-link sign-in for approved workspace domains
- MFA with TOTP or passkeys, plus recovery codes
- Team defaults, shared integrations, saved sessions, and workspace-level planning insights
- WebSocket-powered rooms with live presence, moderator controls, and shareable links or QR codes
- A built-in spin-the-wheel tool for quick decisions during planning sessions
- Quick break games including Guess the Number, Word Chain, Emoji Story, One-Word Pitch, Category Blitz, Clueboard, Sprint Word, Team Threads, and Sprint Risk
- No ads or tracking
- Self-hostable on Cloudflare
- Open source and transparent
Simply visit sprintjam.co.uk and start creating rooms immediately!
-
Clone the repository
git clone https://github.com/nicholasgriffintn/sprintjam.co.uk.git cd sprintjam.co.ukYou should end up with a pnpm monorepo that contains the following apps:
apps/app- dispatch worker and static assetsapps/room-worker- planning poker APIs, WebSockets, and thePlanningRoomDurable Objectapps/auth-worker- workspace auth, teams, and team-level integrations backed by D1apps/stats-worker- stats ingest and query APIs backed by D1apps/wheel-worker- spin-the-wheel APIs and theWheelRoomDurable Object
-
Install dependencies
corepack enable pnpm install -
Create local worker env files
pnpm run devstarts the app and boots the other workers through the Cloudflare Vite plugin. Secrets now live per worker, not in a single root.dev.varsfile.# apps/room-worker/.dev.vars TOKEN_ENCRYPTION_SECRET=replace-me # Optional: # STATS_INGEST_TOKEN=replace-me # INTERNAL_API_SECRET=replace-me # FEEDBACK_GITHUB_TOKEN=replace-me # POLYCHAT_API_TOKEN=replace-me # JIRA_OAUTH_CLIENT_ID=your-jira-client-id # JIRA_OAUTH_CLIENT_SECRET=your-jira-client-secret # JIRA_OAUTH_REDIRECT_URI=https://your-domain.com/api/jira/oauth/callback # LINEAR_OAUTH_CLIENT_ID=your-linear-client-id # LINEAR_OAUTH_CLIENT_SECRET=your-linear-client-secret # LINEAR_OAUTH_REDIRECT_URI=https://your-domain.com/api/linear/oauth/callback # GITHUB_OAUTH_CLIENT_ID=your-github-client-id # GITHUB_OAUTH_CLIENT_SECRET=your-github-client-secret # GITHUB_OAUTH_REDIRECT_URI=https://your-domain.com/api/github/oauth/callback
# apps/auth-worker/.dev.vars TOKEN_ENCRYPTION_SECRET=replace-me RESEND_API_KEY=replace-me # Optional: # INTERNAL_API_SECRET=replace-me # JIRA_OAUTH_CLIENT_ID=your-jira-client-id # JIRA_OAUTH_CLIENT_SECRET=your-jira-client-secret # JIRA_OAUTH_REDIRECT_URI=https://your-domain.com/api/teams/integrations/jira/callback # LINEAR_OAUTH_CLIENT_ID=your-linear-client-id # LINEAR_OAUTH_CLIENT_SECRET=your-linear-client-secret # LINEAR_OAUTH_REDIRECT_URI=https://your-domain.com/api/teams/integrations/linear/callback # GITHUB_OAUTH_CLIENT_ID=your-github-client-id # GITHUB_OAUTH_CLIENT_SECRET=your-github-client-secret # GITHUB_OAUTH_REDIRECT_URI=https://your-domain.com/api/teams/integrations/github/callback
# apps/stats-worker/.dev.vars STATS_INGEST_TOKEN=replace-me
# apps/wheel-worker/.dev.vars TOKEN_ENCRYPTION_SECRET=replace-me
Notes:
- Set the same
INTERNAL_API_SECRETinapps/room-worker/.dev.varsandapps/auth-worker/.dev.varsif you want room sessions to use team-level provider credentials. - Set the same
STATS_INGEST_TOKENinapps/room-worker/.dev.varsandapps/stats-worker/.dev.varsif you want round stats to be persisted locally. - Add OAuth credentials to both
apps/room-worker/.dev.varsandapps/auth-worker/.dev.varsif you want both room-level and team-level integrations.
- Set the same
-
Apply the local database migrations
pnpm run db:migrate:local
This writes local D1 state to
.data, which is also where local Durable Object state is persisted. -
Start local development
pnpm run dev
Then open
http://127.0.0.1:5173. -
Prepare your Cloudflare account before the first deploy
The checked-in
wrangler.jsoncfiles still need your own account-level resources:- update the routes in
apps/app/wrangler.jsonc - create a D1 database for auth and stats, then replace the bound
database_nameanddatabase_idvalues inapps/auth-worker/wrangler.jsoncandapps/stats-worker/wrangler.jsonc - keep the service binding names aligned across workers if you rename any Worker
- add the same secrets in Cloudflare that you used locally
- update the routes in
-
Deploy to Cloudflare
Authenticate Wrangler first with
wrangler loginor by exportingCLOUDFLARE_API_TOKEN.pnpm run db:migrate:prod pnpm run deploy
For staging, use
pnpm run db:migrate:stagingandpnpm run deploy:staging.
# Start the app and auxiliary workers
pnpm run dev
# Type-check the monorepo
pnpm run typecheck
# Build all packages
pnpm run build
# Run unit tests
pnpm run test
# Run E2E tests
cd apps/app
pnpm exec playwright install --with-deps
pnpm test:e2eFor local HTTPS, SprintJam uses apps/app/.certs/local.pem and apps/app/.certs/local-key.pem. Create both files together from the same command so they always match.
cd apps/app
mkdir -p .certs
mkcert -cert-file .certs/local.pem -key-file .certs/local-key.pem sprintjam.localhost
pnpm run dev -- --host sprintjam.localhostIf those certificate files exist, Vite automatically serves HTTPS. Then open https://sprintjam.localhost:5173.
Contributions are welcome! This project was built quickly and there are definitely areas for improvement.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request