Common questions about the rf-skill-eval harness and its CI
integration. For setup see usage.md; for pre-push
workflow see local-testing.md.
- Why can't I use Opus?
- My workflow ran out of rate limit, what now?
- Does this send my code to Anthropic?
- How do I trigger the canary manually?
- The PR comment says a metric regressed — how do I debug?
- Can I run this without a paid Claude subscription?
- How do I rotate my OAuth token?
- What's the difference between narrow / realistic / adversarial tiers?
- Where are historical results stored?
- Why is rf-mcp required?
Three reasons, in order of importance:
- Cost. Opus is roughly 5× Sonnet and 25× Haiku per token. A single weekly canary on Opus would exceed the maintainer's subscription budget and force a move to per-token billing.
- Variance masking. Skill effects are measured as δ (Cliff's delta) between control and treatment arms. Opus's higher baseline capability compresses this delta — a skill that genuinely helps Haiku may look neutral on Opus because Opus would have solved the task anyway.
- Rubric calibration. The gating thresholds
(
|δ| ≥ 0.33medium-effect, +30% token budget) in ADR-004 are calibrated against Haiku/Sonnet behavior. Opus metrics would not be comparable without re-baselining the entire rubric.
The CLI rejects --model claude-opus-... at argument parse time. If
you believe Opus coverage is justified, open an ADR rather than
patching the allow-list.
The OAuth subscription path shares a 5-hour rolling window with the maintainer's interactive Claude Code sessions. When it is exhausted you have four options, ordered from least to most disruptive:
-
Wait and re-run. The window resets on a rolling basis. Use
claude usagelocally or re-run the workflow after a few hours. -
Schedule off-hours. The weekly canary is already scheduled for 04:00 UTC Sunday to minimize collision. For ad-hoc PR runs, push late in the day and retry in the morning.
-
Reduce concurrency. The matrix is already capped at
max-parallel: 1–2for OAuth auth (ADR-005). If you locally raised it, lower it back. -
Switch to API-key auth for the run. Re-dispatch the workflow with
use_api_key=true:gh workflow run skill-evaluation.yml -f use_api_key=true
API keys bill per token but have no 5-hour cap. This is the designed escape hatch for overflow runs.
For PRs from forks, the API-key path is automatic — repo secrets (including the OAuth token) are not exposed to fork-triggered runs by GitHub default, and the workflow falls back to the API key.
Yes. The harness drives claude -p subprocesses. Prompts, tool
calls, file contents read by the agent, and test outputs observed by
the agent all traverse Anthropic's API — identical to running
Claude Code interactively.
This means:
- Do not include production secrets in your test fixtures. Use
placeholder credentials in
eval/fixtures/sut-*/. - The
sut-browserfixture's demo app runs onlocalhost; the page text seen during test execution is sent along with the session. Review fixture content before committing. - Session JSONLs captured under
eval/runs/contain the agent's view of your code. Artifact retention is 30 days (PR) and 365 days (canary) inside GitHub Actions.
See Anthropic's data-handling policy: https://www.anthropic.com/legal/privacy
The harness does not add any additional telemetry beyond what
Claude Code itself sends. If a specific fixture contains sensitive
content, mark its task YAML skip_in_ci: true and run it only
locally.
The weekly canary runs all three tiers with N=8 replicates. To run
it on-demand:
gh workflow run skill-evaluation.yml -f tier=canaryTo run it with API-key auth (avoids the subscription window):
gh workflow run skill-evaluation.yml \
-f tier=canary -f use_api_key=trueWatch progress:
gh run list --workflow=skill-evaluation.yml --limit 5
gh run watchFull-canary runs take up to four hours on subscription auth. Schedule accordingly.
Step-by-step:
-
Read the scorecard. The PR comment lists the regressing metric, the δ, and the 95% CI. Confirm the CI excludes zero — a wide CI that crosses zero is noise, not a real regression.
-
Download the artifacts from the failing run:
gh run download <run-id> --dir /tmp/eval-artifacts
Artifacts include every matrix cell's
runs/<cell_id>/plus the aggregatedscorecard/directory. -
Open the HTML scorecard:
xdg-open /tmp/eval-artifacts/scorecard/scorecard.html
Scroll to the "Failure Gallery" section — it shows the two or three worst individual sessions for the regressing metric with links to their session JSONL.
-
Inspect the session JSONL for a failing cell:
jq -c 'select(.type == "tool_use" or .type == "user") | {turn: .turn_idx, tool: .name, text: .text}' \ /tmp/eval-artifacts/run-<cell>-treatment/session.jsonl
-
Reproduce locally:
uv run rf-skill-eval run \ --task eval/tasks/<tier>/<task>.yaml \ --arm treatment \ --log-level DEBUG
See local-testing.md for the full debug loop.
-
If it reproduces, fix the skill. If it does not reproduce (three local runs all pass), the regression is flaky — file an issue tagged
flaky-evaland retry the PR run. Per ADR-005, CI does not auto-retry failed cells; a single failure is valid data.
Yes, via the ANTHROPIC_API_KEY fallback. Every token is billed
per-call (no subscription flat rate), but the harness works
identically otherwise.
Locally:
# In .env, comment out CLAUDE_CODE_OAUTH_TOKEN and uncomment:
ANTHROPIC_API_KEY=sk-ant-api03-...In CI (fork PRs automatically use this path, since repo secrets are not injected into fork-triggered runs):
gh workflow run skill-evaluation.yml -f use_api_key=trueThe workflow reads ANTHROPIC_API_KEY from repo secrets in this
mode. For a one-off run, the maintainer can temporarily add a
dedicated API key as a repo secret and remove it after.
Cost expectations are in usage.md. A full weekly canary on API-key billing is roughly $6 (Haiku) or $30 (if Sonnet is in the matrix).
OAuth tokens expire roughly one year after issuance. Rotate annually or immediately on suspected compromise.
claude setup-tokenCopy the new sk-ant-oat01-... value.
sed -i 's/^CLAUDE_CODE_OAUTH_TOKEN=.*/CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-NEW/' .envgh secret set CLAUDE_CODE_OAUTH_TOKEN --body "sk-ant-oat01-NEW"Visit https://console.anthropic.com/ and revoke the previous OAuth token from your account's authorized applications list.
uv run rf-skill-eval doctor
gh workflow run skill-evaluation.yml -f tier=smokeThe workflow-start check in install-claude-code should report
"token valid, expires in ~365 days".
Repo maintainers should keep an annual reminder (GitHub issue auto-opened ~11 months after last rotation, per ADR-005).
| Tier | Duration | Shape | Gating? |
|---|---|---|---|
narrow |
~5 min each | Single skill, single file, one behavior | Yes (PR) |
realistic |
~20 min each | Multi-step, multi-file, real-work simulation | Yes (merge) |
adversarial |
~10 min each | Deliberately tempts known failure modes | Reported-only in v1 |
- Narrow tasks isolate one skill's effect. Most skill PRs only exercise narrow tasks in CI.
- Realistic tasks evaluate skills under representative work.
They gate merges to
mainbut do not gate PRs. - Adversarial tasks test whether a skill prevents specific anti-patterns (e.g., "just make the test pass" when the correct fix is in the product). In v1 their metrics are reported but do not gate ship — see ADR-004 "Anti-gaming for the grader".
Full tier definitions and task-authoring guidelines:
eval/tasks/README.md.
Three layers, each answering a different question:
-
GitHub Actions artifacts (retention: 30 days PR, 365 days canary). Raw session JSONL, hook logs, per-cell
scorecard.json. Use for debugging a specific regression; download withgh run download. -
SQLite + Parquet trend database, committed to the orphan
eval-historybranch after every canary run. One row per(run_id, skill_id, metric_id, arm). Use for longitudinal analysis and baseline computation.git fetch origin eval-history git show origin/eval-history:trends.db > /tmp/trends.db sqlite3 /tmp/trends.db "SELECT skill_id, metric_id, AVG(value) FROM trends WHERE timestamp > date('now','-30 day') GROUP BY 1, 2;"
-
30-day rolling baselines, computed on the fly from the trend DB by
rf-skill-eval baselines. The gating rule in ADR-004 compares current-run metrics against these baselines.
Full persistence design: ADR-006.
rf-mcp is the Model Context Protocol server that exposes Robot
Framework test execution as tool calls to the agent. Several skills
(notably testcase-builder, results-analysis) rely on it for
their primary value proposition: letting the agent run the test
it just wrote before claiming the task is done.
The executed_before_complete primary metric directly counts
rf-mcp tool calls. Without rf-mcp, that metric is always zero,
treatment arms look no different from control, and the skill's
effect is invisible to the rubric.
See skills/README.md for the rf-mcp
setup that the harness expects. The harness itself installs rf-mcp
into each per-arm profile during invocation; contributors do not
need to install it globally.