Story Points — full documentation (https://story-points.danielrose7.workers.dev) Source: https://story-points.danielrose7.workers.dev/docs/index.md # Story Points Realtime pointing poker for agile teams. No accounts, no install — one standing URL per room, reusable sprint after sprint. **App:** [story-points.danielrose7.workers.dev](https://story-points.danielrose7.workers.dev) ## How it works, in one paragraph Create a room (or claim any URL like `/room/your-team`), share the link, and everyone joins with just a name — as a voter or an observer. Votes stay hidden until everyone has voted (auto-reveal, configurable), then the spread, average, agreement %, and a distribution chart appear. The room keeps its settings, deck, theme, and history between sessions; refreshing the page reclaims your seat. ## Guides - [Getting started](/docs/getting-started) — create, invite, vote, reveal - [Features](/docs/features) — queue, history, countdown, anonymous voting, away votes, presets, and the toggles for all of them - [Themes](/docs/themes) — 29 themes plus seasonal auto-theming - [API](/docs/api) — plain-HTTP import/export for scripts, CLIs, and agents ## Principles - **No accounts — and that includes OAuth and API keys.** A room URL is the invitation and the capability; an optional 6-character room code is the only lock. Auth machinery is accounts by the back door: key issuance, rotation, revocation, a dashboard, a database of who's who — and keys parked in scripts and CI logs leak. Scoping the credential to one room and sharing it the way you share the room keeps all of that out, and it's what makes "point your own agent at the API" a one-click idea instead of a setup ceremony. - **Dependencies must earn their place.** ~20 KB of gzipped JavaScript: Lit, plus a lazy-loaded ~2 KB QR encoder that only downloads if you open the invite QR. That's the whole roster. - **No tracker integrations in the app.** A small HTTP API is the bridge; anything that can run `curl` can import a backlog and export results. - **Free to run.** Cloudflare Workers + one Durable Object per room, within the free plan — and [self-hostable](/docs/self-host) on yours. - **Speaks your language.** The app UI ships in English, Español, Deutsch, Français, Português, and 日本語 — auto-detected from your browser, with a 🌐 switcher in the footer. Language is personal, not per-room: one invite link, and each teammate sees their own. (These docs stay English.) --- Source: https://story-points.danielrose7.workers.dev/docs/getting-started.md # Getting started ## Create a room Hit **Create a room** on the [home page](https://story-points.danielrose7.workers.dev), or just visit any room URL you like — `/room/your-team-name` — and it's yours to claim. Room names are lowercase letters, digits, and dashes. When creating from the home page you can pick a **starting preset**: - 🏃 **Sprint planning** — Fibonacci deck, all features on (the default) - 👕 **T-shirt sizing** — XS–XL deck - 🚑 **Triage** — grouped severity tiers (Urgent/High/Medium/Low), no timer chimes or vote stats - 🎯 **Minimal** — just cards and a reveal; queue, history, stats, countdown, and chimes all off Presets only seed the room; everything stays editable in room settings. ## Invite the team The room URL is the invite — copy it from the "Invite your team" panel. Everyone enters a name and joins as a **voter** or an **observer** (observers watch and manage, but don't hold up the reveal). ## Vote and reveal 1. Type what you're estimating into the story description (it syncs live). 2. Voters pick a card. Others see *that* you've voted, never *what*. 3. When every connected voter has voted, cards flip automatically (auto-reveal is a setting; there's also a **Show votes** button and an optional ⏳ countdown that reveals at zero). 4. **Next ticket →** records the round to history and pulls the next story from the queue; **Re-vote** re-runs the same story without recording. ## Seats, refreshes, and hosts - Refreshing the page reclaims your seat — name, role, and current vote. - **Leave room** frees your seat so it doesn't block auto-reveal. - The first joiner is the **host** (⚙️ room settings, 👑 host transfer). If the host disconnects, the longest-seated member is promoted; the original host reclaims the role on return unless they handed it off explicitly. - Rooms keep settings and history for months between sessions, and clean themselves up after ~60 days of no use at all. --- Source: https://story-points.danielrose7.workers.dev/docs/features.md # Features Every optional feature has a host toggle in **⚙️ Room settings → Features**, so a room only shows what its team actually uses. Presets bundle sensible combinations at creation time. ## Ticket queue An **Up next** list of stories waiting their turn. Fill it four ways: type one-per-line, paste a tracker export (smart paste), 📎 **Import CSV** (Linear and Jira exports parse natively — multi-line descriptions and all), or `POST` from a script/agent (see [API](/docs/api)). Imports stage into a **preview table** — edit, reorder, or drop rows before adding. Lines ending in a ticket URL render a clickable ↗ link, in the queue and on the current story (Linear links are built automatically once the app has seen your workspace URL). Queue items can be reordered in place; **Next ticket →** records the finished round and pulls the front of the queue into the story. Toggle off to hide the panel and reject API imports. ## Round history **Next ticket →** after a reveal records the round — story, vote spread, and time-to-reveal — into a collapsible 📜 panel (last 50 rounds). Copy it out as Markdown or CSV, or download JSON/CSV from the same panel. **Re-vote** deliberately records nothing. The host can clear history in settings; switching the feature off stops recording without destroying existing entries. ## Voting countdown A ⏳ button starts an N-second countdown (5–600, default 60); votes reveal automatically at zero. Anyone can start or cancel it. The server owns the clock, so it fires even if everyone's tab is asleep. ## Vote statistics On reveal: vote count, average (numeric decks), **agreement %** (share of voters on the most common value), and a distribution bar chart when the vote spread. One toggle governs the extras. ## Anonymous voting Votes are never attributed to people — before *or* after reveal — except your own. Stats and celebrations still work; revealed seats show a ✓. ## Away votes Vote, close the tab, still count: your seat stays visible with a 💤 tag and your vote joins the reveal. Auto-reveal still keys off connected voters only. Toggle off for strict "live connections only" rooms. ## Timer, chimes, and rabbits Every round has an elapsed timer that freezes at reveal. It turns amber at 5 minutes and gains a hopping 🐇 at 10 — plus another every 5 minutes (they're a rabbit-hole warning, not a countdown). Optional chimes mark the escalations; the room can switch them off, and every individual has a local mute and volume slider. If everyone leaves mid-round, the clock restarts when the first person returns (toggleable). ## Deck editor and groups Decks are label + value pairs — Fibonacci, T-shirt, powers of 2, or fully custom. The **+ Groups** disclosure in the deck editor adds a Group column; cards sharing a group render as labeled clusters in the voting hand (e.g. severity tiers for triage). ## Room codes (optional) Rooms are open by default — the URL is the invitation. A host who wants a quieter table can flip **🔒 Require a room code** in settings: the server generates a 6-character airline-style code (no confusable letters), invite links carry it (`?code=ABC123`) so they still just work, and the API requires it too. People already in the room stay in when it's enabled; the host can regenerate the code at any time. Wrong guesses are rate-limited. ## Reactions and celebrations An ephemeral reaction tray (🐇 for "we're in a rabbit hole", plus two theme-flavored slots), high-five collisions when two people send the same emoji, and varied reveal celebrations — confetti, rockets, up-and-to-the-right charts — chosen by how the vote landed. Never persisted. --- Source: https://story-points.danielrose7.workers.dev/docs/themes.md # Themes 29 themes: five you pick because you like them, a seasonal calendar that rolls through the year on its own, and thirteen regional celebrations that only enter the rotation for rooms created in their locale. Every theme re-dresses the whole room — table felt, card backs, confetti — and invites two of its own emoji into the reaction tray. ## Seasonal (auto) New rooms default to **🗓 Seasonal (auto)**: the theme follows the calendar, resolving to the nearest holiday anchor every time the room is viewed — a standing room re-themes itself as holidays approach. The host can pin any specific theme in **Room settings → Theme**; picking "Seasonal (auto)" again unpins it. The home page always wears today's seasonal colors. ## The year-rounders | Theme | The room becomes | Tray guests | | --- | --- | --- | | 🃏 Card table | Casino felt — deep green, gold accents. The default deal. | 🎲 ♠️ | | 🚀 Outer space | Midnight navy with starlight — estimates from another planet. | 🛸 🌟 | | 🏄 Surf | Tropical teal, beach-day energy. | 🌊 🤙 | | 🎂 Birthday | Party purple; the confetti feels extra appropriate. | 🎈 🎁 | | 🪩 Nightclub | Near-black with neon — sprint planning after dark. | 💃 🕺 | ## The seasonal calendar Each seasonal theme "reigns" while its anchor date is the nearest one on the calendar (roughly the window between its neighbors): | Theme | Anchor | The room becomes | Tray guests | | --- | --- | --- | --- | | 🎊 New Year | Jan 1 | Champagne midnight — gold on black. | 🎊 🕛 | | 🧧 Lunar New Year | Feb 1 | Lantern red and gold. | 🧧 🐉 | | 💘 Valentine's | Feb 14 | Rose and berry. | 💘 🌹 | | 🍀 St. Patrick's | Mar 17 | Shamrock green. | 🍀 🌈 | | 🌸 Easter | Apr 5 | Soft lavender, pastel confetti. | 🐣 🌸 | | 🌷 Mother's Day | May 10 | Warm terracotta and tulips. | 🌷 💐 | | ☀️ Summer | Jun 21 | Golden hour, all day. | 🍦 😎 | | 📚 Back to School | Aug 25 | Amber chalkboard-and-pencils. | 📚 ✏️ | | 🍂 Fall | Sep 22 | Burnt orange, falling leaves. | 🍂 🌰 | | 🎃 Halloween | Oct 31 | Haunted purple-black. | 🎃 👻 | | 🎄 Christmas | Dec 25 | Evergreen and snow. | 🎅 ⛄ | ## Regional celebrations Rooms remember the locale they were created in, and these anchors only join that room's seasonal rotation — a German team's late-September room dresses for Oktoberfest, a French one skips the 4th of July and celebrates Bastille Day, and Thanksgiving stays an English-locale affair. Any host can still pin any of them manually, locale regardless. | Theme | Anchor | Rotation for | The room becomes | Tray guests | | --- | --- | --- | --- | --- | | 🎭 Carnaval | Feb 17 | pt | Rio night — purple stage, gold & green sparkle. | 🎭 🥁 | | 🌸 Hanami | Apr 1 | ja | Dusk over the sakura trees. | 🌸 🍡 | | 🎠 Feria de Abril | Apr 15 | es | Flamenco red, lantern light, lunares. | 🎠 💃 | | 🌽 Festa Junina | Jun 24 | pt | Bonfire night, bunting over the arraial. | 🌽 🎪 | | 🎆 4th of July | Jul 4 | en | Deep flag blue; red-and-white fireworks. | 🎆 🦅 | | 🎋 Tanabata | Jul 7 | ja | The Milky Way between Orihime and Hikoboshi. | 🎋 ⭐ | | 🐂 San Fermín | Jul 7 | es | Pamplona whites and red scarves. | 🐂 🧣 | | 🥖 Bastille Day | Jul 14 | fr | Bleu-blanc-rouge over a Paris night. | 🥖 🍾 | | 🏮 Obon | Aug 13 | ja | Paper lanterns on a warm indigo night. | 🏮 👘 | | 🥨 Oktoberfest | Sep 20 | de | Bavarian sky, lozenge tablecloth, beer gold. | 🥨 🍺 | | 💀 Día de Muertos | Nov 1 | es | Marigold path through the purple night. | 💀 🌼 | | 🥂 Beaujolais Nouveau | Nov 19 | fr | The cellar door opens — burgundy and warm gold. | 🍷 🧀 | | 🦃 Thanksgiving | Nov 26 | en | Warm oven browns. | 🦃 🥧 | Hover any tray emoji for its label — the seasonal guests have opinions ("🌰 tough nut to crack", "👻 ghost of sprints past", "🎅 ho ho hopefully a 3"). ## What a theme changes Palette (felt, accents, card backs), confetti colors, and the two tray slots. Link previews match too: sharing a room URL renders a social card in the room's theme. Under the hood a theme is one block of `--sp-*` CSS custom-property overrides in `src/styles.css` — custom properties inherit into shadow DOM, so every component follows automatically. That also makes a new theme one of the easiest contributions to the [open-source repo](https://github.com/danielrose7/story-points): a token block, two tray emoji, and one script run to generate its social card. ## Where the idea came from Seasonal auto-theming has a lineage: it started as a [CodePen experiment](https://codepen.io/bloom-dan/pen/RwGNePg) and grew up in [Name Draw](https://gobloom.io/posts/name-draw) — a Secret Santa name-drawing app with twelve themes that match the current month — before landing here as today's twenty-nine-theme calendar. Some ideas just want to re-decorate. --- Source: https://story-points.danielrose7.workers.dev/docs/compare.md # Story Points vs. the alternatives > The honest version: every tool here can run a planning-poker session. > Story Points is the one that's free, open source, needs no accounts, and > treats your room URL as the entire product. Here's where the others > differ, and when they're genuinely the better pick. *Facts checked July 2026 from each product's public site; pricing and limits may have changed since.* ## At a glance | | 🃏 Story Points | Pointing Poker | PlanningPoker.com | Parabol | Jira plugins | story-points.app | | --- | --- | --- | --- | --- | --- | --- | | Price | Free, no tiers | Free (donations + light ads) | Free tier + paid plans | Free tier + paid plans | Per-user via Atlassian | £4.99/mo after trial | | Accounts required | **None** | **None** | Facilitator signs up | Everyone signs up | Jira login | Sign-up + billing | | Player limit | None | None stated | Capped on free tier | Tier-dependent | Jira seats | 12 | | Persistent rooms | ✔ same URL every sprint | ✘ ephemeral sessions | ✔ with account | ✔ with account | ✔ inside Jira | ✔ with account | | Hidden votes + auto-reveal | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | Custom decks & grouping | ✔ | Custom values | Partial | Partial | Partial | Scales only | | Ticket queue + CSV import | ✔ Linear/Jira CSV, previewed | ✘ | Jira sync (paid) | ✔ | Native | ✘ | | Export results | ✔ Markdown, CSV, JSON API | ✘ | ✔ (paid tiers) | ✔ | Native | Paid tier | | Plain-HTTP API + llms.txt | ✔ | ✘ | ✘ | API (paid) | Jira API | ✘ | | Open source / self-host | ✔ MIT, 3 commands | ✘ | ✘ | ✔ AGPL | ✘ | ✘ | | Ads / data monetization | None | Light ads + donations | Ads on free tier | None | None | None claimed | ## Pointing Poker The one closest in spirit to Story Points — free, no signup, instant session links, and with tens of millions of votes cast it's earned its place as many teams' default. It runs on donations plus light ads. The trade-offs are a dated UI and ephemeral sessions: there's no standing room URL that keeps your deck, settings, and history between sprints, and no import/export surface — the session ends and the numbers leave with it. It also has a retrospective mode, which Story Points doesn't. **Choose it if** you want retros in the same tool or your team already lives there. If you're coming from Pointing Poker, Story Points is the same no-accounts idea plus persistence, tracker CSV import, exports, themes, and open source — minus the ads. ## PlanningPoker.com The incumbent — around since 2006, and fine at the core loop. The trade-offs are a dated free tier (player caps, ads) and accounts-plus-paid-plans for the features that matter to a recurring team: persistent games, Jira sync, exports. **Choose it if** your organization already pays for it or you need its deep Jira two-way sync. Story Points covers the import/export side with tracker CSV import and a plain-HTTP API instead — no integration to administer, nothing to grant OAuth to. ## Parabol The strongest product on this list — but it's a full agile-meetings suite (retrospectives, standups, sprint poker) with accounts, workspaces, and a per-user price once you outgrow the free tier. Estimation is one mode of a much bigger tool. **Choose it if** you want retros and standups in the same place and don't mind everyone signing up. If you only need estimation, you're carrying the weight of a suite to play cards. ## Planning poker plugins for Jira Estimation that lives inside Jira: native ticket sync, votes written back to the story field. The cost is the Jira-ness — an admin has to install it, everyone estimating needs a Jira seat, and guests (a contractor, a designer, your PM's PM) can't just click a link. **Choose one if** every estimator has a Jira license and you want write-back with zero copy-paste. Story Points deliberately stays outside your tracker: import the CSV, estimate with anyone who has the URL, export the results. ## story-points.app ("Scrum Poker") No relation, despite the name. It's a paid product (£4.99/mo after a 14-day trial) with required accounts, a 12-player room cap, and history/analytics behind the subscription. The core loop — hidden votes, reveal, scales — is the same as everything here. **Choose it if** its specific paid analytics appeal to you. Otherwise the comparison is short: Story Points has no price, no accounts, no player cap, and is open source. ## Physical cards Undefeated for an in-person team in one room. **Choose them if** you're all at the same table. Story Points is for when you're not — or when you want the round recorded without someone typing it up. ## Why free doesn't mean "until we charge" Story Points runs on Cloudflare's free tier and costs approximately nothing to operate, so there is no paywall and no plan for one. It's MIT-licensed — if it ever went away or went bad, `git clone`, `wrangler login`, `npm run deploy` puts your own copy on your own Cloudflare account in a few minutes. That's the real answer to "what's the catch": the license removes the ability for there to be one. **[Create a room](/)** — no signup, you'll be estimating in ten seconds. Or read [how the features work](/docs/features) and [the API](/docs/api). --- Source: https://story-points.danielrose7.workers.dev/docs/api.md # API Story Points deliberately ships **no tracker-specific integrations**. Instead, every room exposes a tiny plain-HTTP surface. The room slug is the capability — same trust model as the app itself — so anything that can run `curl` can bridge to Jira, Linear, GitHub, or your own tooling. Base URL: `https://story-points.danielrose7.workers.dev` **Authentication: there is none, by design.** No OAuth, no API keys, no signup — and none are coming. The room slug (plus the optional room code below) is the entire credential, scoped to exactly one room and shared the same way the room itself is. That's a philosophy, not an omission: key machinery is accounts by the back door, tokens parked in scripts and CI logs leak, and the zero-ceremony surface is what lets you point your own agent at a room with nothing but the URL it was invited with. **Protected rooms:** a host can require a 6-character room code (off by default). When enabled, `queue` and `export` need it — `?code=ABC123` or an `X-Room-Code: ABC123` header — and return `401` without it. Invite links carry the code (`/room/?code=ABC123`). Code checks are rate-limited: ten wrong guesses locks checking for ~15 minutes. ## Import tickets into the queue `POST /api/room//queue` Plain text (one story per line) or JSON. Appends by default; `?mode=replace` swaps the whole queue. Connected clients see imports live. ```sh # Plain text printf 'Login flow rework\nRate limiter for API\n' | \ curl -X POST --data-binary @- \ https://story-points.danielrose7.workers.dev/api/room//queue # JSON curl -X POST -H 'Content-Type: application/json' \ -d '{"items":["Login flow rework","Rate limiter"]}' \ 'https://story-points.danielrose7.workers.dev/api/room//queue?mode=replace' ``` Response: `{"queued": }`. Limits: 100 items, 500 chars each. Returns `403` if the room's host has switched the ticket queue off, `400` for unparseable bodies. ## Export the session `GET /api/room//export` — JSON: room name, current queue, and round history (story, ISO end time, duration in seconds, deck-ordered vote counts). `GET /api/room//export?format=csv` — the history as CSV (`story,ended_at,duration_seconds,votes`). ```sh curl https://story-points.danielrose7.workers.dev/api/room//export ``` Returns `404` for rooms that don't exist yet. ## Peek at a room `GET /api/room//peek` — `{"exists": bool, "name"?: string, "theme"?: string}`. Cheap existence check; doesn't create the room. ## Realtime The app itself runs over a WebSocket at `/api/room//ws?u=` with JSON messages (join, vote, reveal, clear, story, queue, settings, …). It's an internal protocol — no compatibility promises — but it's plain JSON if you want to script a bot; see `shared/types.ts` in the [repo](https://github.com/danielrose7/story-points) for message shapes. ## Agent setup One step for any agent — see the [Agent setup guide](/docs/agent-setup): ``` Fetch https://story-points.danielrose7.workers.dev/agent-setup/prompt.md and follow it ``` Or point your coding agent or MCP tool at [`/llms.txt`](https://story-points.danielrose7.workers.dev/llms.txt) — it indexes these docs in Markdown. Every docs page also serves a raw Markdown twin at the same URL with `.md` appended (e.g. `/docs/api.md`), and [`/llms-full.txt`](https://story-points.danielrose7.workers.dev/llms-full.txt) bundles all pages in one fetch. A typical agent workflow: ```sh # 1. Learn the surface curl https://story-points.danielrose7.workers.dev/llms.txt # 2. Import the backlog you were asked to estimate your-tracker-cli list --sprint 42 | curl -X POST --data-binary @- \ https://story-points.danielrose7.workers.dev/api/room//queue # 3. After the session, collect results and write them back curl https://story-points.danielrose7.workers.dev/api/room//export ``` --- Source: https://story-points.danielrose7.workers.dev/docs/agent-setup.md # Agent setup Set up your agent to import backlogs, follow estimation sessions, and export results. One step, any agent: ``` Fetch https://story-points.danielrose7.workers.dev/agent-setup/prompt.md and follow it ``` Paste that into Claude Code, Cursor, Windsurf, Copilot, or any agent that can fetch a URL. The prompt teaches it the whole surface — no install, no keys. ## What your agent can do afterwards - **Import a backlog** — pipe stories from your tracker's CLI (Jira, Linear, GitHub, a text file) into a room's "Up next" queue. - **Follow a session** — check what's queued and what's been estimated. - **Export results** — pull the round history (stories, vote spreads, durations) as JSON or CSV and write story points back to your tracker with your own tooling. Your tracker credentials never touch Story Points: the agent bridges locally, using CLIs and MCP tools you already have. ## Key concepts - **The room slug is the capability.** There are no accounts or API keys; anyone with the room URL can use its API — same trust model as the app. - **Two endpoints do everything.** `POST /api/room//queue` imports, `GET /api/room//export` exports. Details in the [API docs](/docs/api). - **Markdown-native docs.** Agents can read [`/llms.txt`](/llms.txt) (index), [`/llms-full.txt`](/llms-full.txt) (everything in one fetch), or any docs page with `.md` appended. ## In the app Rooms include ready-made prompts (in the **Up next** and **Round history** panels): pick your tracker — Linear, Jira, GitHub, or other — optionally peg the import to a known list (a Linear view, Jira JQL, a GitHub milestone), and copy a prompt pre-filled with the room URL. Your tracker and scope picks are remembered on your device. Hosts can hide these prompts in **Room settings → Features**. ## Per-agent notes - **Claude Code** — paste the one-liner above, or add it to your project's `CLAUDE.md` so every session knows the surface. - **Cursor / Windsurf / Copilot** — paste the one-liner in chat, or add the fetched contents to your rules/instructions file. - **Anything else** — if it can `curl`, it can integrate; hand it [/docs/api.md](/docs/api.md). ## Troubleshooting Things an agent (or you) can check when a workflow misbehaves: - **Linear custom views** — Linear's API and MCP can filter by project, cycle, team, label, or search, but **custom views are UI-only**. Don't point an agent at a view URL; either give it an equivalent filter, or use the view's ⋯ menu → **Export issues as CSV** and import the file straight into the room's queue (📎 Import CSV — ticket links come along for free). - **`401` on `queue`/`export`** — the room requires a code. Ask the user for it (it's in their invite link as `?code=`), then send it as an `X-Room-Code` header. Don't guess: checks lock out after ten misses. - **`403` on `POST /queue`** — the room's host switched the ticket queue off in **Room settings → Features**. Ask them to re-enable it. - **`404` on `/export`** — the room doesn't exist yet; rooms are created the first time someone joins. `GET /api/room//peek` is the cheap check. - **Empty `history` in the export** — rounds are only recorded when someone clicks **Next ticket →** after a reveal (Re-vote records nothing), and the host may have round history switched off. - **`400` on JSON imports** — send `Content-Type: application/json` with a body shaped `{"items": ["…"]}`. Without that header the body is treated as plain text, one story per line. - **Import seemed to vanish** — queues cap at 100 items × 500 chars each; overflow is trimmed. The response `{"queued": N}` is the source of truth. - **Nothing updates live** — connected clients update over WebSocket on every import; a page that's been asleep reconnects with fresh state within a few seconds. Refreshing always resyncs (and reclaims your seat). - **Sanity-check from a shell:** ```sh curl -i https://story-points.danielrose7.workers.dev/api/room//peek printf 'test ticket\n' | curl -i -X POST --data-binary @- \ https://story-points.danielrose7.workers.dev/api/room//queue ``` --- Source: https://story-points.danielrose7.workers.dev/docs/self-host.md # Self-host ("eject") > Story Points is MIT-licensed and designed to be ejected: if the hosted > app ever goes away, goes bad, or your company wants its own, three > commands put an identical copy on your own Cloudflare account — free > plan included. That's the answer to "what's the catch": the license > removes the ability for there to be one. ## What you need - A free [Cloudflare account](https://dash.cloudflare.com/sign-up) — the whole app fits in the Workers **free plan** (Durable Objects with SQLite storage included). - Node 20+ and git. "Free" is honest at the scale self-hosting is for: you and your teams, estimating a few sessions a week — that's a rounding error against the free-plan quotas. If your copy somehow ends up serving the whole world, you'll graduate to the Workers paid plan (~$5/mo) — a good problem, and still cheap. ## The three commands ```sh git clone https://github.com/danielrose7/story-points cd story-points && npm install npm run deploy # runs `wrangler deploy`; prompts `wrangler login` once ``` That's it. Wrangler prints your copy's URL (`story-points..workers.dev`) — rooms, themes, the API, docs, and llms.txt all work identically. Your rooms live in **your** Durable Objects; nothing phones home. ## The one honest caveat Rooms are Cloudflare [Durable Objects](https://developers.cloudflare.com/durable-objects/) — the single non-portable piece. "Eject" means *to your own Cloudflare account*, not to an arbitrary box. There is deliberately no Node/Postgres/Redis abstraction layer: the DO free tier is the landing zone, and keeping the codebase small is what keeps it forkable. ## Make it yours - **Own domain**: add a custom domain to the Worker, then update the baked absolute URLs: the OG tags in `index.html`, `SITE` in `scripts/build-docs.mjs`, and the JSON-LD. - **Own themes/decks**: a theme is a `--sp-*` token block in `src/styles.css`; decks and presets are data in `shared/types.ts`. - **Development**: `npm run dev` runs the full stack (Vite + Worker + DOs) locally. ## Staying current Your fork is yours — there's no auto-update and no telemetry. `git pull && npm run deploy` picks up upstream changes whenever you like. Questions or improvements? [Open an issue](https://github.com/danielrose7/story-points/issues) — or don't; the [MIT license](https://github.com/danielrose7/story-points/blob/main/LICENSE) means you never need permission.