Content
<p align="center">
<img width="372" src="internal/httpapi/web/githublogo.png" alt="scrumboy logo" />
<br />
<img src="https://img.shields.io/badge/version-v3.18.24-blue" alt="version" />
<img src="https://img.shields.io/badge/license-AGPL--v3-orange" alt="license" />
<img src="https://img.shields.io/badge/i18n-23%20languages-yellow" alt="i18n" />
<a href="https://github.com/markrai/scrumboy/actions/workflows/ci.yml">
<img src="https://img.shields.io/github/actions/workflow/status/markrai/scrumboy/ci.yml?branch=main&label=tests" alt="tests" />
</a>
</p>
#### Self-hosted project management & issue-tracking solution + instant shareable & customizable boards + realtime collaboration, automation, API access and MCP-compatible client support
<img width="2975" height="1078" alt="image" src="internal/httpapi/web/github_preview.jpg" />
## Table of contents
- [Quick Start](#quick-start)
- [Run the official Docker image](#run-the-official-docker-image)
- [Run the Windows executable](#run-the-windows-executable)
- [Build locally from source](#build-locally-from-source)
- [Run from source](#run-from-source)
- [Optional Configuration](#optional-configuration)
- [Environment variables](#environment-variables)
- [Encryption key (optional)](#encryption-key-optional)
- [OIDC / SSO login (optional)](#oidc--sso-login-optional)
- [TLS / HTTPS (optional)](#tls--https-optional)
- [PWA / Web Push (optional)](#pwa--web-push-optional)
- [Frontend build note](#frontend-build-note)
- [Why Scrumboy?](#why-scrumboy)
- [Who is this for?](#who-is-this-for)
- [Modes](#modes)
- [Features](#features)
- [Integrations & API Access](#integrations--api-access)
- [MCP (JSON-RPC) for AI agents](#mcp-json-rpc-for-ai-agents)
- [Webhooks (outbound HTTP)](#webhooks-outbound-http)
- [Config](#config)
- [Roles](#roles)
- [System roles (instance-wide)](#system-roles-instance-wide)
- [Project roles (per project)](#project-roles-per-project)
- [Export scope](#export-scope)
- [Import modes](#import-modes)
- [Code layout (reference)](#code-layout-reference)
- [Documentation](#documentation)
- [License and Contributions](#license-and-contributions)
## Quick Start
Runs in seconds. No setup required.
No `.env` file, TLS certificates, or encryption key are required to start the app.
### Run the official Docker image
Scrumboy is distributed as a container image on GitHub Container Registry:
`ghcr.io/markrai/scrumboy:latest`
**Docker run** (named volume for persistent SQLite data under `/data`):
```bash
docker run -d \
--name scrumboy \
-p 127.0.0.1:8080:8080 \
-v scrumboy-data:/data \
ghcr.io/markrai/scrumboy:latest
```
The image defaults to `DATA_DIR=/data` and `SQLITE_PATH=/data/app.db`. Mount a volume or host directory on `/data` so the database survives container recreation.
**Docker Compose** (minimal example; save as `docker-compose.yml`):
```yaml
services:
scrumboy:
image: ghcr.io/markrai/scrumboy:latest
container_name: scrumboy
ports:
- "127.0.0.1:8080:8080"
volumes:
- ./data:/data
restart: unless-stopped
```
```bash
docker compose up -d
```
Open [http://localhost:8080](http://localhost:8080).
### Run the Windows executable
Windows users can download `scrumboy-*-windows-amd64.exe` from [GitHub Releases](https://github.com/markrai/scrumboy/releases). The matching `.sha256` file is published beside it for checksum verification.
Put the exe in a dedicated writable folder before running it, for example `%USERPROFILE%\Scrumboy`. The exe starts a local Scrumboy server; open [http://localhost:8080](http://localhost:8080) after it starts.
Scrumboy creates runtime data under `./data` by default. The default SQLite database is `./data/app.db`, and SQLite may also create `app.db-wal` and `app.db-shm` while the server is running. The exe is single-file for distribution, but it is not "no runtime files ever."
Advanced users can set `DATA_DIR` to choose the runtime data directory and `BIND_ADDR` to choose the listen address or port.
### Build locally from source
To build from a local clone instead of pulling the published image:
```bash
docker compose up --build
```
The repository's `docker-compose.yml` uses `build: .` and maps `./data` to `/data`.
Open [http://localhost:8080](http://localhost:8080).
### Run from source
```bash
go run ./cmd/scrumboy
```
Open [http://localhost:8080](http://localhost:8080).
## Optional Configuration
### Environment variables
- The app does **not** automatically load `.env` files.
- On Linux/macOS, export variables manually (for example: `export SCRUMBOY_ENCRYPTION_KEY=...`).
- On Windows, `win_run_full.bat` and `win_run_anonymous.bat` manage `data/scrumboy.env` automatically for local convenience.
- Precedence on Windows is: existing process env var `SCRUMBOY_ENCRYPTION_KEY`, then `data/scrumboy.env`, then legacy root `scrumboy.env`.
- The canonical Windows-managed local file format is `SCRUMBOY_ENCRYPTION_KEY=<base64-32-byte-key>`.
- Windows helper scripts still accept legacy raw single-line key files for backward compatibility.
### Encryption key for 2FA/password reset
- `SCRUMBOY_ENCRYPTION_KEY` is **not** required for basic startup.
- It becomes required for encrypted auth/security features, including:
- 2FA
- Password reset flows
- If an existing database already has 2FA-enabled users, startup fails without this key.
- The key is part of the same backup/restore unit as `data/app.db`. Back them up together.
- Do **not** regenerate or replace the key casually after encrypted auth/security data exists, or you can break access to 2FA/password-reset data.
- If a bad key is configured before any encrypted auth/security data exists, Scrumboy may warn and continue with 2FA setup/password reset disabled until you configure a valid key.
Generate a key with: `openssl rand -base64 32`
Example for Docker Compose secret injection:
```yaml
services:
scrumboy:
environment:
- SCRUMBOY_ENCRYPTION_KEY=${SCRUMBOY_ENCRYPTION_KEY}
```
Example for systemd secret injection:
```ini
[Service]
Environment="SCRUMBOY_ENCRYPTION_KEY=REPLACE_WITH_BASE64_32_BYTE_KEY"
```
In both cases, the deployment manager is injecting the environment variable. Scrumboy itself does not auto-load these files.
### OIDC / SSO login (optional)
Scrumboy supports OpenID Connect for single sign-on with any standards-compliant provider (Keycloak, Authentik, Auth0, Entra ID, etc.). OIDC is enabled by setting all four required environment variables:
| Variable | Description |
|----------|-------------|
| `SCRUMBOY_OIDC_ISSUER` | Issuer URL (e.g. `https://auth.example.com/realms/main`) |
| `SCRUMBOY_OIDC_CLIENT_ID` | OAuth client ID |
| `SCRUMBOY_OIDC_CLIENT_SECRET` | Confidential client secret |
| `SCRUMBOY_OIDC_REDIRECT_URL` | Full callback URL registered at IdP (e.g. `https://scrumboy.example.com/api/auth/oidc/callback`) |
Optional:
| Variable | Description |
|----------|-------------|
| `SCRUMBOY_OIDC_LOCAL_AUTH_DISABLED` | Set to `true` to disable local password login when OIDC is configured (SSO-only mode) |
Local password authentication remains available by default alongside OIDC. After successful OIDC login, the user receives a standard Scrumboy session cookie. The IdP must return a verified email (`email_verified: true`). HTTPS is recommended when using OIDC to ensure session cookies are `Secure`.
See [`docs/oidc.md`](docs/oidc.md) for full setup details, constraints, and troubleshooting.
### TLS / HTTPS (optional)
- TLS is optional.
- HTTPS is enabled only when both `SCRUMBOY_TLS_CERT` and `SCRUMBOY_TLS_KEY` files exist.
- Otherwise, the server runs on HTTP by default.
### PWA / Web Push (optional)
Install the app from the browser for a standalone window and better mobile UX. **Background assignment alerts** use the **Web Push API** with **VAPID** keys on the server. When both keys are set, signed-in clients attempt to subscribe automatically (browser permission may be prompted). Docker users must pass the VAPID variables into the container environment and recreate the container after changes. Details, Docker verification steps, and subscriber contact semantics: **[`docs/pwa.md`](docs/pwa.md)**.
### Frontend build note
The Docker image and `go run` embed prebuilt assets under `internal/httpapi/web/dist`. If they are missing, build them:
```bash
cd internal/httpapi/web
npm install
npm run build
```
Then run `docker compose up --build` (local image build) or `go run ./cmd/scrumboy` again from the repository root.
# Why Scrumboy?
Simplicity of a light Kanban, with the power of structured systems: Roles, sprints, audit trails & customizable workflows - without being locked into SaaS tools.
# Who is this for?
- self-hosted & privacy-focused community
- small to medium-sized teams & solo builders
# Modes
- **Full** (`SCRUMBOY_MODE=full`, default): Auth can be enabled. First user via bootstrap; then login/session. Backup/export, tags, multi-project. Projects can be user-owned (project_members) or anonymous (shareable by URL): `/anon` (or `/temp`) creates a throwaway board and redirects to `/{slug}`.
- **Anonymous** (`SCRUMBOY_MODE=anonymous`): No auth. Landing at `/`; live deployment at: https://scrumboy.com/
# Features
- Custom Workflows: You can create any combination of workflow you want, per project, with user-defined "Done" lane.
- Realtime SSE enabled boards for instant multi-user actions.
- **Webhooks (API-only, full mode):** Register URLs per project so Scrumboy can POST JSON when subscribed domain events fire (e.g. `todo.assigned`). For your own automations, not in-app or browser notifications. See [Integrations](#integrations--api-access).
- Customizable Tags: Users can inherit and customize tag colors.
- Advanced filtering: Search todos based on text or tags.
- Sprints: create, activate, close; sprint filter on board; default sprint weeks (1 or 2) per project.
- Authentication & 2FA: TOTP supported when `SCRUMBOY_ENCRYPTION_KEY` is set.
- Audit trail: append-only `audit_events` table; todo/member/project/link actions logged (see [docs/audit_trail.md](docs/audit_trail.md)).
- Backup: export/import JSON; merge or replace; scope full or single project (see store backup logic).
- PWA: Excellent UX for mobile users.
- Multi-language Support: English, 简体中文, हिन्दी, Español (Latinoamérica), العربية, Français, বাংলা, Português (Brasil), Bahasa Indonesia, اردو, Русский, Deutsch, 日本語, Kiswahili, Tiếng Việt, Türkçe, 한국어, فارسی, ไทย, Italiano, Bahasa Melayu, Polski, and Українська.
- Anonymous shareable boards can be created in both Full & Anonymous deployments.
- VoiceFlow - deterministic voice commands (see [docs/voiceflow.md](docs/voiceflow.md)).
- Sticky-Note Wall - per-project scratchpad of draggable sticky notes on the board (see [docs/wall.md](docs/wall.md)).
- Todo notes Markdown preview (optional) - **markdown** / **preview** tabs in the todo Notes field; optional Mermaid diagrams in fenced ` ```mermaid ` blocks in preview only (see `FAQ.md`, `docs/markdown&mermaid.md`).
---
## Integrations & API Access
Scrumboy supports API access tokens for automation, integrations, and programmatic MCP access (legacy HTTP and JSON-RPC - see below). Full MCP guide for developers and agents: [`docs/mcp.md`](docs/mcp.md).
You can create a token from the API and use it to call MCP endpoints directly - no browser session or cookies required.
**Create a token (requires login session):**
```bash
curl -b cookies.txt -X POST http://localhost:8080/api/me/tokens \
-H "Content-Type: application/json" \
-H "X-Scrumboy: 1" \
-d '{"name":"cli"}'
```
Response includes a one-time token (starts with sb_).
Use it with MCP:
```bash
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sb_your_token_here" \
-d '{"tool":"projects.list","input":{}}'
```
### MCP (JSON-RPC) for AI agents
Scrumboy exposes a **Model Context Protocol (MCP) compatible JSON-RPC endpoint** for AI agents (Claude, etc.) and MCP-compatible clients.
**Endpoint:** `POST /mcp/rpc`
This is separate from the `/mcp` HTTP endpoint above and follows **JSON-RPC 2.0** (`initialize`, `tools/list`, `tools/call`, etc.). See **[`docs/mcp.md`](docs/mcp.md)** for tools, auth, response shapes, and examples; **[`API.md`](API.md)** for the full HTTP/MCP behavior reference.
#### Example: `initialize`
```bash
curl -X POST http://localhost:8080/mcp/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
```
#### Example: list tools
```bash
curl -X POST http://localhost:8080/mcp/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
```
#### Example: call a tool
```bash
curl -X POST http://localhost:8080/mcp/rpc \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sb_your_token_here" \
-d '{
"jsonrpc":"2.0",
"id":3,
"method":"tools/call",
"params":{
"name":"todos.create",
"arguments":{
"projectSlug":"my-project",
"title":"Created via MCP"
}
}
}'
```
**Notes**
- Compatible with MCP clients that support **HTTP JSON-RPC** to this URL.
- Some MCP clients expect **stdio**-based servers - those are **not** supported here.
- Authentication works via **session cookie** or **Bearer** token (same rules as `/mcp`).
- Compatible Codex/Claude-style agent workspaces that support local or manual
plugin loading can use the Scrumboy Board Operator plugin package in
[`plugins/scrumboy-board-operator`](plugins/scrumboy-board-operator). The
package contains a focused Skill workflow guide; each harness still needs to
be configured to load it.
This enables:
- CLI usage
- CI/CD automation
- AI agents and MCP clients (use **`POST /mcp/rpc`** for JSON-RPC; **`POST /mcp`** remains available for the legacy `{ "tool", "input" }` envelope)
- Scripting/integrations without login flows
### Webhooks (outbound HTTP)
Scrumboy can **POST JSON to URLs you register** when certain events occur. This is for **server-side integrations** (your script, gateway, queue worker, etc.). It does **not** add notifications inside the Scrumboy UI; live boards still update via **SSE** as before.
- **Availability:** **Full mode only** (endpoints are disabled in anonymous mode).
- **Who can configure:** Project **maintainers**, via the HTTP API only - there is **no settings screen** for webhooks yet.
- **API:** `POST /api/webhooks` (create), `GET /api/webhooks` (list yours), `DELETE /api/webhooks/{id}` - same session cookie / CSRF header rules as other mutating `/api/*` calls.
- **Events:** Subscribe to specific types (e.g. `todo.assigned`) or `*` for all delivered types. The set may grow over time; unused types in your list are harmless.
- **Security:** Optional per-webhook **secret**; when set, requests include an `X-Scrumboy-Signature` header (`sha256=` HMAC of the raw JSON body).
- **Semantics:** Best-effort delivery with retries on failure; not a durable external queue - design for idempotent receivers using the event `id` in the JSON body.
Example create (replace cookie / project id / URL):
```bash
curl -b cookies.txt -X POST http://localhost:8080/api/webhooks \
-H "Content-Type: application/json" \
-H "X-Scrumboy: 1" \
-d '{"projectId":1,"url":"https://example.com/scrumboy-hook","events":["todo.assigned"],"secret":"optional-shared-secret"}'
```
# Config
Env vars and defaults are defined in `internal/config/config.go`. ResolveDataDir uses `DATA_DIR` and `SQLITE_PATH` as documented there.
None of these are required for basic startup.
| Variable | Default (from code) |
|----------|---------------------|
| `BIND_ADDR` | `:8080` |
| `DATA_DIR` | `./data` |
| `SQLITE_PATH` | (empty; then `$DATA_DIR/app.db`) |
| `SQLITE_BUSY_TIMEOUT_MS` | `30000` |
| `SQLITE_JOURNAL_MODE` | `WAL` |
| `SQLITE_SYNCHRONOUS` | `FULL` |
| `MAX_REQUEST_BODY_BYTES` | `1048576` (1 MiB) |
| `SCRUMBOY_MODE` | `full` (or `anonymous`) |
| `SCRUMBOY_ENCRYPTION_KEY` | (empty) - **Required for 2FA.** Base64-encoded 32-byte key. Generate with `openssl rand -base64 32`. Without it, 2FA setup returns 503. Back this key up with `data/app.db`; do not replace it casually once encrypted auth/security data exists. |
| `SCRUMBOY_TLS_CERT` | `./cert.pem` - TLS cert for HTTPS |
| `SCRUMBOY_TLS_KEY` | `./key.pem` - TLS key for HTTPS |
| `SCRUMBOY_INTRANET_IP` | `192.168.1.250` - LAN IP to log for intranet access |
| `SCRUMBOY_VAPID_PUBLIC_KEY` | (empty) - **Web Push.** VAPID public key (URL-safe base64). Required together with private key for PWA background assignment notifications and for post-login auto-subscribe in the SPA. |
| `SCRUMBOY_VAPID_PRIVATE_KEY` | (empty) - VAPID private key (URL-safe base64). |
| `SCRUMBOY_VAPID_SUBSCRIBER` | (empty) - Contact for VAPID JWT `sub` (not tied to IdP). Use a **plain email** (e.g. `ops@example.com`); the server adds `mailto:`. Or set a full `mailto:...` or `https://...` URL explicitly. If unset, a built-in default is used. |
| `SCRUMBOY_DEBUG_PUSH` | (empty) - Set to `1` to log push send/prune on the server. |
`docker-compose.yml` overrides some of these (e.g. `SQLITE_BUSY_TIMEOUT_MS=5000`).
---
# Roles
In **full mode**, access is governed by two separate role systems. System roles do not grant project access; project access comes only from project membership.
### System roles (instance-wide)
| Role | Who has it | Allowed actions |
|--------|------------|------------------|
| **Owner** | Bootstrap (first) user; can be assigned by another owner | List all users; create users (admin-only API); update any user’s system role (owner/admin/user); delete users (except cannot delete the last owner). |
| **Admin** | Assigned by an owner | List all users; create users. Cannot change system roles or delete users. |
| **User** | Default for new users; assigned by owner | No system-level user management. Access to projects only via project membership. |
### Project roles (per project)
A user must be a member of a project to access it; system role alone does not grant access.
| Role | View board & todos | Create/edit/move/delete todos | Edit body when assigned | Manage members | Delete project | Tag delete/color (project-scoped) |
|---------------|--------------------|-------------------------------|--------------------------|----------------|----------------|-----------------------------------|
| **Maintainer**| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ (maintainer) |
| **Contributor**| ✓ | - | ✓ (body only) | - | - | - |
| **Viewer** | ✓ | - | - | - | - | - |
- **View** (board, backlog, burndown, charts, etc.): Any project role (Viewer or above).
- **Create/edit/move/delete todos, assign, sprints**: Maintainer only. Contributor cannot create, delete, move, or assign; cannot edit title, tags, sprint, or estimation.
- **Edit body when assigned**: Contributor can edit the body field only when the todo is assigned to them. Maintainer has full edit.
- **Manage members** (add/remove members, change role): Maintainer only.
- **Delete project**: Maintainer only.
- **Delete/update tag** (project-scoped tags): Maintainer only. User-owned tags: owner of the tag or maintainer in all projects where the tag is used.
- **Create tags**: Contributor or Maintainer.
Temporary/anonymous boards (shareable by URL, no auth) do not use project roles; anyone with the link can view and edit. New Todo and drag-and-drop are enabled for anonymous boards.
---
# Export scope
- **Full**: All projects the user can access (full mode: projects where the user is a member, or temporary boards they created; anonymous mode: not applicable for full export).
- **Single project**: One board/project only (e.g. current board in anonymous mode).
# Import modes
When importing a backup JSON, you choose how it is applied:
| Mode | Description |
|------|-------------|
| **Replace** | Replace all: delete every project in your current export scope, then create projects from the backup. Effect is “nuke and restore” so the instance matches the backup. Not available in anonymous mode. |
| **Merge** | Merge/update: for each project in the backup, match by slug. If a project with that slug exists (and you have access), update its todos, tags, and links to match the backup; otherwise create a new project. In anonymous mode, merge behaves like Create Copy (all projects are created as new). |
| **Create copy** | Create copy: create new projects for every project in the backup. Slugs are made unique (e.g. `name-imported-2`), so nothing is overwritten; you get duplicates. |
In **anonymous mode**, full-scope import is not allowed; you can only import into the current board (todos and tags are added to that board).
---
# Code layout (reference)
- `cmd/scrumboy`: main server entrypoint. Other `cmd/*` are utilities (tagcheck, tagrecover, dbquery, slugfix).
- `internal/config`: env-based config.
- `internal/version`: app and export format version.
- `internal/db`: SQLite open/options (PRAGMAs from config).
- `internal/migrate`: DB migrations.
- `internal/store`: data model and persistence (projects, todos, tags, auth, backup, ordering, memberships, audit, links, sprints, workflows, etc.).
- `internal/httpapi`: HTTP server, routing, auth cookies, SPA serve, embedded web FS.
- `internal/httpapi/web`: frontend (TS, CSS, HTML); built with `npm run build` in `internal/httpapi/web`; output under `web/dist` and embedded by server.
Invariants (e.g. canonical URL `/{slug}`, no UI links to `/p/{id}`) are enforced in code and tests; see `internal/httpapi` and `internal/store` for the authoritative behavior.
---
# Documentation
- **Architecture diagrams:** [`docs/diagrams/`](docs/diagrams/) - Mermaid sources and self-contained viewer (`serve-diagrams.bat` or `python serve.py` in that folder, then open `http://127.0.0.1:8775/`)
- **MCP (HTTP tools + JSON-RPC):** [`docs/mcp.md`](docs/mcp.md) - tool catalog, auth, legacy vs `/mcp/rpc`, examples (agents & automation). See also [`API.md`](API.md) for exhaustive MCP HTTP detail.
- **Agent plugin package:** [`plugins/scrumboy-board-operator`](plugins/scrumboy-board-operator) - local/manual plugin metadata, board-operator Skill, and seed eval cases for MCP/Agoragentic agent workflows.
- **PWA / Web Push (VAPID):** [`docs/pwa.md`](docs/pwa.md) - keys, subscriber contact, post-login auto-subscribe when VAPID is configured, Settings opt-out, tradeoffs.
- **Roles and permissions:** [`docs/roles_and_permissions.md`](docs/roles_and_permissions.md) - project roles, backend authorization, anonymous boards.
- **Audit trail:** [`docs/audit_trail.md`](docs/audit_trail.md) - action vocabulary, event model, integration points.
---
# License and Contributions
Scrumboy is licensed under the **GNU Affero General Public License v3** (AGPL v3). See [LICENSE](LICENSE) for the full text.
**Contributing:** Contributors must sign the [Contributor License Agreement (CLA)](CLA.md) before contributions are accepted. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, build, and pull request guidelines.
Scrumboy is an independent open-source project and is not affiliated with, sponsored by, or endorsed by Scrum.org, Scrum Alliance, Inc., or any other organization associated with Scrum training or certification. Any reference to "scrum" is made solely to describe the project management methodology that the software is intended to support. We hope you will ❤️ it as much as we do!
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
Python tool for converting files and office documents to Markdown.
awesome-claude-skills
A curated list of awesome Claude Skills, resources, and tools for...
antigravity-awesome-skills
The Ultimate Collection of 130+ Agentic Skills for Claude...
context-mode
MCP is the protocol for tool access. We're the virtualization layer for context.
claude-context-mode
claude-context-mode plugin reduces MCP context bloat, saving up to 99% of tokens.