See how your software really gets built.
Turn Jira, GitHub, GitLab, and Azure DevOps into one board with the widgets, dashboards, rankings, and roadmaps engineering leaders use to see what’s really going on.
Live demo · Website · Docs · Enterprise
A hosted Deckgauge, seeded with a fictional company: two boards carrying 240 items, a roadmap, comparison dashboards, a 25-person org chart, timesheets, and six months of engineering history behind the intelligence widgets.
demo.deckgauge.com — sign in with test@test.com / test
The demo is shared by everyone who visits and is reset periodically, so treat anything you change there as temporary. Do not put real data in it. For a private instance with your own sources connected, install it below — it takes one command.
Pull Jira, GitHub, GitLab, and Azure DevOps into a single Monday-style board — grouped, owned, status-tracked, sized, and classified CapEx/OpEx. Discuss any item inline.
Timelines built straight from live board data — parallel lanes per team, effort-sized bars, and a today line.
Import your org from CSV/Excel (or sync your directory) — a live reporting tree, per-team boards, and private 1:1 / review notes on every person.
📺 Full live tour → deckgauge.com — plus the intelligence dashboard, the ranking leaderboard, and CapEx/OpEx reporting.
Paste this into your AI coding agent (Claude Code, Cursor, Copilot agent, or any agent that can run commands). It fetches the setup skill and installs Deckgauge on your machine:
curl -fsSL https://deckgauge.com/install.md
That’s it — the agent clones the repo, starts the stack, sets up the database, and hands you back
http://localhost:3000.
git clone https://github.com/Codpal-Limited/deckgauge
cd deckgauge
./scripts/init-env.sh
docker compose up -d
# create the schema (-T keeps it non-interactive; if it fails, see CONTRIBUTING.md
# — do NOT add --accept-data-loss, it drops tables)
docker compose run --rm -T api sh -c "cd /app/packages/db && npx prisma db push"
# create a signed-in-and-populated demo account
./scripts/test-account.shThen open http://localhost:3000 and sign in with test@test.com /
test. You land on a working product: two boards carrying 240 items, a
roadmap, a Platform-vs-Mobile comparison dashboard, a 25-person org chart,
timesheets, and six months of engineering history behind the Engineering
Intelligence and Team Focus dashboards. The org-tree sync that fills the
per-engineer views runs as part of that command, so nothing is left to press.
./scripts/init-env.sh writes .env and generates a random password for
Postgres, ClickHouse, Keycloak's database, the Keycloak admin console, the OIDC
client and the session-signing key — this install's own, not one shared with
every other clone. It refuses to overwrite an existing .env; use
./scripts/init-env.sh --check on one. There is no cp .env.example .env step
any more, and copying that file by hand does not work: every credential in it is
empty and docker-compose.yml requires them, so the stack stops at up with the
variable named rather than booting on a password published in this repository.
Before you expose this install to anything.
test@test.comhas a password everybody knows, anddocker-compose.ymlpublishes its ports on all interfaces by default (BIND_HOSTis unset). That is fine on a laptop and not fine anywhere else: remove the account (below) and setBIND_HOST=127.0.0.1:in.env— note the trailing colon — before the machine is reachable by anyone but you.
Remove them in this order — data first, then the account. Neither touches a board you made yourself, but the sequence matters:
# 1. the demo data, keeping the account
docker compose run --rm api npx tsx /app/packages/db/src/demo/seed-demo.ts --remove
# 2. then the account and its grants
./scripts/test-account.sh --removeRemoving the account deletes its User row, and every grant — OrgMembership,
BoardAccess, OrgTreeAccess, RoadmapAccess, ComparisonAccess — cascades
with it. test@test.com is the only member of a stock install, so once it is
gone the organization has no active admin, and seed-demo.ts --remove looks one
up before it removes anything: it refuses, and the demo content is stranded —
in the database, visible to nobody, removable by nothing.
Prefer to start empty and register your own account? Skip
scripts/test-account.sh entirely. Open http://localhost:3000, sign in, and
create your organization — only the first person to sign in can, and Deckgauge
never creates one for you. You can still seed the demo content into it
afterwards:
docker compose run --rm api npx tsx /app/packages/db/src/demo/seed-demo.ts
# fills the per-engineer leaderboard, heat strip and per-employee board lists,
# which are computed by the org-tree sync rather than written by the seeder
docker compose run --rm -e DECKGAUGE_ORG_SLUG=your-org-slug \
worker npx tsx /app/apps/worker/src/scripts/trigger-org-sync.tsYou need nothing further on a fresh install: the first account to sign in is granted admin automatically, which is the same grant that lets you create the organization at all — so the Engineering Intelligence dashboards and the org chart's salary column both work for you.
That only changes if yours is not the first account (you ran
scripts/test-account.sh earlier, or someone else registered first). Analytics
then falls back to the cockpit-admin Keycloak realm role rather than your
organization role — the cross-cutting people-analytics reads carry no board id to
check — so grant it and sign out and back in to re-mint the token:
docker compose exec keycloak sh -c '
/opt/keycloak/bin/kcadm.sh config credentials --server http://localhost:8080 \
--realm master --user "$KC_BOOTSTRAP_ADMIN_USERNAME" \
--password "$KC_BOOTSTRAP_ADMIN_PASSWORD" &&
/opt/keycloak/bin/kcadm.sh add-roles -r deckgauge \
--uusername you@example.com --rolename cockpit-admin'The config credentials line is required: kcadm.sh stores its session in a
config file the container does not ship with, and an unauthenticated call hangs
instead of failing. It reads the admin credentials from the container's own
environment, so you never type or paste them — unless you rotated
KEYCLOAK_ADMIN_PASSWORD after first boot, in which case those variables hold a
password the master realm no longer has and you must pass the real one.
Full setup — connecting sources, SSO, access control — is in the docs.
Back up first. docker compose up -d after a git pull starts whatever
image versions that commit pins, and two of those upgrade your data in place:
./scripts/backup.sh # Postgres, Keycloak, ClickHouse, uploads
git pull && docker compose up -dKeycloak migrates its own database schema on first start of a new version and that migration is one-way — rolling the image back does not roll the schema back. ClickHouse likewise upgrades its data directory in place. Both are routine and neither needs manual steps; the backup is what makes them reversible if something about your install is unusual.
Your existing .env keeps working across ordinary upgrades. The compose file
passes only the variables it names, so keys that later releases stop using are
ignored rather than breaking startup. (Two releases do need an .env edit: the
default-credential change immediately below, and the deckgauge rename after
it.)
docker-compose.yml used to default every credential — POSTGRES_PASSWORD to
cockpit, KEYCLOAK_ADMIN_PASSWORD to admin, and so on — so an install could
run without ever setting them. Those fallbacks are gone: each is now
${VAR:?…}, and compose refuses to start while one is missing. Nothing is
rotated and no data moves; the values simply have to be written down.
Run ./scripts/init-env.sh --check. It lists exactly what your .env is
missing and changes nothing. In practice that is CLICKHOUSE_USER and
CLICKHOUSE_PASSWORD, which existed only inside docker-compose.yml before, and
possibly KEYCLOAK_CLIENT_SECRET and NEXTAUTH_SECRET.
Set them to the values your install is already using, not to fresh ones.
CLICKHOUSE_USER=cockpit
CLICKHOUSE_PASSWORD=cockpit
KEYCLOAK_DB_PASSWORD=keycloak
KEYCLOAK_CLIENT_SECRET=deckgauge-secret
NEXTAUTH_SECRET=change-me-in-production
Postgres, ClickHouse and Keycloak's database each read their password only on
first start, so a new one here does not rotate anything — it locks the stack
out of its own volume, and the failure that follows is an authentication error
pointing at nothing. Rotating for real means ALTER USER on the running server
(or docker compose down -v, which deletes the data). A fresh
NEXTAUTH_SECRET is safe and signs everyone out once.
Two of the five are rotatable, and you should rotate both — just not by
editing this file alone. Writing KEYCLOAK_CLIENT_SECRET=deckgauge-secret
above is correct today, because that is what your realm already holds and
--import-realm will not change a realm that exists. But it is a value
published in this repository, so leaving it there permanently re-pins your
install to a secret anyone can read. Rotate it on the RUNNING Keycloak and put
the new value in .env:
NEW=$(openssl rand -hex 32)
CID=$(docker compose exec -T keycloak /opt/keycloak/bin/kcadm.sh get clients \
-r deckgauge -q clientId=deckgauge-web --fields id --format csv --noquotes)
docker compose exec -T keycloak /opt/keycloak/bin/kcadm.sh update "clients/$CID" \
-r deckgauge -s secret="$NEW"
# then set KEYCLOAK_CLIENT_SECRET=$NEW in .env and: docker compose up -d web keycloak(kcadm.sh needs config credentials first — the block further up shows the
form.) NEXTAUTH_SECRET is the other one, and it needs nothing but a new value.
The remaining three are volume-initialisation passwords and are not rotatable
this way.
Releases before this one shipped under the project's old internal name,
vp-cockpit. Containers, the Compose project, the Keycloak realm and its web
client have all moved to deckgauge. Fresh installs get the new names and need
nothing. An existing install needs two things after git pull.
First, edit .env. This matters more than it looks. .env.example assigns
these keys rather than commenting them, and the setup step at the time was
cp .env.example .env — so your .env almost certainly names the old realm, and
compose interpolates it, meaning your stale value overrides the new default.
Change the realm segment in these, wherever they appear:
- KEYCLOAK_ISSUER=http://localhost:8080/realms/vp-cockpit
+ KEYCLOAK_ISSUER=http://localhost:8080/realms/deckgauge
- KEYCLOAK_CLIENT_ID=vp-cockpit-web
+ KEYCLOAK_CLIENT_ID=deckgauge-web
- KEYCLOAK_JWKS_URI=http://keycloak:8080/realms/vp-cockpit/protocol/openid-connect/certs
+ KEYCLOAK_JWKS_URI=http://keycloak:8080/realms/deckgauge/protocol/openid-connect/certsLeave KEYCLOAK_CLIENT_SECRET exactly as it is — the migration does not
change the client secret, so whatever you have now stays correct.
Then migrate Keycloak, which imports keycloak/realm-export.json only into
an empty database and so never sees the rename on its own:
docker compose up -d # bring the stack up on the new names
./scripts/rename-keycloak-realm.sh # rename the realm, client and theme
docker compose up -d --force-recreate api webThe script refuses to run until that .env edit is done, and names the exact
lines if you skipped it. It is idempotent, reads the running Keycloak rather
than guessing, and skips anything already migrated. If your clone directory is
not named deckgauge, tell it which Compose project to use:
COMPOSE_PROJECT_NAME=<your-dir> ./scripts/rename-keycloak-realm.sh.
Everyone signs in once more afterwards — tokens issued by the old realm are no
longer valid, and NEXTAUTH_SECRET's default moved too, so existing session
cookies stop decrypting.
Two cosmetic leftovers are harmless and can be removed at your leisure: the
old vp-cockpit-* containers (docker rm) and the old images
(docker image prune). Backups already in ./backups/ keep their old
filenames and stay restorable — scripts/restore.sh takes the path you give
it and does not care what the archive is called.
- 📊 Monitoring & visibility — DORA, flow, throughput, review time, WIP as widgets you watch, centralized across all four tools.
- 🤝 Contribution insight, not a scoreboard — see PRs, tickets, commits and review comments per person, with weights you choose, to recognise the people carrying the load and spot who has gone quiet because they are stuck. Decision support with a human in the loop — never an automated performance rating. Team and org totals are the default view; per-person detail is there when you need it.
- 🗂️ Alignment dashboards — pull imported issues into one board for leadership meetings: comment conclusions, re-prioritize, set due dates, resync for live status.
- 🛣️ Auto-generated roadmaps — timelines built from live board data, with progress and a today line.
- 💰 CapEx / OpEx for finance — audit-ready software capitalization, inferred from activity, no manual timesheets.
- 👥 Team management & reviews — dated, private notes so 1:1s and performance reviews are grounded in real examples.
Source-available. Multi-tool. No lock-in. Read the queries, run it yourself, trust the numbers.
Deckgauge has an in-app Advisor panel that answers questions about a board. If you already have Claude Code or Codex installed and signed in, it runs on your local agent — no API key, no model configuration, no separate LLM bill, and your model credentials never touch Deckgauge.
pnpm deckgauge:advisor # detects your local agent and connects the panel to itOpen a board's Advisor panel while signed in and it authenticates itself with your existing session. The agent reads board data only through Deckgauge's read-only, board-scoped MCP tools — every call re-checks your board access server-side. The bridge also asks the agent to hand it permission decisions, and auto-denies file edits and shell commands whenever it gets them; if an agent won't do that, the bridge says so rather than pretending otherwise. It runs a full local coding agent on your behalf, so read the security model before pointing it at anything you care about.
No local agent? The panel falls back to a server-side provider (an Anthropic key or your own Ollama server), configured in Settings → Advisor.
Details, including the full security model: docs/advisor-local-agent.md
and docs/advisor-mcp.md.
-
Community — free and source-available, uncapped (analyze any number of developers), under the license below. This is the whole product: no metric, board, dashboard or connector is held back for a paid tier.
-
Enterprise — we host and operate it for you, or you take a commercial license for your own environment, with support attached. Published price, no sales call: deckgauge.com/pricing · support@codpal.com
What that adds is hosting, support and a commercial license — not features taken out of the free core. SSO through Keycloak and the salary / manager-note visibility rules are in the Community edition and stay there. Aggregate-only (works-council) mode, audit logs and SCIM are designed and not built: we build them for the customer whose rollout needs one, on an agreed timeline. deckgauge.com/enterprise says which is which.
Deckgauge is built and maintained by CodPal — fractional CTO-as-a-service for startups and scale-ups. The platform is source-available under the FSL (see License) and stands on its own. If you want help acting on what it surfaces — reading your DORA metrics, clearing delivery bottlenecks, or standing up engineering leadership — CodPal offers a Deckgauge Engineering Health Check: a fractional CTO reviews your dashboard and hands you a one-page assessment plus your top three fixes. → support@codpal.com
Contributions welcome — see CONTRIBUTING.md. Contributors sign off under the DCO/CLA so the code can be used across editions.
Functional Source License (FSL-1.1-Apache-2.0), SPDX id FSL-1.1-ALv2. The short
version, because it is the first thing people ask:
Free to run, at any size, forever. No developer cap, no seat count, no feature gate on metrics, no expiry, no license key to run it, nothing that phones home. Running it commercially is fine — including inside a company that competes with us. Read it, change it, fork it, redistribute it. The one thing you may not do is offer Deckgauge to other people as a commercial product or service that substitutes for it, which is to say: do not resell it as a competing hosted service.
And it converts. Every release carries an irrevocable Apache-2.0 grant that takes effect
on its second anniversary. v2.0.0 was published on 11 September 2026, so it is Apache-2.0
licensed from 11 September 2028. Later releases convert on their own dates.
Why not Apache-2.0 today, what the choice costs us, and the cases people assume are forbidden
and are not: https://deckgauge.com/license/. The licence itself governs and is in
LICENSE.


