Hi — Journeyman's two-layer scoring (fact-counted events + a pluggable, qualification-gated judge) is one of the more carefully-specified agent evals I've read, so I wanted to flag a possible adapter rather than let it sit unnoticed.
I maintain EvalPort, an open interchange spec (TestCase/Grader/Result/ResultSet/GraderResult, Python + TS SDKs) for sharing eval data across frameworks without flattening the semantics that make each one worth using. I read journeyman/record.py, judge.py, rubrics.py, qualify.py and schema/report.schema.json on master before writing this, so the mapping below is against your actual types, not a guess:
| Journeyman |
EvalPort |
one cell (scene × seed) — record.py's {cell_id, scene, seed, messages, final_text, budget, events, verdicts, calls, tokens_in, tokens_out, seconds} |
TestCase (id, input) + its Result |
RubricItem (axis, question, verdicts tuple, positive, na_means) — scene.py |
Grader(type="llm_judge", id=axis, params={question, verdicts, positive, na_means}) |
a judge's per-axis verdict — judge.py's {"verdict", "positive", "na_means", "raw"} |
GraderResult(grader_id=axis, type="llm_judge", score, passed, reason=raw) |
report.json's {seal, judge, self_judged, axes, cost} |
ResultSet(suite_id, run_id, results, runner, summary, metadata) — seal and self_judged fit naturally under metadata |
A rough sketch, using the real SDK types:
from openeval.types import TestCase, Grader, Result, GraderResult
def cell_to_testcase(scene, seed, rubric_items):
return TestCase(
id=f"{scene.name}_s{seed}",
input=scene.task,
graders=[
Grader(id=item.axis, type="llm_judge",
params={"question": item.question,
"verdicts": list(item.verdicts),
"positive": item.positive,
"na_means": item.na_means})
for item in rubric_items
],
)
def cell_result(cell_record, verdicts):
grader_results = [
GraderResult(
grader_id=axis, type="llm_judge",
score=None if v["verdict"] == "na" and v["na_means"] == "not-applicable"
else float(v["verdict"] == v["positive"]),
passed=v["verdict"] == v["positive"],
reason=v["raw"][-300:],
metadata={"raw_verdict": v["verdict"]},
)
for axis, v in verdicts.items()
]
return Result(
test_case_id=cell_record["cell_id"],
passed=all(g.passed for g in grader_results),
grader_results=grader_results,
actual_output=cell_record["final_text"],
duration_ms=int(cell_record["seconds"] * 1000),
metadata={"events": cell_record["events"], "budget": cell_record["budget"]},
)
Two things make Journeyman a slightly unusual but I think good-fit source: (1) qualify.py's labelled calibration set (v2_real.json, 82 cases / seven axes) is already shaped like a graded TestCase + expected-label set — it could double as a portable conformance suite other judge-qualification tooling reuses, not just an internal fixture; (2) your na_means distinction (failure vs not-applicable) doesn't have a direct EvalPort field today, but maps cleanly into score=null (excluded, matching your own report schema's "score: null when every cell was not-applicable") vs score=0.0 — no spec change needed on our side.
For a concrete precedent of the "standalone adapter package, zero footprint on the target repo" shape, the closest thing in EvalPort today is deepeval-openeval-adapter — it maps DeepEval's per-metric MetricData (an LLM-judge-scored item, closer in spirit to your per-axis verdict than most adapters here) into GraderResult the same way sketched above.
Happy to build and maintain a journeyman-openeval-adapter myself if that's welcome — no ask for anything to change in this repo. Mostly wanted to check whether this mapping looks right to you before I did, since you know the na_means/precedence rules far better than I do from the outside.
— Sahi, independent contributor (not affiliated with this project)
Hi — Journeyman's two-layer scoring (fact-counted events + a pluggable, qualification-gated judge) is one of the more carefully-specified agent evals I've read, so I wanted to flag a possible adapter rather than let it sit unnoticed.
I maintain EvalPort, an open interchange spec (
TestCase/Grader/Result/ResultSet/GraderResult, Python + TS SDKs) for sharing eval data across frameworks without flattening the semantics that make each one worth using. I readjourneyman/record.py,judge.py,rubrics.py,qualify.pyandschema/report.schema.jsononmasterbefore writing this, so the mapping below is against your actual types, not a guess:scene×seed) —record.py's{cell_id, scene, seed, messages, final_text, budget, events, verdicts, calls, tokens_in, tokens_out, seconds}TestCase(id, input) + itsResultRubricItem(axis,question,verdictstuple,positive,na_means) —scene.pyGrader(type="llm_judge", id=axis, params={question, verdicts, positive, na_means})judge.py's{"verdict", "positive", "na_means", "raw"}GraderResult(grader_id=axis, type="llm_judge", score, passed, reason=raw)report.json's{seal, judge, self_judged, axes, cost}ResultSet(suite_id, run_id, results, runner, summary, metadata)—sealandself_judgedfit naturally undermetadataA rough sketch, using the real SDK types:
Two things make Journeyman a slightly unusual but I think good-fit source: (1)
qualify.py's labelled calibration set (v2_real.json, 82 cases / seven axes) is already shaped like a gradedTestCase+ expected-label set — it could double as a portable conformance suite other judge-qualification tooling reuses, not just an internal fixture; (2) yourna_meansdistinction (failurevsnot-applicable) doesn't have a direct EvalPort field today, but maps cleanly intoscore=null(excluded, matching your own report schema's"score: null when every cell was not-applicable") vsscore=0.0— no spec change needed on our side.For a concrete precedent of the "standalone adapter package, zero footprint on the target repo" shape, the closest thing in EvalPort today is deepeval-openeval-adapter — it maps DeepEval's per-metric
MetricData(an LLM-judge-scored item, closer in spirit to your per-axis verdict than most adapters here) intoGraderResultthe same way sketched above.Happy to build and maintain a
journeyman-openeval-adaptermyself if that's welcome — no ask for anything to change in this repo. Mostly wanted to check whether this mapping looks right to you before I did, since you know thena_means/precedence rules far better than I do from the outside.— Sahi, independent contributor (not affiliated with this project)