Invite-only retro boards for teams that want the truth without the ceremony.
Spill. it. out. Turn honest async reflection into decisions your team can actually act on.
Spill. is a board-first retrospective app that lets teams write privately, reveal together, vote, turn the highest-signal pain points into actions, and keep a searchable history of what keeps coming back.
- Private first: drafts stay private until reveal.
- Real collaboration: participants, authors, ready state, votes, and live board updates are backed by the API.
- Invite-only access: email-backed ACLs decide who can see and mutate a board.
- Actions, not theatre: top-voted friction turns into action candidates the team can confirm, reject, edit, and complete.
- Expressive by default: GIF search and card media are part of the retro, not decorative afterthoughts.
The repo/package name is spillio.
Spill. is in a stable MVP shape:
- end-to-end retro flow works
- boards persist in Postgres
- cards, votes, ready state, participants, actions, summaries, deliveries, and history are backed by the Rust API
- board updates sync through WebSockets, with reconnect and polling fallback
- production identity is header/proxy based, suitable for Google IAP or a trusted auth proxy
- email identity controls board ownership, visibility, invitations, and ACLs
- boards are invite-only
- local mode is available for development without a real auth provider
AI and external delivery integrations are intentionally still placeholder seams where the product needs provider-specific wiring.
Spill. is not an "AI runs your retro" tool. The core product is the board. AI can help organize, summarize, or propose follow-up, but humans own the retro content and decisions.
-
Writing
- Participants add private cards.
- Other participants cannot read your drafts until reveal.
- Participants mark ready when done.
-
Discussion
- The board reveals cards for team discussion.
- Cards can be edited, moved, grouped, and annotated.
-
Voting
- Participants vote on what deserves action.
- Vote limits are board settings.
-
Action discussion
- Top-voted items are converted into action candidates.
- The team confirms, rejects, edits, and completes actions.
-
Wrapped recap
- Completed boards stay available from history.
- Recurring tags and open actions are surfaced across boards.
- standard and custom templates
- private draft visibility before reveal
- real participants and card authors
- GIF search and GIF-backed cards
- manual card grouping
- ready state in async phases
- voting and vote counts
- action lifecycle
- meeting notes and AI artifact records
- delivery records for exports/integrations
- board history with active/completed boards
Production identity is expected to come from a trusted upstream auth layer such as Google IAP, oauth2-proxy, or an equivalent reverse proxy.
The web app reads upstream identity headers and sends normalized identity to the Rust API. Email is the ownership key:
- display name is user-facing only
- email defines board ownership and visibility
- board creators become host grants
- invitees become member grants
- uninvited users see access denied
- every board mutation is authorized against the participant/grant model
Useful web env vars:
SPILLIO_AUTH_MODE=proxy
SPILLIO_AUTH_EMAIL_HEADER=x-goog-authenticated-user-email
SPILLIO_AUTH_NAME_HEADER=x-goog-authenticated-user-name
SPILLIO_API_URL=http://api:4000
SPILLIO_BROWSER_API_URL=https://your-public-api.example.com
NEXT_PUBLIC_SPILLIO_API_URL=https://your-public-api.example.comFor local development, SPILLIO_AUTH_MODE=local enables a self-claimed email
and display name form. Local mode is not secure and should not be used as a
production auth boundary.
- Web: Next.js app in
apps/web - API: Rust Axum API/WebSocket service in
services/api - Domain: Rust crates under
services/api/crates - Database: Postgres with SQLx migrations
- Companion: the single-binary
spillCLI incli/(board access + ingest)
The Rust API owns durable board state, visibility rules, phase transitions, participants, grants, votes, and WebSocket events. The Next.js app renders the product and calls the API through typed JSON contracts.
Prerequisites:
- Node.js 22
- pnpm
- Rust toolchain
- Docker, for local Postgres
pnpm install
cp .env.example .env
pnpm db:up
pnpm db:migrateRun the API:
set -a; source .env; set +a
cargo run -p spillio-api -- serveRun the web app:
pnpm dev:webDefault local URLs:
- web:
http://127.0.0.1:3000 - API:
http://127.0.0.1:4000 - API health:
http://127.0.0.1:4000/health
GIF search requires SPILLIO_KLIPY_API_KEY. Without it, the API returns a
degraded empty GIF response instead of failing the board.
The completed-retro page exposes an AI wrap-up summary. When a retro
is completed, the API auto-creates a summary AI artifact and runs it
in the background through the pluggable AI provider abstraction in
services/api/src/ai_provider. The shipped implementation is a
gateway provider that POSTs the prompt to SPILLIO_AI_GATEWAY_URL
(a fully-formed endpoint) as {prompt_text: "…"} and reads
{response: "…"} back. The wrap-up tile reads the artifact off
the board payload and re-renders as it advances through
pending → running → succeeded / failed, driven by the
existing board WebSocket. With the env var unset (local dev), the
auto-trigger is skipped and the tile stays hidden — the rest of the
API is unaffected.
docker compose --profile app up --buildThe compose profile runs Postgres, migrations, the Rust API, and the web app. For a real deployment, run migrations before serving traffic.
pnpm check
pnpm buildpnpm check runs:
- web TypeScript checks
- companion package tests
- Rust workspace tests against Postgres
API:
DATABASE_URLSPILLIO_API_ADDRSPILLIO_KLIPY_API_KEYRUST_LOGSPILLIO_AI_PROVIDER(optional; defaults togatewaywhen a gateway URL is set)SPILLIO_AI_GATEWAY_URL(optional; fully-formed URL of the AI gateway endpoint)
Web:
SPILLIO_API_URLNEXT_PUBLIC_SPILLIO_API_URLSPILLIO_AUTH_MODESPILLIO_AUTH_EMAIL_HEADERSPILLIO_AUTH_NAME_HEADER
docs/product-overview.mddocs/api-contracts.mddocs/deployment.mddocs/designer-mock-brief.mddocs/mvp-product-doc.mddocs/tech-stack-design.mddocs/implementation-plan.mddocs/companions.mdmock/index.html

