Pricing
CLI

How to score a prompt from the command line

August 25, 2026 · 7 min read
CLI
Evals
Workflow

Most people who want to grade a prompt start by writing a scoring script. It calls a model, asks it to rate the output one to ten, parses the number, prints it. It works on the afternoon you write it. Six weeks later nobody trusts it, because nobody can say what the number means or whether it moved.

The terminal is the right place for this. The scoring script is the wrong shape. Here is the loop we actually use, entirely from the command line.

The two-minute version

The CLI runs with npx — no install, Node 22 or newer:

# Structure and syntax, fully local — no API, no credits
npx rubrkit validate "prompts/**/*.md"

# Score it against the rubric
npx rubrkit test "prompts/**/*.md" --remote

# Gate on the score
npx rubrkit audit team-agent-kit --fail-under 85 --ci

Commands that call Rubrkit read RUBRKIT_API_KEY from your environment. Keys are never written to disk, logs, or bundles, and they are not allowed in a --config file — pass --api-key explicitly only when you have no other option.

Start local, because local is free

validate makes no API calls and costs no credits. It answers a narrow question — is this artifact structurally sound — and it answers it instantly. Run it on save, run it in a pre-commit hook, run it on every file in the repo. There is no reason to be stingy with it.

test --local is the same idea one step up: local checks across a glob, with no scoring round trip.

npx rubrkit test "prompts/**/*.md" --local --format json

Nothing here answers "is this prompt any good." That is the point. Let the free checks catch the cheap failures first, so the paid scoring run is spent on the question only scoring can answer.

Then score it

test --remote submits the artifact and returns a quality score against the ten-dimension rubric. audit does the same with findings and gates attached. eval runs the rubric with detailed per-dimension scoring.

The flag that matters most in an inner loop is --watch:

npx rubrkit test prompts/triage.md --remote --watch

Now editing the prompt re-scores it. You are no longer guessing whether the sentence you just tightened helped — you watch the number move while you work. Pair it with --changed in a larger repo so you only re-score what you touched.

If you are iterating hard and want to skip the expensive analysis pass, --no-ai reduces cost where it is supported. One caution in the other direction: --no-cache forces a fresh run, and a forced run is charged like any uncached audit. Reach for it when you genuinely suspect a stale result, not by reflex.

Get the number out of the terminal

Text output is for you. Everything else should be structured:

# JSON for scripts
npx rubrkit audit team-agent-kit --format json --output audit.json

# JUnit for your CI's test reporter
npx rubrkit eval team-agent-kit --format junit --output rubrkit-junit.xml

JUnit is the underrated one. Point it at the same reporter your unit tests already use and prompt regressions show up in the same place as everything else — with a name, a history, and a diff — instead of buried in a log nobody opens.

Long runs return a job id; rubrkit report <job-id> --format json fetches the result later, which is what you want when the audit outlives the step that started it.

Exit codes, so a script can act on it

This is the part a homemade scoring script almost never gets right. The CLI distinguishes failed the bar from could not run:

  • 0 — passed.
  • 1 — quality checks failed: threshold not met, or findings detected.
  • 2 — invalid usage or configuration.
  • 3 — auth failure, usually a missing or invalid key.
  • 4 — rate limited, usage blocked, or circuit breaker active.
  • 5 — network, API, or server failure.

A script that treats every non-zero exit as "the prompt is bad" will one day turn your build red because a token expired, and someone will spend an hour editing a prompt that was fine. Gate on 1. Alert on 3 through 5.

Two flags decide what counts as failure:

# Fail if the score drops below 85
npx rubrkit audit team-agent-kit --fail-under 85 --ci

# Fail on any high-severity finding, whatever the score
npx rubrkit audit team-agent-kit --fail-on high --ci

They answer different questions. --fail-under catches slow erosion — the prompt that has been getting vaguer for a month. --fail-on catches a single sharp problem that a good average would otherwise hide. Most teams want both.

--ci turns off anything interactive and gives you CI-appropriate exit codes. Always pass it in a pipeline; never rely on the default being right.

Why not just write the scoring script

Because the script is the easy half. The half that rots is everything around the number:

  • A stable scale. "7 out of 10" from a model with no rubric means a different thing this week than it did last week. A named ten-dimension rubric gives the number somewhere to stand.
  • Noise you have measured. A single score is a sample, not a value. If you have not measured how much your evaluator moves on unchanged text, you cannot tell a real 2-point improvement from a coin flip — the failure mode we walk through in how to test a prompt.
  • Exit codes that mean something. See above.
  • Findings, not just a verdict. A score tells you it got worse. A finding tells you which line.

None of that is hard to build. It is hard to keep — which is the actual reason homegrown scoring scripts end up unmaintained in a tools/ directory everyone has quietly agreed to ignore.

Put it in the pipeline

Once the command works in your terminal, it is one line in CI. That is exactly how we grade our own published skills — one job per skill, gated at 75, red build if any single one drops below the bar.

npx rubrkit test "skills/**" --remote --fail-under 80 --ci

Start with validate on save. Add --watch while you edit. Add the gate when you are ready to stop having the argument about whether the prompt got better.