Thanks for considering a contribution. This doc tells you exactly what helps, what doesn't, and how to land a PR fast.
- Pick a
good-first-issuefrom issues - Fork → branch → make change → add or update a test under
scripts/eval/tests/ - Run
npm test— it executes the complete deterministic local suite. - Open a PR with a one-line summary + before/after evidence
| Want | Don't want |
|---|---|
Bug fixes from documented boundaries in KNOWN_ISSUES.md |
Refactors with no observable behavior change |
| New check kinds (with a 3-case demo skill) | Features without a regression test |
Portability fixes (BSD/macOS, alpine/musl, alternate jq/yq versions) |
Bumping dependencies "just because" |
| Faster paths in the critical loop (lock, manifest, score) | New runtime dependencies; keep additions to the existing Bash, jq, and Python standard-library toolchain |
| Documentation that maps invariants to specific file:line | Documentation generated by an LLM with no examples |
| Audit reports that find new bugs (with reproducers) | Drive-by lint nits |
- The execution path is Bash + jq + OpenCode. Python standard library backs the yq fallback; Node is used only by repository documentation validation.
- The run adapter is OpenCode-specific. The grade command accepts content-addressed evidence from other runners and does not invoke a model.
- Honest failure modes: PASS, FAIL, ERROR, NEEDS_REVIEW, and INDETERMINATE are distinct. Missing evidence must not be represented as PASS or numeric zero.
- Product measurements stay in named dimensions; do not add an uncalibrated global score or claim causal attribution from hash co-occurrence.
- Shell entrypoints use set -euo pipefail and must work on the minimum supported Bash version.
- YAML schema changes are additive. New result, baseline, environment-manifest, and grading-manifest schemas require compatibility notes and boundary tests.
- Every behavioral change needs a consumer-visible regression test and an exercised smoke path. Product scoring needs measured/unavailable boundary coverage.
Product-quality measurements and harness-validity metrics are different records; see POLICY.md — Measurement boundaries.
# Full deterministic local suite
npm test
# One focused integration test
bash scripts/eval/tests/ab_compare.sh
# Dry-run the OpenCode adapter without spawning a model
EVAL_SKIP_AUTH_CHECK=1 eval-harness run --skill=omo-session-distiller --dry-runTests are bash scripts under scripts/eval/tests/. Each one is self-contained:
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
WORK="$(mktemp -d -t eval-harness-XXX.XXXXXX)"
trap 'rm -rf "$WORK"' EXIT
# ... arrange ephemeral state ...
# ... act (invoke the harness) ...
# ... assert ...
echo "PASS: <what was proven>"
exit 0Patterns to follow:
- Stub
opencodewhen you don't need a real LLM call (seeregression_inject.shfor the canonical stub) - Stub
curlwhen testingllm_judge(seellm_judge_unit.sh) - Set
EVAL_SKIP_AUTH_CHECK=1to bypass the API-key preflight in tests - Set
EVAL_STATE_DIR="$WORK/state"to keep state isolated per test - Set
OPENCODE_SKILLS_ROOT="$WORK/skills"to keep skill discovery isolated
- Shell: bash,
set -euo pipefail, prefer[[ ]]over[ ], quote everything, uselocalfor function vars - Avoid eval and shell execution of case input. The implicit-safe grader uses safe_shell.py with an argv allowlist; unsafe_shell: true explicitly opts trusted case YAML into bash -c.
- Comments only where load-bearing: complex algorithms, security boundaries, portability quirks. Self-documenting code over docstrings.
- One file = one concern. New libs go in
scripts/eval/lib/ - Cross-platform. Code must work on Linux + macOS (BSD coreutils). When in doubt, test both.
- Put grader-specific behavior in
scripts/eval/lib/extended_graders.sh; keep shared case/status aggregation inscore.sh. - Register the kind in
run_checkand define its required/optional, dimension, weight, and unavailable-evidence behavior. - Add deterministic positive, negative, malformed-input, and missing-evidence coverage where applicable; do not add an uncalibrated global score.
- Update autofix proposal handling only if the new kind can produce an actionable fix.
- Document the case contract in README, POLICY, the skill guide, and CHANGELOG; run
npm test.
mainis always green (every test inscripts/eval/tests/passes)- Features land on
feature/<vX.Y.Z>-<topic>branches - Releases happen via merge commit + annotated tag
vX.Y.Z+ GitHub Release - SemVer: PATCH for non-breaking fixes; MINOR for additive changes; 0.x MINOR releases may contain explicitly documented breaking changes with migration paths.
Open a new issue with:
- One-line summary — what's broken
- Reproducer — minimal case YAML / shell commands / env
- Expected vs actual — what should happen, what does
- Environment —
eval-harness --help | head -1,bash --version | head -1, OS
Bonus points if you can point to the file:line where you think it's broken.
KNOWN_ISSUES.mdfor the pinned bug list- GitHub Actions example; the composite action installs the harness from GitHub source.
KNOWN_ISSUES.mdfor documented operating and measurement boundariesCHANGELOG.mdfor what shipped when- Discussions for design questions
- Issues for bugs and feature asks
Forged in the regression furnace.