eval-create
Skill0 starsChanged 11 days agoApache-2.0View on GitHub
Designs, writes and manages Google ADK eval cases. Covers the case taxonomy (happy path, edge and refusal, adversarial, memory, regression, resume from seeded state), how many cases a suite needs and of what shape, naming, capturing a golden trace from a real run or a saved session, converting `adk run --jsonl` output into an eval case, migrating legacy eval files (both legacy shapes) to the current schema, multi-turn context retention tests, closing coverage gaps branch by branch, and curating an existing suite: list, rename, move, split, remove and dedupe cases, rebase the app name, and the dev-UI and `adk eval_set` flows. Use when asked to "write/add/generate eval cases", "capture a golden trace", "turn this session into a test", "add a regression case", "test that it refuses", "test whether it remembers", "migrate my old .test.json", "rename / delete / dedupe eval cases", or "clean up my evalset". Don't use to pick metrics or rubrics (use `/adk:eval-criteria`), to validate files without changing them (use `/adk:eval-review`), to run evals (use `/adk:eval-run`), or to set up simulated users (use `/adk:eval-simulation`).
In this repository10 other files it gives its agents.
- adkSkill
- agent-createSkill
- agent-debugSkill
- agent-reviewSkill
- eval-analyzeSkill
- eval-ciSkill
- eval-criteriaSkill
- eval-reviewSkill
- eval-runSkill
- eval-simulationSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 81
One behavioural concern per case: If naming what it proves needs an "and", it is two cases.
- Very specific: line 87
A forbidden call needs no special syntax: Write the trajectory that should happen — which stops before the forbidden call — and let exact …
- Very specific: line 97
Never edit an existing case to make a run pass: Every writer here refuses to overwrite an eval_id.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Write and manage ADK eval cases
An eval case says: given this input, the agent should do these things, in this order, with these values. Writing them well is mostly about scope — one behaviour per case — and about covering the branches the instruction actually has, rather than the one path someone demonstrated. Keeping a suite good over time is the same discipline applied to renames, splits and deletions.
${CLAUDE_SKILL_DIR} is this skill's directory.
Flow
Discover. What the agent can do, what is already covered, where the gaps are:
python3 ${CLAUDE_SKILL_DIR}/../adk/scripts/discover.py <agent-dir> --focus layout,agent,evalsets,configs,coverage python3 ${CLAUDE_SKILL_DIR}/../eval-review/scripts/coverage_matrix.py <agent-dir> python3 ${CLAUDE_SKILL_DIR}/scripts/manage_cases.py list <agent-dir> --by-categoryThe coverage matrix names the specific uncovered branches, which is what the new cases should be. The list shows what a suite already asserts.
- Report. Tools and their argument contracts, existing cases by category,
the branch count against the case count, the uncovered rules by name, and
anything the suite carries that it should not (duplicates, vague ids, a stale
app_name). - Options. Usually: close the branch gaps, capture a golden trace from a real run, add the missing adversarial or memory layer, migrate a legacy file, add a regression case for a bug just fixed, or tidy the suite (rename, split, dedupe). All free.
- Confirm, then generate with
--dry-run, show the write plan, write, and validate with/adk:eval-review's scripts. An explicit prior grant from the user ("proceed without asking") satisfies this step; the plan is still shown.
The categories
| Category | Proves | Id prefix |
| happy | the unobstructed path works end to end | happy_ |
| edge | each branch stops where it should, including "ask, don't guess" | edge_ |
| adversarial | pressure, claimed authority and tempting-but-valid data do not change the decision | adversarial_ |
| memory | a constraint stated once survives intervening turns | memory_ |
| regression | a fixed bug stays fixed | regression_ |
| activation | a skill-equipped agent loads the right skill, not its sibling, and none for an unrelated request | activation_ |
| resume | a stateful agent, started from seeded session_input.state, holds at an unmet gate or proceeds from the recorded step | resume_ |
Roughly 70% narrow single-turn cases, 20% multi-turn, 10% adversarial. Weight adversarial higher for an agent that spends money or writes to a system of record. A baseline case with no tools bound proves the agent degrades honestly instead of inventing capabilities.
Decision rules
- One behavioural concern per case. If naming what it proves needs an "and",
it is two cases;
manage_cases.py splitturns one into several. - N branches need N+1 cases. One per conditional or prohibition in the instruction, plus the happy path. The coverage matrix counts them for you.
- At least one case must be a refusal. A suite of happy paths cannot detect an agent that approves everything.
- A forbidden call needs no special syntax. Write the trajectory that should
happen — which stops before the forbidden call — and let exact matching do the
work. Add a restraint rubric via
/adk:eval-criteriato say it in words too. - Assert on arguments, not just names. The right tools in the right order with the wrong claim id is a broken agent that a name-only check passes.
- Name the behaviour in the id. The id is what a person reads first when a
run goes red;
edge_frozen_cost_centre_no_submittells them what broke before they open the file,test_3does not. - Leave
final_responseempty when only the trajectory matters. Withresponse_match_scoreat 0, an empty expected answer is deliberate. - Never edit an existing case to make a run pass. Every writer here refuses
to overwrite an
eval_id. Change a case deliberately, with the reason recorded, throughmanage_cases.py, and re-capture rather than hand-edit. - Every turn of a multi-turn case must get a reply. Through 2.13.0 a turn
the agent answers with no event aborts the whole
adk evalrun and scores no case. If the agent may legitimately stay silent there, give it a fallback reply or end the case before that turn. - A skill pair needs a negative sibling case. A request meant for skill A
must load A and not B, worded the way B's description is (
AGT083flags the riskiest pairs). - Capture only runs you have read. A golden trace of the agent doing the wrong thing locks in the wrong thing.
- Legacy files come in two shapes. The wrapped shape still runs under
adk eval; the flat-turn shape crashes it and onlyAgentEvaluatorreads it. Migrate both for a stable id and a readable diff.
Capturing a golden trace
adk run <agent-dir> --jsonl "the request to record" > /tmp/run.jsonl
python3 ${CLAUDE_SKILL_DIR}/scripts/session_to_evalset.py --trace /tmp/run.jsonl \
--eval-id happy_travel_claim --evalset tests/eval/evalsets/happy.evalset.jsonWithout --jsonl, adk run prints text only and every tool call is invisible.
The dev UI does the same conversion: adk web, run the request, then Eval → add
the current session. That tab also edits and deletes cases and runs them with
threshold sliders; see managing-evalsets.md.
References
| Question | File |
| Choosing categories, sizing a suite, the branch rule | case-taxonomy.md |
| Every field of an eval case, with worked examples | evalset-schema.md |
| Capturing, converting and trusting golden traces | golden-traces.md |
| Designing context-retention tests | memory-tests.md |
| Adversarial cases and trap fixtures | adversarial-cases.md, trap-mocks.md |
Curating a suite: dev UI, adk eval_set, GCS, frozen suites, versioning, recipes EVAL.yaml | managing-evalsets.md |
| Behavioural assertions in pytest, one failure mode at a time | behavioral-tests.md |
| Activation cases for an agent with ADK skills | skills-and-progressive-disclosure.md |
Templates: assets/templates/evalsets/ — one per category (including
activation.evalset.json, a positive and a negative skill-load case, and
resume.evalset.json, a hold-at-gate and a proceed-from-step case seeded with
state), a baseline no-tools case, and a scenario case.
Scripts
| Command | Does | Exit codes |
scripts/gen_cases.py <agent-dir> --spec JSON (--evalset F | --new ID) [--dry-run] | adds cases, refuses to touch existing ids; a {"skill": "name"} entry in a turn's tools, or "skill": "name" on the turn (loaded first), becomes load_skill with {"skill_name": "name"}, prefixed when the toolset sets tool_name_prefix; activation_* ids land in the activation category; "state": {...} on a case seeds its session_input.state (resume cases, simulated idle time) | 0, 1 findings or clash, 2 usage |
scripts/session_to_evalset.py --trace F --eval-id ID --evalset F [--drop-final-response] | turns a run into a case | 0, 1 findings, 2 usage |
scripts/migrate_legacy.py <old.test.json> [--out F] [--eval-set-id ID] | either legacy shape to the EvalSet schema | 0, 1 findings, 2 usage |
scripts/manage_cases.py list|show|rename|move|remove|dedupe|split|rebase-app-name ... [--evalset F] [--dry-run] [--registry F] [--unfreeze] | curates an existing suite through a write plan; refuses to remove, rename, move (either end), split, dedupe --apply or rebase a case in a "frozen": true suite (EVS120, read from --registry or the nearest eval_registry.json) unless --unfreeze; adding cases to a frozen suite is allowed | 0, 1 refused, 2 usage or frozen |
Completion checklist
- Every new case has one concern and a descriptive
eval_id. - Each uncovered branch named by the coverage matrix now has a case, or was consciously left.
- At least one case in the suite is a refusal.
- Arguments are asserted, not just tool names.
session_input.app_namematches what the agent resolves to.- No existing case was modified without the user deciding it.
validate_evalset.pyandcrosscheck_tools.pyexit 0.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

