Two teams can use the same model and the same prompt — and get completely different results.
The difference is often not the model. It is the harness: the guides, rules, skills, hooks, tests, and CI feedback wrapped around the agent.
Most repositories build that harness slowly. Almost none of them measure it. Worse: a pull request can quietly delete hooks.json or drop a CI gate, and nobody notices until an agent does something expensive.
This tutorial shows how to put a deterministic maturity score into your GitHub Actions pipeline with Harness Score — so AI-assisted repos get the same kind of ratchet you already expect from tests and lint.
What “AI harness maturity” means
Harness Score scans filesystem evidence across tools like Cursor, Claude Code, Windsurf, Cline, Continue, Codex, and Copilot. It returns:
- a maturity level from L0 (Unharnessed) to L4 (Self-correcting)
- a score across six dimensions (up to 108 points)
- a ranked list of what to fix next
| Level | Name | Rough meaning |
|---|---|---|
| L0 | Unharnessed | Agents rediscover the project every session |
| L1 | Documented | Substantive context file exists |
| L2 | Guided | Scoped rules / skills + basic hygiene |
| L3 | Sensing | Tests, lint, types, and CI feedback exist |
| L4 | Self-correcting | Gate + feedback hooks close the loop |
Important constraints (by design):
- No LLM calls during the scan
- No network during the scan
- Same commit ⇒ same score
That is what makes the number safe to gate CI on.
Try it locally first:
npx harness-score@1.5.1
Why put this in GitHub Actions
Local scans are useful. CI is the contract.
With the Action in your pipeline you can:
- Fail PRs that drop below a minimum maturity level
- Show a job summary with the dimension breakdown
- Post a sticky PR comment with score deltas vs the base branch
- Emit a README badge that updates when maturity changes
Official Action: Harness Score on the GitHub Marketplace
Tutorial: add Harness Score to CI
1) Create the workflow
Add .github/workflows/harness.yml:
name: Harness maturity
on:
pull_request:
push:
branches: [main]
jobs:
harness:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: paladini/harness-score@v1
with:
min-level: '0' # report only for now
badge: 'harness-badge.svg'
report: 'harness-report.md'
Commit, push, and open the Actions tab. You should see a job summary like:
Harness Score: L2 · Guided (65% maturity)
plus a per-dimension table.
Tip: for stronger supply-chain hygiene, pin the Action to a full commit SHA instead of
@v1.
2) Start gating when you know your baseline
Once you know where the repo sits, raise the floor.
Example: require at least L3 · Sensing on main and PRs:
- uses: paladini/harness-score@v1
with:
min-level: '3'
badge: 'harness-badge.svg'
If maturity falls below L3, the job fails and prints the gaps needed to recover (for example: missing sensors or CI coverage).
A practical rollout:
- Week 1:
min-level: '0'(observe) - Week 2: set
min-levelto your current level (prevent regressions) - Later: bump one level at a time as you add guides, sensors, and hooks
3) Add sticky PR comments (optional, highly recommended)
On pull_request events, the Action can compare the PR head against the base branch and update a single sticky comment:
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
harness:
runs-on: ubuntu-latest
concurrency:
group: harness-score-${{ github.event.pull_request.number }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- uses: paladini/harness-score@v1
with:
min-level: '3'
comment: 'true'
badge: 'harness-badge.svg'
You need pull-requests: write — the Action cannot grant that for you.
The comment shows level movement (for example L2 → L3), score deltas, and newly passing / newly failing checks. That makes harness regressions visible in review, not only in a red X on the Checks tab.
4) Publish the badge in your README
The Action can write harness-badge.svg on every run. A common pattern is committing it to a badges branch (or uploading it wherever you host static assets), then embedding:
<img alt="Harness Score" src="https://raw.githubusercontent.com/<you>/<repo>/badges/harness-badge.svg" height="20">
You can also pin a static level badge from the docs site if you prefer not to auto-update.
More badge recipes: Show your maturity
Useful Action inputs
| Input | Default | What it does |
|---|---|---|
min-level |
0 |
Fail when maturity is below this level (0–4) |
badge |
harness-badge.svg |
SVG pill path (empty to skip) |
report |
(empty) | Write a Markdown report |
comment |
false |
Sticky PR comment with score delta |
working-directory |
. |
Subdirectory to scan (monorepos) |
version |
pinned release |
harness-score npm version |
gate |
maturity |
Gate on maturity (repo-only) or effective
|
include-user-harness |
false |
Include user-level harness paths in effective score |
config |
.harness-score.json |
Custom config path |
Outputs you can consume in later steps: level, level-name, percent.
Optional: repository config
If you need team policy (scopes, presets, per-check rules), add .harness-score.json at the repo root.
Example: keep CI gated on repository maturity, while still allowing local diagnosis with user-scope overlays:
{
"scopes": {
"user": true,
"system": false
},
"gate": "maturity"
}
Customization is transparent: excluded checks are removed from both earned and available points (no free credit), and security checks for exposed credentials cannot be disabled.
What this does not claim
A high score means the infrastructure for reliable agent work exists:
- context and rules
- skills/commands
- hooks/guardrails
- sensors (tests/lint/types)
- CI feedback
- hygiene/safety
It does not mean your tests are good, your rules are true, or every runtime path honors the committed harness. That honesty is intentional — deterministic scanners should not pretend to judge vibes.
Full starter workflow
Copy-paste version with gate + PR comment + badge + report:
name: Harness maturity
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
harness:
runs-on: ubuntu-latest
concurrency:
group: harness-score-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- name: Scan AI harness maturity
id: harness
uses: paladini/harness-score@v1
with:
min-level: '3'
comment: 'true'
badge: 'harness-badge.svg'
report: 'harness-report.md'
- name: Upload report artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: harness-score
path: |
harness-badge.svg
harness-report.md
Try it, then ratchet
- Run
npx harness-score@1.5.1locally - Add the workflow with
min-level: '0' - Set
min-levelto your current level to prevent silent regressions - Climb toward L3/L4 with the ranked fix list from the report
Links:
If you add this to a repo, comment with your starting level (L0–L4) and the first check that surprised you — those reports are the best way to harden the maturity model.
Top comments (0)