Free, open-source certainty scoring for project work items. Connects to GitHub Issues, Linear, Jira, Notion (Monday + ClickUp coming). Outputs a static HTML dashboard + Markdown report — zero server required.
npx certainty-units sync
Teams that track success by counting effort (points, tickets closed) see how much is moving — certainty-units shows how sure you are about what's moving, and what would make you surer.
Fastest path — score any public GitHub repo, no API key needed:
npx certainty-units init
# edit certainty.config.yaml:
# source: github
# github:
# repo: your-org/your-repo
npx certainty-units sync
# Output: cu-report.html (open in any browser)For Linear / Jira / Notion, set the API key env var and run the same command:
LINEAR_API_KEY=lin_api_xxx npx certainty-units syncEvery sync prints instant insights in the terminal:
278 items · avg certainty 56%
high 68 medium 116 low 54 uncertain 40
Since last sync (2026-06-27): avg 54% → 56% ▲ +2 · 12 new items
▼ 45 → 20 ENG-142 Add SSO support
▲ 30 → 80 ENG-98 Migrate billing
Least certain open items:
5% #1099 always_allow permission policy not honored
missing: validation +40, workflow +20, discussion +15
Each work item gets a Certainty Score (0–100):
| Signal | Max points | How it maps |
|---|---|---|
| Validation status | 40 |
validated → 40, assumed → 10 |
| Workflow progress | 20 |
done → 20, review → 15, in_progress → 10 |
| Discussion | up to 15 | 5 pts per comment — undebated items hide risk |
| Acceptance criteria | 10 | found on the item (see below) |
| CU tier set | 10 | basic / intermediate / advanced |
| Evidence / description | 5 | non-empty description |
Scores map to levels: high (≥80) · medium (≥50) · low (≥20) · uncertain (<20)
Every score is auditable: hover the score bar in the HTML report for the per-signal
breakdown, and cu-data.json (via --json) includes certainty_breakdown per item.
The score is only as honest as its inputs, so the adapters read signals your team already produces:
-
Acceptance criteria are detected automatically from an
## Acceptance Criteriaheading (or**Acceptance Criteria**, or anAcceptance criteria:line) in the item description, or from a markdown checklist (- [ ] …). In Notion, use anAcceptance Criteriacolumn. -
Validation labels override workflow-derived validation. Label an item
validated,assumed, orneeds-clarification(Notion: tags) to record validation explicitly instead of letting "closed" imply "validated". -
CU tier labels —
cu:basic,cu:intermediate,cu:advanced— set the tier directly on any tool that has labels.
The score is the diagnosis; next is the prescription:
npx certainty-units next # this week's certainty to-do list
npx certainty-units next --create-issues # file each plan as a follow-up issuenext takes your least certain open items and prints concrete, assignable actions
(validate this assumption, write acceptance criteria for that, size this one).
--create-issues files them straight into your repo as checklist issues
(GitHub source, needs a token with write access) and skips items that already
have an open follow-up.
Each sync snapshots per-item scores to .cu-history.json and the next sync reports
what moved: average trend, biggest drops and rises, new items. Commit the file (or
cache it in CI) to keep the trail. Disable with --no-history.
When delivered CU velocity rises while average certainty stays flat or falls, the sync flags certainty debt: output is accelerating faster than validation. This is the number to watch on AI-augmented teams.
certainty-units sync --fail-below 50 # exit 1 if avg certainty < 50%Put it in front of a sprint kickoff or release train to block on too much uncertainty.
certainty-units sync --slack-webhook https://hooks.slack.com/services/…Posts the summary and least-certain items to a channel (or set output.slackWebhook
in the config).
| Tool | Status | Auth |
|---|---|---|
| GitHub Issues | ✅ | none for public repos, token for private |
| Linear | ✅ | API key |
| Jira | ✅ | API token |
| Notion | ✅ | API key |
| Monday.com | 🚧 coming | |
| ClickUp | 🚧 coming |
project: My Project
source: github # github | linear | jira | notion
github:
repo: owner/name
token: ${GITHUB_TOKEN} # optional for public repos
# state: all # all | open | closed
# limit: 500 # most recently updated issues to fetch
linear:
apiKey: ${LINEAR_API_KEY} # env var expansion supported
teamId: your-team-id
jira:
host: yourteam.atlassian.net
email: you@example.com
apiToken: ${JIRA_API_TOKEN}
projectKey: MYPROJECT
notion:
apiKey: ${NOTION_API_KEY}
databaseId: your-database-id
output:
html: cu-report.html
markdown: cu-report.md # optional
history: .cu-history.json # optional — score snapshots for deltas
# slackWebhook: https://hooks.slack.com/services/…Every tool uses different status names. Override the defaults:
linear:
apiKey: ${LINEAR_API_KEY}
teamId: abc123
fieldMap:
validation_status:
field: state.type # dot-path into the Linear issue object
map:
completed: validated
started: assumed
cu_tier:
field: estimate
map:
1: basic
3: intermediate
8: advanced- Copy examples/cu-report.yml to
.github/workflows/in your repo - Add your API key as a repo secret (
LINEAR_API_KEY, or nothing for public GitHub repos) - Enable GitHub Pages → the report publishes every Monday, with week-over-week deltas
MIT — free to use, modify, and embed. "Propozel" and "Certainty Units" are trademarks; the license covers the code, not the branding (see NOTICE).
Built on the Certainty Units methodology.