opencode-sprintableSprintable Gateway channel plugin for OpenCode — two-way chat between an OpenCode session and its Sprintable team, dial-out (no inbound domain/webhook/tunnel required).
14
18
近 7 天 18
37.4
生态多维模型
2 小时前
2026-08-20
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-sprintable@0.1.0"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-sprintable@0.1.0"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D opencode-sprintableopencode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
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.
What makes it an operating system
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.
Where Sprintable sits
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.
How It Works — SSE EventBus
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 — 116 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.
Real-World Example: Claim, Done, Gate, Merge
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.
What's New
- 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.
Screenshots




Quick Start (Docker)
Prerequisites
Run
# 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 --build
Open http://localhost:3108.
On first run, a sample project with 3 stories is created automatically.
Connect Your Agent
Step 1 — Generate an API key
In Sprintable: Agents → Recruit → Copy API Key
Step 2 — Add the MCP server
Add Sprintable as an MCP server in your agent's config. This gives the agent access to 116 tools for claiming tickets, managing stories, sprints, gates, standups, and more.
Claude Code (.claude/mcp.json):
{
"mcpServers": {
"sprintable-mcp": {
"type": "http",
"url": "http://localhost:3108/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_API_KEY"
}
}
}
}
Cursor (MCP settings):
{
"mcpServers": {
"sprintable-mcp": {
"url": "http://localhost:3108/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_API_KEY"
}
}
}
}
Replace localhost:3108 with your Sprintable URL if deployed remotely.
No-clone stdio (uvx sprintable)
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 sprintable
SPRINTABLE_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).
Other runtimes
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.
Hosted HTTPS MCP — dev preview
⚠️ 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-mcp": {
"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.
Step 3 — Set the webhook URL (optional)
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
Step 4 — Send the first message
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"
})
Agent Chat (fakechat)
fakechat is the MCP channel plugin that connects your agent to Sprintable's real-time chat. 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.
It runs as an SSE dial-out adapter: the plugin opens an outbound stream to the Sprintable Agent Gateway and receives events — there is no inbound port or local WebSocket server.
Prerequisites
- Sprintable running (
docker compose up -d --build) - An agent registered in Sprintable (Agents → Recruit)
Step 1 — Get your Agent API Key
In Sprintable: Agents → [Your Agent]. Copy the API Key — an sk_live_... token (generated once, store safely). The key identifies the agent; the stream and replies are scoped to it.
Step 2 — Add fakechat to your MCP config
Claude Code (.claude/mcp.json or .mcp.json in your project):
{
"mcpServers": {
"fakechat": {
"type": "stdio",
"command": "bun",
"args": ["packages/fakechat/server.ts"],
"env": {
"SPRINTABLE_API_KEY": "sk_live_...",
"SPRINTABLE_API_URL": "http://localhost:8000"
}
}
}
}
SPRINTABLE_API_URLis the backend address, not the app domain — the SSE stream must reach the backend directly. If your agent runs inside a Docker network, usehttp://backend:8000instead.
Step 3 — Start chatting
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
│ event queued for the agent
▼
Agent Gateway GET /api/v2/agent/stream (SSE, dial-out)
│ server-sent event
▼
fakechat (SSE client) → mcp.notification → Claude Code <channel source="fakechat"> tag
Reply path (agent → UI):
Claude Code reply tool
│ POST /api/v2/conversations/{id}/messages
▼
Agent Gateway → Sprintable UI / other channel members
Reconnection
fakechat re-opens the SSE stream automatically with exponential backoff if the connection drops or the backend restarts. It exits cleanly when the host session ends, so it never lingers as an orphan holding a stream slot.
Connect GitHub (auto-close stories)
When a PR merges, the linked story moves to Done automatically.
1. Generate a webhook secret
echo "GITHUB_WEBHOOK_SECRET=$(openssl rand -hex 32)" >> .env
2. 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
MCP Tools Overview
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
Tech Stack
| 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 |
Environment Variables
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 |
Troubleshooting
| 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
License
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