Are you the author? Sign in to claim
Deterministic quality scorer for AI agent instruction files — 8-dimension scoring with security, multi-format (SKILL.md,
The Ruff for AGENTS.md — deterministic quality scores for the instruction files that drive your AI. Same input, same score, on every machine.
That last badge is Schliff scoring this repo's own AGENTS.md — live, and reproducible from your own checkout.
Your AI instruction files silently degrade — and nothing catches it. AGENTS.md is read by Cursor, Codex, Copilot, and Claude Code — one rotting file now quietly degrades four tools. A trigger phrase rots, an edge case slips, the file balloons past its token budget. No error, no red test — just agents that quietly get worse.
Schliff scores AGENTS.md — and the rest of the family (SKILL.md, CLAUDE.md, .cursorrules, system prompts) — against an explicit, versioned rubric. No LLM judge in the critical path. No network. No randomness. A rule engine you can read, pin, and gate CI on.
pip install schliff
schliff score AGENTS.md # or any SKILL.md / CLAUDE.md / .cursorrules
schliff demo # no instruction file handy? score a built-in bad one
This is the real, current output of schliff score AGENTS.md on this repo's own
AGENTS.md — clone and run it yourself:
schliff v8.7.0
structure ██████████ 100/100 perfect
operational_coverage ██████████ 100/100 perfect
efficiency ████████░░ 79/100 good
composability ██████████ 95/100 excellent
clarity ██████████ 100/100 perfect
Structural Score ███████████████████░ 95.8/100 [S]
Tokens: 996 / 3,000 (ok)
Format: agents.md (normalized)
No model produced that number. Run it on another laptop and you get 95.8 again — a score you can't reproduce isn't a measurement, it's a vibe. And we hold ourselves to that: this repo's own badge (scored in isolation) once disagreed with its own CLI (scored in-repo) by ~15 points on the same bytes, because structure was crediting an on-disk references/ neighbourhood instead of the file's content. We fixed the engine, not the file (#10) — now cp AGENTS.md /tmp && schliff score /tmp/AGENTS.md returns the same number as CI and the badge. (The agents.md headline weights structure·operational_coverage·efficiency at 0.4/0.4/0.2; composability and clarity are shown for information, not counted.)
The quick-start and case-study numbers here are reproducible from released schliff==8.7.0 (pip install schliff==8.7.0); the hydra field run below is dated to the version it was measured on. No install? Paste your file into the playground — same engine, with AGENTS.md and SKILL.md tabs.
The SKILL.md for ShieldClaw — a real prompt-injection-defense skill, now archived — is Schliff's reproducible before/after. The fixtures ship in docs/case-studies/shieldclaw/; every number below is the current engine's output, reproducible with schliff score. (For the 28.7 row, score a copy of SKILL-before.md outside that directory — in place, the engine auto-discovers the sibling eval suite.)
| Score | Grade | Dimensions measured | |
|---|---|---|---|
| Before, scored in isolation | 28.7 | F | 4/7 — no eval suite; explicit ceiling warning |
| Before, with its eval suite | 84.5 | B | 7/7 |
| After fixes | 94.6 | A | 7/7 |
Two separate effects, and Schliff refuses to conflate them. Adding the eval suite lifted the measurement ceiling (28.7 → 84.5) — that is coverage, not quality. The quality delta is 84.5 → 94.6, driven by composability 20 → 86 and efficiency 60 → 83 after adding scope boundaries, an I/O contract, and handoffs — structural gaps a linter can't see, caught as a number that was too low.
A second field run, against an external repo (hydra, measured on released schliff==8.4.0, 2026-07-03): 71.0 [C] → 76.5 [B] — edges 82→100, composability 56→81, fix merged upstream (Zandereins/hydra#34). Efficiency deliberately stayed at 47: a ~14k-token file against a 1,000-token budget was an informed decline, not a blind chase of the number. (External repo — not re-runnable from these fixtures.)
Most "AI quality" tools ask another LLM how good your prompt feels — a different answer every run. That makes the score non-reproducible (re-run it, get a different number), un-auditable (the rubric lives in a hidden prompt), and trivially gameable (write for the judge, not the user). You can't gate a release on a number that drifts. Schliff computes how good the file measurably is — the same answer every run.
Deterministic means reproducible and auditable — it does not automatically mean the number is right. Schliff's claim is narrower and checkable: the rubric is open source, every scorer is readable, the weights are a dict, and the case studies above show the score moving with real fixes. If you disagree with the rubric, you can read it and file an issue — you can't do that with a judge prompt.
Config linters tell you whether the file is valid — a list of pass/fail rules. Schliff tells you how good it is — one graded 0–100 score you can gate, diff across commits, and rank.
verify, badge, and the leaderboard return the same score on your laptop and in CI.scripts/scoring/. The weights are a dict you can open. There is no hidden judge prompt.guards.py) detects and floors padding, junk fences, platitude farms, and keyword stuffing — worthless text cannot outrank operational text. A plausible lie about your repo is out of reach of any static scorer (see What the score does not measure).[evolve] / [judge] extras pull in LLM clients for an opt-in smoke-test only — never for scoring.)Because the number is stable, it does real work: gate pull requests on it in CI, or diff and compare it across commits with the CLI.
An optional LLM judge exists for exploratory work, but it is never part of the deterministic score. The number you gate on is rule-based, end to end.
Full methodology: docs/SCORING.md.
For the SKILL.md family, Schliff runs 8 scorers per file. 7 of them form the headline composite; security (always computed) and runtime (opt-in) are reported as separate signals so a security warning never silently inflates or deflates your quality grade.
| Dimension | Weight | In headline? |
|---|---|---|
structure | 0.15 | ✅ |
triggers | 0.20 | ✅ |
quality | 0.20 | ✅ |
edges | 0.15 | ✅ |
efficiency | 0.10 | ✅ |
composability | 0.10 | ✅ |
clarity | 0.05 | ✅ |
security | 0.05 | Separate signal (gate threshold 70) |
runtime | — | Separate signal (no profile weight) |
The seven headline weights are renormalized to sum to 1.0 — that is the canonical basis.
[!NOTE]
securityis a side signal for theSKILL.md/CLAUDE.md/.cursorrules/AGENTS.mdfamily, but a core 0.15 headline dimension for thesystem_promptformat, which uses its own scorer set. Onlyruntimeis excluded everywhere.
Schliff does not quietly renormalize across whatever you happened to measure. Unmeasured dimensions contribute 0 and stay in the denominator — so coverage gaps lower your ceiling instead of quietly disappearing. Your score ceiling equals your measurement coverage. Measure 4 of the 7 headline dimensions and your maximum possible score is capped accordingly, with an explicit warning:
ℹ Scored 4/7 dimensions — the score can't exceed 42% until the rest
are measured. Run /schliff:init to add an eval suite and score:
triggers, quality, edges.
[!IMPORTANT] This is deliberate. A partial measurement is an honest partial score, never a flattering one. Unmeasured work is missing points, not invisible. To lift the ceiling, measure more — don't hide the gap.
[!NOTE] Structural score = the composite renormalized over the dimensions Schliff can measure deterministically without an eval suite (structure, efficiency, composability, clarity). The full 7-dimension composite additionally folds in triggers, quality, and edges — which require an eval suite, generated with the
/schliff:initClaude Code slash command. AGENTS.md needs no eval suite: its full 3-dimension headline (structure, operational_coverage, efficiency) is always measurable.
[!NOTE] Calibration is strictly opt-in: ambient auto-calibrated weights apply only when
SCHLIFF_CALIBRATED_WEIGHTSis set and only for the interactivescorecommand, and Schliff emits aweight_source=calibratedwarning flagging that such scores are not comparable to the canonical scale. Everything that gates a release stays canonical.
S ≥ 95 · A ≥ 85 · B ≥ 75 · C ≥ 65 · D ≥ 50 · E ≥ 35 · F < 35
test_known_limit_plausible_fabrication_scores_high, spec §11).len//4, not a tokenizer.triggers/quality/edges need an eval suite (/schliff:init) or the ceiling warning caps the score. AGENTS.md has no such gap.A high Schliff score is necessary, not sufficient.
One engine, five instruction-file formats — each with its own token budget and scorer set:
| Format | Token budget | Scorers |
|---|---|---|
SKILL.md | 1,000 | shared 8-scorer registry |
CLAUDE.md | 2,000 | shared 8-scorer registry |
.cursorrules | 500 | shared 8-scorer registry |
AGENTS.md | 3,000 | shared 8 scorers + operational_coverage (own 3-dim headline) |
| system prompts | 1,500 | dedicated set (structure_prompt, output_contract, efficiency, clarity, security, composability, completeness) |
Format is auto-detected; override with --format (skill, claude, cursor, agents, system-prompt).
Published on the GitHub Marketplace as AGENTS.md Lint (Schliff).
Gate pull requests on instruction-file quality. The action defaults to your
repo-root AGENTS.md and posts a scored comment on every PR:
# .github/workflows/agents-lint.yml
name: AGENTS.md Lint
on: [pull_request]
jobs:
score:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Zandereins/schliff@v1
with:
minimum-score: '75' # optional: fail the PR below this score
By default it scores AGENTS.md at the repo root; set skill-path: to lint a
SKILL.md, CLAUDE.md, or .cursorrules instead. One caveat: the Action
installs the latest released engine from PyPI, so after a release its scores can
lead an older pinned install; pin it with schliff-version: '8.7.0' in the
with: block if you need byte-stable gates.
Prefer not to depend on a third-party action? The dependency-light equivalent:
- run: pip install schliff
- run: schliff verify AGENTS.md --min-score 75
schliff verify exits non-zero when the score falls short and works for every
supported format — the minimum is scaled by measurement coverage, so SKILL.md
files without an eval suite aren't auto-failed. Requires schliff ≥ 8.5.0 for
AGENTS.md: older engines scored it under the SKILL profile
(#101).
Show your repo's AGENTS.md quality — no setup, no CI, no account:

Replace OWNER/REPO with your repository. The badge is scored live from your
AGENTS.md at HEAD; GitHub's image cache (camo) may delay refreshes. Public
repos only.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Zandereins/schliff
rev: v8.7.0
hooks:
- id: schliff-verify
args: ['--min-score', '75']
The hook fires on SKILL.md files (its files filter); gate AGENTS.md with the Action or schliff verify AGENTS.md in CI.
schliff <command> [path] [options]
| Command | What it does |
|---|---|
score | Score a file and print the grade bar |
verify | CI gate — exit 0/1 based on a minimum score |
check-commands | CI gate — flag setup/build/test commands that don't exist in the repo (exit 1 if dangling) |
doctor | Scan and grade every installed skill |
badge | Generate a Markdown score badge |
diff | Explain score changes between two git commits |
compare | Compare two files side by side |
suggest | Rank fixes by estimated score impact |
report | Generate a Markdown score report |
demo | Score a built-in bad skill to see Schliff in action |
evolve | Improve an instruction file's score |
version | Print the version |
Beyond grading, Schliff can apply fixes. The improvement engine measures first, then fixes (not the other way around):
measure_patch_ratio.py — re-run it to check. The rest are handed to an optional LLM.It also carries cross-session episodic memory (episodic_store.py), so improvement runs learn from prior attempts instead of repeating them. Drive it from Claude Code with /schliff:auto, or use schliff evolve directly. This is an optional convenience layer — the deterministic score is the product.
pip install "schliff[evolve,judge]" # optional LLM extras for this layer only
LLM extras power this optional layer only; they are never used for scoring.
| Install | Pulls in | When you need it |
|---|---|---|
schliff | stdlib only | Scoring, verify, badge, CI — everything that gates a release |
schliff[judge] | LLM client | Opt-in exploratory LLM-judge smoke-test (never scoring) |
schliff[evolve] | LLM client | Opt-in autonomous-improvement extras |
The full methodology — scorer internals, the full-denominator composite, the anti-gaming guards, and the calibration model — lives in docs/SCORING.md.
scripts/
├── cli.py # CLI entrypoint
├── scoring/
│ ├── registry.py # canonical weights, scorer lists, headline exclusions
│ ├── composite.py # full-denominator composite model
│ ├── formats.py # format detection + token budgets
│ ├── guards.py # anti-gaming detection
│ └── structure.py · triggers.py · quality.py · edges.py · …
├── text_gradient.py # deterministic patch gradients (apply gate)
├── episodic_store.py # cross-session episodic memory
└── measure_patch_ratio.py # canonical source for the patch-ratio claim
docs/SCORING.mdschliff demo in the CLI). The playground reports the structural score for SKILL.md — the CLI's full 7-dim composite can differ; AGENTS.md has no such gap.docs/case-studies/MIT © Franz Paul
⚠️ Experimentelle Skill-Sammlung für deutsches Recht (Arbeits-, Gesellschafts-, Insolvenz-, Datenschutz-, Prozessrecht u
Manage multiple Claude Code agents from TUI or Web with tmux and git worktrees
Project management using GitHub Issues + Git worktrees for parallel agent execution
Core skills library for Claude Code with 20+ battle-tested skills including TDD, debugging, and brainstorming