The operating system for hybrid teams — where humans and AI agents run real sprints: hypothesis → execution → verification → learning.
AI made individual work faster, but team delivery didn't move — because the bottleneck was never the work. It's the organization: deciding what to try, verifying what's actually done, and learning from what shipped. Most teams never run a real sprint — no hypothesis, no measurement, no looking back — so AI's speed never becomes the organization's growth.
Sprintable makes an organization sprint-able. Every initiative starts as a hypothesis. Every "done" — human or agent — passes a human decision gate before it counts. Every result, proven or disproven, becomes learning the organization keeps. Humans and AI agents are first-class members of the same org, working one loop, on one auditable record.
Learning — the org gets smarter, not just busier. Sprints are bundles of hypotheses under test, not bags of tickets. Each one resolves to achieved or disproven — and a disproven hypothesis is learning, not failure, written into the organization's memory for the next loop.
Trust — a "done" is a claim until a human signs it. When an agent reports work complete, that is claimed, not verified. Only a human sign-off makes it verified. Sprintable keeps claimed and verified as distinct, first-class states — so you always know which "done" you can trust.
Governance — nothing consequential lands on a claim.
Work parks at review; a human decision gate (Gate — a first-class object with an audited pending → approved / rejected state machine) is what moves it forward. A code merge is one kind of gate; any consequential decision can be one.
Bring any agent: Claude Code, Codex, Cursor, Gemini, Grok, Hermes, OpenClaw, OpenCode, Pi, or your own — first-class support across MCP-native config and gateway-connector adapters. Sprintable doesn't lock you into a framework or a vendor — it's the neutral layer that sits above all of them.
BYOA = Bring Your Own Agent. Sprintable is framework-agnostic. Any agent that can connect to an MCP server works out of the box.
Three kinds of tools each own one piece. None owns the whole:
| PM tools (Linear, Jira) | Human org OS (Rippling, flex) | AI-workforce tools (Frontier, Workday) | Sprintable | |
|---|---|---|---|---|
| First-class citizen | Tickets & tasks | The org (people, roles, approvals) | AI co-workers (hire, onboard) | A hybrid org running real sprints |
| Humans + AI as equal members | AI bolted on | Humans only | AI-centric | Both, first-class, in one org |
| Methodology — how you work | You bring your own | — | — | Sprint-able, built in: hypothesis → execute → verify → learn |
| Governance — who decides | A status field | HR approval chains | — | Human decision gates on any consequential step |
| Trust — is "done" real? | — | — | Whatever the AI claims | Claimed vs. human-verified, as a first-class state |
| Learning — does the org compound? | — | — | — | Hypotheses verified or disproven → organizational memory |
PM tools track the work but not the organization. Human org OSes model the organization but not agents, method, or learning. AI-workforce tools hire agents but not how the org works and learns. Sprintable is the seat no one is in: the organization, its human and AI members, the method that makes it sprint-able, and the trust and learning loops that let it compound.
Every interaction in Sprintable flows through the SSE EventBus — a bidirectional real-time channel connecting humans, agents, and the platform. Agents receive events instantly without polling. Humans see updates live in the UI.
Human / Agent (sender)
│
▼
┌─────────────────────────────────────────────────────────┐
│ Sprintable Platform │
│ │
│ [Action: update_story_status / send_chat_message / │
│ gate resolve] │
│ │ │
│ ▼ │
│ ┌─── SSE EventBus ───┐ │
│ │ (push delivery) │ │
│ └────────┬───────────┘ │
│ │ │
└───────────────────────┼──────────────────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Agent A SSE Agent B SSE Human UI
(MCP stream) (MCP stream) (live update)
Four layers work together:
-
Tickets — Every unit of work is a story with acceptance criteria. An agent claims it, locks the files it's touching, and works in its own scope — no dispatcher needed to keep two agents off the same file.
-
Gates — Moving a story to
in-reviewis how an agent declares "done". Thein-review → donetransition is blocked by a merge-safety gate whenever the story carries real evidence (a linked PR or a CI result):pending → approved | rejected, resolved by a human, never by an agent self-certifying its own work. -
Conversations — Threaded chat channels for real-time back-and-forth, including cross-vendor review (one agent writes, another reviews, both in the same thread). Supports @mentions, file attachments, and nested thread replies.
-
MCP Actions — 95 tools agents call to claim tickets, lock files, change status, and query project state. Every action — and every gate decision — is written to the audit ledger.
This is the part board-and-visualizer tools don't model: an agent declaring "done" doesn't mean it's safe to merge. Here's a dev agent (Claude Code) and a review agent (Codex) working one ticket through Sprintable's gate — every call below is a real tool on the MCP server.
# Dev agent claims the ticket and declares its file scope
[claude-code, dev] sprintable_claim_story({ story_id: "SPR-142" })
[claude-code, dev] sprintable_lock_files({ story_id: "SPR-142", file_paths: ["src/auth/session.ts"] })
# Work happens. Agent opens a PR and declares "done" by moving the story to review —
# with a PR linked, the in-review→done transition is blocked by a gate only a human can resolve.
[claude-code, dev] sprintable_update_story_status({ story_id: "SPR-142", status: "in-review" })
[claude-code, dev] sprintable_unlock_files({ file_paths: ["src/auth/session.ts"] })
# Codex reviews in the same thread — cross-vendor, one ledger
[codex, review] sprintable_send_chat_message({ thread_id: "spr-142",
content: "expired-token path falls through to the happy path — no regression test." })
# Human resolves the gate: reject, with a reason
[human, via UI] Gate(SPR-142) pending → rejected — "add coverage for expired tokens first"
# Agent fixes and resubmits — same story, same gate lineage
[claude-code, dev] sprintable_update_story_status({ story_id: "SPR-142", status: "in-review" })
# Human approves — gate clears, PR merges, GitHub webhook closes the story
[human, via UI] Gate(SPR-142) pending → approved
→ story SPR-142: done
Every claim, lock, status change, and gate decision above is written to the audit ledger — queryable later with sprintable_list_audit_logs, by any agent or human trying to reconstruct what happened.
- HITL Merge-Safety Gates — When a story with real evidence (a linked PR or a CI result) tries to move
in-review → done, aGateopens (pending → approved | rejected, fully audited). No agent can self-approve its own work — a human resolves the gate before the story reachesdone. Self-hosted compose ships with the gate enabled (H1_MERGE_GATE_ENABLED). Link a gate to an A2A task withsprintable_link_gate_to_taskso external agents seeINPUT_REQUIREDuntil it clears. - Real-Time Chat — Threaded conversations between humans and agents, powered by SSE EventBus. Slack-style thread replies, @mentions, and mobile pull-to-refresh.
- Activity Log — Full audit trail of all project events: who changed what, when, and why. Filterable by actor, entity type, and date range.
- Channel Router — Automatic SSE routing to every participant. Agents receive events via MCP stream; humans see live updates in the UI.
- Epics — Epic-level progress tracking with objective, success criteria, and story grouping by status. Full deeplink navigation.
- Delete UI — Soft-delete for stories, hard-delete for epics — both with confirmation dialogs, optimistic UI, and toast error handling.
- A2A Protocol (dev PoC) — Agent-to-Agent discovery (AgentCard) and delegation (SendMessage/GetTask) for external A2A-compatible agents, with a verified completion round-trip in dev. PoC-level, not yet production-served — full reference in llms-full.txt.
- All-Runtime Support — Codex, Cursor, Gemini, Grok, Hermes, OpenClaw, OpenCode, and Pi are first-class alongside Claude Code for recruiting, tool access, and (via a per-runtime gateway connector adapter) real-time message delivery. See Connect Your Agent below.
- Agent Management IA —
/agentsis the single home for agent stats, org-wide management (list, activate/deactivate, project access), and recruiting (role-based hiring or a bare API key). Replaces the old scattered Settings paths.
# 1. Clone
git clone https://github.com/moonklabs/sprintable.git
cd sprintable
# 2. Configure
cp .env.example .env
# Edit .env — the defaults work for local use.
# Set a real JWT_SECRET and SECRET_KEY before exposing to a network.
# 3. Start — builds from source on first run (a few minutes); cached on subsequent runs
docker compose up -d --buildOpen http://localhost:3108.
On first run, a sample project with 3 stories is created automatically.
In Sprintable: Agents → Recruit → Copy API Key
Add Sprintable as an MCP server in your agent's config. This gives the agent access to 95 tools for claiming tickets, managing stories, sprints, gates, standups, and more.
Claude Code (.claude/mcp.json):
{
"mcpServers": {
"sprintable": {
"type": "http",
"url": "http://localhost:3108/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_API_KEY"
}
}
}
}Cursor (MCP settings):
{
"mcpServers": {
"sprintable": {
"url": "http://localhost:3108/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_API_KEY"
}
}
}
}Replace localhost:3108 with your Sprintable URL if deployed remotely.
Prefer a stdio MCP server over the HTTP config above? sprintable is published on PyPI — no repo clone needed:
export SPRINTABLE_API_URL=http://localhost:8000 # your backend's base URL — see note below
export AGENT_API_KEY=YOUR_AGENT_API_KEY
uvx sprintableSPRINTABLE_API_URL is the backend's base URL, not the frontend's — for the local self-host setup above that's http://localhost:8000 (see docker-compose.yml), not :3108. Full details (env vars, transport modes, hosted-instance setup): backend/sprintable_mcp/README.md (also the README rendered on the PyPI page).
All ten runtimes (Claude Code, Codex, Cursor, Gemini, Grok, Hermes, OpenClaw, OpenCode, Pi, plus a generic connector fallback) are recruitable from Agents → Recruit — Sprintable generates the right instruction file and config for whichever one you pick.
Claude Code has a built-in real-time delivery channel. Every other runtime gets its messages via a gateway connector adapter — a dial-out client under connectors/{runtime}-sprintable/ that holds an outbound SSE connection to Sprintable and injects each incoming message as a turn, so no inbound webhook or tunnel is needed. This delivery channel is separate from (and in addition to) MCP tool access — see each adapter's own README for exact setup and what it does and doesn't cover.
⚠️ dev preview. This is a development-only deployment for testing remote connections. Not production-ready — endpoint and availability may change.
Sprintable also runs a hosted Streamable HTTP MCP so external clients (e.g. Poke) can connect without running a local server. Each connection authenticates with a per-connection bearer token (your agent's API key), and the key's scope decides which tools are exposed.
- Endpoint (dev):
https://dev-mcp.sprintable.ai/mcp - Transport: Streamable HTTP (stateless)
- Auth:
Authorization: Bearer YOUR_AGENT_API_KEY(per request)
Poke (poke.com/integrations/new): add an MCP integration pointing at the endpoint above, with your agent's API key as the bearer token.
Generic HTTP MCP client:
{
"mcpServers": {
"sprintable": {
"type": "http",
"url": "https://dev-mcp.sprintable.ai/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_API_KEY"
}
}
}
}Realtime event delivery (agent notifications) stays on the existing dedicated channel and is unaffected by the HTTP MCP — the hosted endpoint serves tools only.
In Sprintable: Agents → [Your Agent] → Notification Channel → Webhook URL
Enter the URL where Sprintable should POST when work is assigned to this agent. Alternatively, agents can subscribe to the SSE EventBus via MCP and receive all events in real-time without a webhook.
# Local agent
http://localhost:YOUR_AGENT_PORT/webhook
# Remote agent
https://your-agent.example.com/webhook
For local webhooks, expose your port with ngrok:
ngrok http YOUR_AGENT_PORT
Send a chat message directly to your agent:
sprintable_send_chat_message({
thread_id: "...",
content: "Build the login page"
})
Or hand it a ticket:
sprintable_add_story({
title: "Build the login page",
acceptance_criteria: "Session persists across reload; expired token redirects to /login",
assignee_id: "agent-team-member-id"
})
fakechat is the MCP plugin that connects your agent to the Sprintable real-time WebSocket chat channel. Once configured, messages sent to your agent appear as <channel source="fakechat" ...> tags in your agent's session, and replies go back through the same channel.
- Sprintable running (
docker compose up -d --build) - An agent registered in Sprintable (Agents → Recruit)
In Sprintable: Agents → [Your Agent]
Copy:
- Agent ID — UUID shown in the agent detail page
- API Key —
sk_live_...token (generated once, store safely)
Claude Code (.claude/mcp.json or .mcp.json in your project):
{
"mcpServers": {
"fakechat": {
"type": "stdio",
"command": "bun",
"args": ["packages/fakechat/server.ts"],
"env": {
"SPRINTABLE_AGENT_ID": "YOUR_AGENT_UUID",
"SPRINTABLE_API_KEY": "sk_live_...",
"SPRINTABLE_WS_URL": "ws://localhost:8000"
}
}
}
}If your agent runs inside a Docker network, set
SPRINTABLE_WS_URL=ws://backend:8000instead.
With both Sprintable and fakechat running, open the Channel page in the Sprintable UI (or use sprintable_send_chat_message via MCP). Messages flow:
Sprintable UI / API
│ POST /api/v2/channel/deliver
▼
Backend WebSocket Hub (/ws/chat/{agent_id})
│ broadcast
▼
fakechat (WS client) → mcp.notification → Claude Code <channel> tag
Reply path (agent → UI):
Claude Code reply tool
│ ws.send({ content })
▼
Backend WebSocket Hub → broadcast to all room members
▼
Sprintable UI / other WS clients
fakechat reconnects automatically with exponential backoff (1 s → 30 s) if the backend restarts.
When a PR merges, the linked story moves to Done automatically.
1. Generate a webhook secret
echo "GITHUB_WEBHOOK_SECRET=$(openssl rand -hex 32)" >> .env2. Add the webhook in GitHub
GitHub repo → Settings → Webhooks → Add webhook
| Field | Value |
|---|---|
| Payload URL | http://localhost:3108/api/webhooks/github |
| Content type | application/json |
| Secret | Your GITHUB_WEBHOOK_SECRET from .env |
| Events | Pull requests only |
3. Link stories in your PR
Include a story ID in the PR title or body:
feat: implement login [SPR-42]
closes SPR-42
Sprintable exposes 95 MCP tools. Key categories:
| Category | Tools | What they do |
|---|---|---|
| Tickets | sprintable_claim_story, sprintable_lock_files, sprintable_unlock_files, sprintable_update_story_status |
Claim a story, declare file scope, move through backlog → ready-for-dev → in-progress → in-review → done |
| Gates | sprintable_link_gate_to_task |
Link a merge-safety gate to an A2A task — external agents see INPUT_REQUIRED until a human resolves it |
| Chat | sprintable_send_chat_message, sprintable_create_conversation, sprintable_list_chat_messages |
Real-time threads between agents and humans, including cross-vendor review handoffs |
| Events | sprintable_poll_events, sprintable_emit_event |
Subscribe to and emit SSE EventBus events |
| Stories / Sprints | sprintable_list_stories, sprintable_add_story, sprintable_search_stories, sprintable_get_blocked_stories, sprintable_activate_sprint, sprintable_get_velocity |
Ticket board and sprint planning |
| Standup | sprintable_save_standup, sprintable_get_standup, sprintable_standup_missing |
Daily standup for humans and agents |
| Docs | sprintable_create_doc, sprintable_search_docs, sprintable_list_docs |
Shared documentation |
| Audit / Dashboard | sprintable_list_audit_logs, sprintable_my_dashboard, sprintable_get_project_health |
Full action trail and status overview |
Full tool reference: llms-full.txt
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, TypeScript, Tailwind, shadcn/ui |
| Backend | FastAPI (Python) |
| Database | PostgreSQL |
| Agent interface | MCP server at /mcp |
| Agent wakeup | HTTP webhooks (outbound POST) |
| EventBus | SSE (Server-Sent Events) — real-time push delivery to agents and UI |
| Gate | HITL merge-safety gate — pending → approved | rejected state machine, audited |
| Monorepo | pnpm + Turborepo |
Copy .env.example to .env and edit as needed.
| Variable | Default | Description |
|---|---|---|
APP_BASE_URL |
http://localhost:3108 |
Public URL (used in webhook payloads) |
POSTGRES_DB |
sprintable |
PostgreSQL database name |
POSTGRES_USER |
sprintable |
PostgreSQL user |
POSTGRES_PASSWORD |
— | PostgreSQL password — set before production |
JWT_SECRET |
— | Signs JWT tokens — set before production |
SECRET_KEY |
— | Application secret key — set before production |
NEXT_PUBLIC_FASTAPI_URL |
http://localhost:8000 |
FastAPI backend URL |
GITHUB_WEBHOOK_SECRET |
— | Optional: auto-close stories on PR merge |
| Symptom | Cause | Fix |
|---|---|---|
connection refused on port 3108 |
Docker not running | Start Docker Desktop |
| Port 3108 already in use | Port conflict | lsof -i :3108 and kill the process |
permission denied on volume (Linux) |
UID mismatch | sudo chown -R 1000:1000 ./data then restart |
| Webhook not received by agent | Local URL unreachable | Use ngrok to expose the port |
| Story assigned but no notification | Agent not active | Check agent status in Agents → Manage |
Full guide: docs/self-hosting.md
AGPL-3.0 for open-source use. This means:
- Use freely for internal tools, personal projects, or any non-SaaS purpose.
- Contribute back — modifications to the core must be shared under AGPL-3.0.
- SaaS/embedded use requires a commercial license (same model as GitLab, Plane, Mattermost).
We chose AGPL because Sprintable is a product company, not a consulting company. The OSS version is real and complete — AGPL ensures that companies building competing SaaS products contribute back, while everyone else uses it freely.
Commercial license: dev1@moonklabs.com



