create-skill-test — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited create-skill-test (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 7 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 7 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Scaffold an evaluation spec (eval.yaml) for a skill, agent, or workflow package so it conforms to the Vally schema, passes skill-validator check and check_eval_quality.py, is powerful enough to return a verdict, and does not overfit to the skill's own wording.
eval.yaml for a skill, agent, or workflow packageimprove-skill-qualitySKILL.md files — use create-skill| Input | Required | Description |
|---|---|---|
| Skill or agent name | Yes | Must exist under plugins/<plugin>/skills/ or plugins/<plugin>/agents/ |
| Plugin name | Yes | e.g. dotnet-msbuild |
| Skill content | Yes | Read it — you cannot write non-overfitted rubric items without it |
| Scenario hypothesis | Yes | State the expected improvement for a preference case, or the invariant protected by a guard |
| Failure modes to discriminate | Recommended | Each becomes one distinct stimulus |
Before writing YAML, state what the stimulus proves. A preference stimulus is necessary when the target should improve the answer, action, restraint, or validation result compared with the same model without the target. A non-voting activation contract or no-op guard is necessary when it protects a meaningful invariant, even if correct behavior is baseline-equivalent.
Do not add a stimulus when it measures:
disable-model-invocation: true reference skill in isolation.Map each proposed case to capability, risk, and customer journey tags. Preference cases must add distinct voting value. Activation contracts and no-op guards may share a capability when they protect a separate routing or preservation invariant. If two cases have the same inputs, expected outcome, failure mode, and grader path, keep the stronger one. The five-stimulus floor never justifies padding.
Then locate the target and test directory:
tests/<plugin>/<skill-name>/eval.yaml # skills
tests/<plugin>/agent.<agent-name>/eval.yaml # agents (the agent. prefix disambiguates)
tests/agentic-workflows/<package>/eval.yaml # redistributable gh-aw packagesVerify the target exists at plugins/<plugin>/skills/<skill-name>/SKILL.md or plugins/<plugin>/agents/<agent-name>.agent.md, and read it.
Agent evals use the native SDK agent lane. Vally 0.14 cannot register custom agents, so agent.* specs do not run through the skill experiment. The evaluation workflow discovers them separately, runs the target agent through skill-validator evaluate, and adapts that evidence into the same schema-versioned result and dashboard pipeline. The distinct-stimulus floor applies to both skill and agent evals.
Be careful with a skill that sets `disable-model-invocation: true`. The model cannot invoke it, so the skill is absent from the model-facing skilled arm and any direct eval compares two identical arms. Answer-content graders do not create a difference between those arms. The honest coverage for such skills is dependency-level — through the outcome evals of the skills that load them, and through the plugin arm. For example, filter-syntax is covered by the filtered-command scenarios in tests/dotnet-test/run-tests/eval.yaml.
The spec is Vally format. Every eval in this repo uses stimuli: and graders:; scenarios: and assertions: are a pre-Vally format that no longer loads.
name: <skill-name>
description: Evaluates the <plugin>/<skill-name> skill
type: capability
defaults:
timeout: 5m
runs: 1
stimuli:
- name: <what the agent must accomplish>
prompt: <natural developer request>
tags:
capability: <distinct-capability>
risk: <failure-being-prevented>
journey: <customer-task>
environment:
files:
- src: fixtures/<case>/Project.csproj
dest: Project.csproj
graders:
- type: output-matches
config:
pattern: (root cause|underlying issue)
- type: exit-success
- type: prompt
rubric:
- <outcome the agent should have reached>Use `defaults:` only.config:is a deprecated alias that the repository gate rejects. Vally warns when the alias appears alone and throws when a spec declares both keys. Replaceconfig:with onedefaults:block and preserve its settings.
The gate gives each distinct stimulus one vote. Repeated runs for one stimulus collapse to one majority-direction vote and remain available as reliability evidence.
underpowered — never a pass, never a regression.discarded; they hold the discordant count down.
| discordant stimulus votes | records that pass | p |
|---|---|---|
| ≤ 4 | none | ≥ 0.0625 |
| 5–7 | zero losses only (5W/0L) | 0.031 |
| 8 | one loss survivable (7W/1L) | 0.035 |
At exactly 5 stimuli, one tie is fatal because it leaves 4 discordant votes. At 6 stimuli one tie is survivable; at 7, up to two are. A loss is not. Five is an eligibility floor, not adequate power. For example, 80% power needs 8 discordant votes only for a true 90% conditional win rate; it needs 18 at 80%, 37 at 70%, and 158 at 60%. Size for the effect and tie rate you need to detect.
Use runs for reliability, not task breadth. Vally recommends 3 runs in CI and 5–10 nightly for pass rate, pass@k, pass^k, and flakiness. Extra runs never clear the five-stimulus floor.
Do not set runs in dotnet-skills.experiment.yaml; experiment overrides overwrite every eval's own value rather than defaulting it.
cued prompts inflate the overfit score and bias the baseline.
property give arithmetic, not evidence.
capability, risk, and journey tags. Use stablelowercase kebab-case values. A useful portfolio crosses distinct rows or columns in that matrix; it does not repeat one journey with cosmetic wording changes.
name. Vally pairs comparison trajectories by(stimulus name, trial index); duplicate names make slot identity ambiguous.
leaves already-correct input alone.
already-correct input; dormancy proves the target stays inactive on an off-target request.
environment:
files:
- src: fixtures/broken-build/App.csproj # path relative to eval.yaml
dest: App.csproj # path in the agent's working directory
- src: fixtures/broken-build # a directory
dest: .
commands:
- dotnet build -bl || exit 0 # guard intentional failuresDo not set `environment.skills` in a skill eval. The experiment declares vary: /environment/skills and supplies the value itself — [] for the baseline arm and plugins/<plugin>/skills/<skill> for the skilled arm — so anything the eval declares is replaced, in every arm. It cannot add a skill to one arm only. environment.skills is meaningful in an agent.* eval; the native agent lane loads those entries only in the isolated target run, while the plugin run loads the production plugin's complete skill surface. Copy the shape from an existing agent eval such as tests/dotnet-test/agent.test-quality-auditor/eval.yaml rather than reproducing a remembered form — the specs in this repo are not consistent about how they spell those entries.
Fixture rules — each one has already cost a real result:
.gitignore (e.g. coverage*.xml) hassilently swallowed a committed fixture: the eval passed locally and failed at setup in CI. Verify with git ls-files, not by looking at the working tree.
fixture meant to be broken must fail for the exact reason the stimulus is about, and no other. Judges penalize agents for unrelated "pre-existing build issues" that the fixture author introduced.
scores well and the skill has nothing to add.
line-rate, summary totals (lines-covered/lines-valid), and <line> elements disagree lets the two arms read different truths, and the loss is the fixture's fault. Update any rubric item or prompt that quotes a figure in the same change.
n; rename leftovers add trials without evidence.(|| exit 0), or vally drops the trial.
SKILL.md — the stagedskill lives there, and deleting it aborts only the skilled arm.
preservation, snapshot or compare every in-scope file, not one representative file. A grader that checks only the main output can miss deletion, truncation, or edits to sibling files.
Graders are hard pass/fail checks evaluated on every arm.
| Type | Required config | Purpose |
|---|---|---|
output-matches / output-not-matches | pattern | Regex over agent output |
output-contains / output-not-contains | substring | Literal text in output |
file-exists / file-not-exists | path | Glob against the work directory |
file-contains / file-not-contains | path, value | Content of a produced file |
run-command | command (plus optional expected_exit_code, timeout, stdout_matches) | Verify produced code actually builds/runs |
exit-success | — | Agent produced non-empty output |
prompt | — | Runs the LLM judge against the rubric |
Rules:
config is absent or missing its required key parses fine and enforces nothing.The usual cause is an indentation slip during an edit; check_eval_quality.py blocks it.
(root cause|primary error|underlying issue).
Recommendation: line can silently stop doing so while the eval still passes.
file-not-contains / file-not-exists to prove the agent avoided an incorrect action.Define the deterministic contract before writing the prompt grader:
golden_patch, if any. The goldenworkspace and final golden_trajectory response must pass every deterministic grader that applies to them.
missing file, zero discovered tests, an out-of-scope edit, or a changed semantic value. The relevant deterministic grader must fail.
partial artifact because one positive substring exists.
Use golden_patch for replayable workspace state and golden_trajectory for the expected final response. A narrated edit, build, or test is not proof: completion claims need a patch or a run-command grader that replays the evidence.
Rubric items are judged pairwise (baseline vs. skilled). The overfitting judge classifies each item:
| Classification | Description | Goal |
|---|---|---|
| outcome | Whether the agent reached a correct result — WHAT, not HOW | Target this |
| technique | Whether the agent used a skill-specific procedure | Minimize |
| vocabulary | Whether the agent used the skill's terminology | Avoid |
binlog using dotnet build /flp".
SKILL.md phrasing.does this measures nothing and inflates the overfit score.
Good:
rubric:
- Correctly identified the missing NuGet package as the root cause of the build failure
- Recognized that downstream failures cascaded from that root cause
- Suggested a concrete fix that resolves itOverfitted:
rubric:
- Replayed the binary log using 'dotnet build /flp:v=diag' # technique
- Measured cold, warm, and no-op build scenarios # vocabulary
- Used the template-comparison skill # rewards activationconstraints:
expect_tools: [bash]
reject_tools: [edit, create]
reject_skills: [some-skill]expect_tools: [bash] on an advisory question forces a restore or build and converts ananswer into a timeout with no quality benefit. Only require tools when the task genuinely needs them.
reject_tools is the right way to keep a read-only stimulus read-only.A dormancy guard proves the skill stays dormant on an off-target request that superficially matches it. Add one per real "when not to use" boundary: wrong input format, out-of-scope request, incompatible project type, wrong framework version, prerequisite absent.
- name: Decline dump analysis request
prompt: |
I already have a .dmp crash dump from my .NET app. Can you help me
analyze it to find the root cause of the crash?
expect_activation: false
graders:
- type: output-matches
config:
pattern: (out of scope|not cover|does not|cannot|only.*collect)
- type: prompt
rubric:
- Stated that dump analysis is out of scope
- Did not open or analyze the dump file
- Did not install analysis tools such as dotnet-dump analyze, lldb, or windbg
- Suggested the correct alternativeNever combine `expect_activation: false` with `constraints.reject_skills`. That forces the skilled arm to run skill-free, so the harness cannot observe whether the target skill hijacks the request. The comparison remains visible as report-only evidence but does not vote in preference; unexpected isolated activation blocks a pass. expect_activation: false alone is the repo convention.For a package target, verify agentic-workflows/<package>/aw.yml, then read its entry workflow, local imports, and bundled agents. The native SDK lane evaluates their real prompt bodies and installed resources against offline fixtures. Specify collector outputs, revision/tracking evidence, and service responses as fixture inputs; propose terminal actions in result.json rather than pretending to publish through live GitHub or safe-output tools. Assert the structured result with deterministic graders. Do not place expected answers in agent-readable fixtures or staged grader scripts; pass expected values through grader argv.
Prompt expressions are rendered from a flat workflow-context.json fixture, whose keys are exact trimmed expressions and values are strings. Missing context fails setup. A workflow that correctly chooses noop is still expected-active decision evidence, not expect_activation: false routing evidence. Include normal, partial, stale, incompatible, missing-evidence, and multi-module cases where applicable. Keep compilation, helper execution, and actual consumer publication tests separate: this lane is labeled workflow-prompt-sdk, not end-to-end Actions execution.
dotnet run --project eng/skill-validator/src/SkillValidator.csproj -- evaluate `
agentic-workflows/<package>/aw.yml `
--tests-dir tests/agentic-workflows --runs 1 --verdict-warn-onlyGuard rubrics verify three things: recognition (why it does not apply), restraint (no workflow, no file changes, no installs), redirection (the correct next step).
dotnet run --project eng/skill-validator/src/SkillValidator.csproj -- check --plugin ./plugins/<plugin>
python eng/eval-quality/check_eval_quality.py
./eng/run-skill-evals.sh <plugin> <skill-name>For an agent eval, exercise the native lane directly:
dotnet run --project eng/skill-validator/src/SkillValidator.csproj -- evaluate \
plugins/<plugin>/agents/<agent>.agent.md \
--tests-dir tests/<plugin> \
--runs 1 \
--verdict-warn-onlyCI adapts this result through eng/vally-adapter/adapt-agent-results.mjs, which applies the same distinct-stimulus sign-test policy used by skill results.
Validation must cover four layers:
check_eval_quality.py and the relevant checker self-tests whenthe checker changes.
point. For agent evals, run skill-validator evaluate to prove the native SDK lane accepts the executable scenario fields. That parser does not read golden_trajectory or golden_patch, so validate the references separately: run check_eval_quality.py, then materialize the fixture, apply the golden patch, and run every applicable deterministic file and command grader against the golden workspace. Confirm the final golden response passes its output graders.
defaults.timeout.Do not certify an eval only with one worker or a larger ad hoc time budget. If normal concurrency exposes a race or timeout, classify it as reliability evidence.
family and one Claude family executor. Report each result separately. Different executor or judge families do not increase the independent stimulus count.
check_eval_quality.py blocks 22 structural defect classes that can corrupt a result: missing or untracked fixtures, self-contradicting coverage fixtures, empty grader configs, dormancy guards with reject_skills, sub-floor stimulus counts, duplicate YAML keys or stimulus names, and invalid defaults, tags, golden evidence, test commands, or ATIF trajectories. See eng/eval-quality/README.md for the complete list. Do not add a new eval to eng/eval-quality/underpowered-allowlist.txt — the gate rejects allowlist entries that are new relative to the base branch.
For the official run, submit a PR review containing /evaluate so it binds to the reviewed commit.
tests/<plugin>/<skill-name>/ or tests/<plugin>/agent.<agent-name>/stimuli: / graders: and the current defaults: settings blockcapability, risk, and journey tags and a unique namegit ls-filesconfig keyexpect_activation: false aloneskill-validator check and check_eval_quality.py pass| Pitfall | Solution |
|---|---|
Writing scenarios: / assertions: | That format no longer loads; use stimuli: / graders: |
Using the deprecated top-level config: alias | Rename it to defaults: and preserve its settings |
| Landing an eval at exactly 5 stimuli | A single tie makes a pass unreachable; size for the effect and tie rate |
Raising runs to clear the floor | Repeats measure reliability for one task; add stimuli |
| Prompt mentions the skill or agent by name | Rewrite as a natural developer request |
| Rubric rewards using the skill | Drop the item — the harness reports activation separately; rubrics measure outcomes |
| Fixture present but ignored by git | Verify with git ls-files; CI setup will fail otherwise |
| Fixture that does not build, or breaks for the wrong reason | Fix the fixture before blaming the skill |
Dormancy guard with reject_skills | Use expect_activation: false alone |
expect_tools: [bash] on an advisory question | Drop it; it causes timeouts, not quality |
| Timeout too short for code generation | Use ~360s; empty output fails every grader |
| Duplicate YAML key left behind by an edit | It overwrites the next stimulus field by field — delete the stray block |
| Duplicate stimulus names | Vally uses names as comparison identity — give every stimulus a stable, unique name |
Direct eval for a disable-model-invocation: true skill | Remove it and cover the reference through consumer outcomes |
| Agent eval below the stimulus floor | The native agent adapter uses the same sign-test gate; add independent preference-eligible stimuli |
Agent eval "run" with ./eng/run-skill-evals.sh | That helper remains skill-only; use skill-validator evaluate |
Agent eval missing environment.skills | Declare the skills the agent routes to, or it cannot invoke them |
environment.skills set in a skill eval | The experiment varies that key and replaces it in every arm; the declaration does nothing |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.