* Make Vally the sole LLM eval engine, retiring skill-validator evaluate Collapses the parallel skill-validator + Vally eval pipeline into a single Vally-only path while preserving every capability skill-validator provided: PR gate, PR comment, dotnet/skills-data historical push, and the dashboard. The skill-validator `check` linter is retained (skill-check.yml) pending microsoft/vally #463. - evaluation.yml: delete build-validator and the skill-validator `evaluate` job; single `evaluate:` job now uses vally-evaluation.yml. Forward the COPILOT_PAT_0..9 pool onto it (from #911) so the reusable workflow's token gate is satisfied. Rewire comment-on-pr / report-status / publish-* / deploy-dashboard onto `evaluate` and vally-results-* artifacts. - vally-evaluation.yml: pin @microsoft/vally-cli@0.9.0; keep the #911 prepare guard; write the generated per-plugin experiment to $GITHUB_WORKSPACE so relative eval globs resolve. - adapt.mjs: reconcile #887's runCompareWithRetry + conclusive/unmatched hardening with the consolidation helpers (nonActivation, compareByStim, roleToDashboard, etc.). Add consolidate.mjs and gen-experiment.mjs. - build-replay-sessions.ps1: read Vally executor-session-logs/events.jsonl instead of skill-validator session output. - Rename all tests/*/*/eval.vally.yaml to eval.yaml (Vally format is now the only eval format); author Vally evals for the four skills that lacked one. - CONTRIBUTING.md + InvestigatingResults: point contributors at the Vally harness; drop non-public links. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix setup-local-sdk eval for Vally schema The hand-authored setup-local-sdk eval used skill-validator grader/environment schema that Vally rejects at validation (no stimuli executed): - file-contains/file-not-contains graders require 'value:' not 'substring:' (output-contains correctly keeps 'substring:'). - environment.files entries require 'src:'/'dest:' (copy a fixture) rather than inline 'path:'/'content:'. Moved the global.json body into fixtures/global.json. Verified with 'vally lint --eval-spec' (0 errors) across all 97 eval.yaml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix markdownlint violations in migration docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback on eval migration - Consolidate run-vally-evals.sh into a single neutral entrypoint eng/run-skill-evals.sh (deletes the thin wrapper; adapt.mjs stays in eng/vally-adapter/ since CI invokes it directly) - Rename reusable workflow vally-evaluation.yml -> evaluation-run.yml and update all references/self-trigger regexes - Rename local output dir vally-results -> eval-results - Bake prerequisite preflight (Node 20+, GITHUB_TOKEN/gh) into the runner - Simplify CONTRIBUTING "Running tests locally" prerequisites - Scrub harness name from consumer-facing surfaces Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reinstate overfitting detection under the Vally harness Overfitting detection previously ran inside skill-validator's `evaluate` command, which the Vally migration replaced, so it silently stopped running. Reinstate it as a standalone step wired into the Vally pipeline: - Add `skill-validator overfitting` command that discovers skills, parses each eval.yaml, runs the existing OverfittingJudge, and emits [{plugin, skill, overfittingResult}] JSON (per-skill failures non-fatal, bounded parallelism). - Add a Vally-format parser bridge (ParseEvalConfigFlexible) so the judge handles the current stimuli/graders eval.yaml format; the legacy scenarios-only parser rejected all 98 evals, so the judge never ran. - adapt.mjs: merge overfitting results onto each verdict via --overfitting <file> (keyed by plugin/skill); output is byte-identical when the flag is absent. - evaluation-run.yml: build skill-validator (shared cache with check), run the judge per leg reading GITHUB_TOKEN, and pass --overfitting to adapt.mjs so the dashboard/skills-data consume it unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reconcile #919 Vally eval configs into the sole eval.yaml convention PR #919 landed on main adding fresh Vally specs for three coverage-gap skills (setup-local-sdk, convert-blazor-server-to-webapp, dotnet-webapi) under the interim eval.vally.yaml filename. This branch collapses to a single Vally spec named eval.yaml, so the merge left each skill with both my migrated eval.yaml and #919's newer eval.vally.yaml (a git-clean but semantic duplicate the pipeline would not discover). Adopt #919's reviewed Vally content as the canonical eval.yaml for all three skills and drop the redundant eval.vally.yaml files, preserving the 'sole eval.yaml, zero eval.vally.yaml' invariant. Content is byte-identical to #919's blobs (b14121c6/47d43823/18a9362f), which already passed vally-evaluate on main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
18 KiB
Contributing
Thanks for your interest in contributing. We expect to accept external contributions, but the bar for merging is intentionally high.
This repository contains shared building blocks for coding agents:
- Skills: reusable, task focused instruction packs
- Agents: role based configurations that bundle tool expectations and skill selection
Because these artifacts can affect many users and workflows, we prioritize correctness, clarity, and long term maintainability over speed.
Code ownership
Every plugin, skill, and agent must have designated owners in the .github/CODEOWNERS file. When you add a new skill or agent, add a matching CODEOWNERS entry. Ownership must be either:
- Two or more FTE GitHub aliases (e.g.,
@user1 @user2), or - A GitHub team alias (e.g.,
@dotnet/my-team)
This ensures that every contribution area has accountable reviewers and that PRs are automatically routed to the right people.
Repository layout
plugins/
<plugin>/
plugin.json
skills/
<skill-name>/
SKILL.md
scripts/
references/
assets/
agents/
<agent-name>.agent.md
tests/
<plugin>/
<skill-name>/
eval.yaml
<fixture files>
Every plugin must have a plugin.json file in the plugin root that is linked to from the marketplace.json file.
Plugin organization
Skills are grouped into domain-specific plugins. When proposing a new skill, place it in the plugin that best matches its domain. See README.md for the current list of plugins. If your skill does not fit any existing plugin, consider creating a new one.
To create a new plugin:
- Add
plugins/<plugin-name>/plugin.jsonand askills/directory beneath it. - Add a matching entry in
.github/plugin/marketplace.json,.claude-plugin/marketplace.json,.cursor-plugin/marketplace.json, and.agents/plugins/marketplace.json. Keep plugin entries consistent across all marketplace manifests (includingplugins[].sourceformat) to reduce drift and make future updates safer. Also add aplugins/<plugin-name>/version.json(copy an existing one) so the plugin participates in automated versioning. Start itsplugin.jsonversion at0.1.0. - Add a CODEOWNERS entry for the new plugin and its tests (see Code ownership).
- Add the plugin to the What's Included table in the root
README.md. - Create a
tests/<plugin-name>/directory for skill tests.
See existing plugins for the expected format.
The dotnet-experimental plugin
Use dotnet-experimental when you want to try out a skill idea but are not yet confident it belongs in a stable plugin — for example, when the skill is outside your usual area of responsibility, the approach is unproven, or you want community feedback before committing to a long-term home.
Skills in dotnet-experimental:
- May change, be reworked, or be removed without notice.
- Are held to the same quality and testing standards as any other skill (frontmatter,
eval.yaml, etc.). - Should eventually graduate to a stable plugin or be retired. When a skill has proven itself, move it to the appropriate domain plugin and update tests accordingly.
Place experimental skills under plugins/dotnet-experimental/skills/ with matching tests in tests/dotnet-experimental/.
Plugin versioning
Each plugin is versioned independently. The same version is duplicated across every manifest a
consumer reads: plugins/<plugin>/plugin.json and plugins/<plugin>/.codex-plugin/plugin.json
(both present for every plugin), plus an optional plugins/<plugin>/.claude-plugin/plugin.json
that only plugins needing an inline Claude manifest carry (e.g. dotnet-msbuild's binlog MCP
server). Consumers (Copilot CLI, Claude, Codex, Cursor) read the version directly from this
repository.
Versioning is automated with Nerdbank.GitVersioning.
A per-plugin plugins/<plugin>/version.json scopes the git height to that plugin's subtree, so the
patch number is derived from history — you do not edit it by hand. The generated manifests
(plugin.json, .codex-plugin/plugin.json, and .claude-plugin/plugin.json where present) and
version.json itself are excluded from that height via the pathFilters, so editing only manifest
metadata (anything other than a deliberate base bump in version.json) does not change the patch
number and is not picked up by /version-bump or the weekly sync. Touch a skill or other plugin
content to bump the version.
What this means when you contribute:
- Every plugin carries its own
plugins/<plugin>/version.json. It declares the plugin's version base; the weekly sync fails fast if a plugin ships aplugin.jsonwithout one, so none is ever left unversioned. - Don't hand-edit the
versionfield in any of the manifests (plugin.json,.codex-plugin/plugin.json, or.claude-plugin/plugin.json). The patch number is computed and stamped automatically, and a manual edit will be overwritten. - The only version field you may change is the base (
"version") inplugins/<plugin>/version.json, and only to declare a deliberate minor or major release of that plugin (e.g.0.1→0.2or1.0). Changing the base resets the patch number to0. - After a PR changes a plugin's content, bumping its version is optional:
- A maintainer can comment
/version-bumpon a same-repo PR to stamp the new version onto the branch. - Otherwise the weekly version sync opens a PR that stamps any plugin whose content changed without a version bump, explaining each change. Nothing is ever missed.
- A maintainer can comment
Patch numbers are predicted from git history, so two PRs bumped concurrently can land the same patch
number for a plugin; the weekly sync recomputes the authoritative height on main and reconciles any
collision. Version-only changes do not trigger skill evaluations.
Before you start
- Search existing issues and pull requests to avoid duplicates.
- Start with an issue before you submit a pull request for a new skill, a new agent, or any non trivial change. This helps us align on scope and avoids wasted work.
- Small fixes like typos, broken links, or clearly isolated corrections can go straight to a pull request.
- Keep changes small and focused. One skill or one agent per pull request is a good default.
What we look for
We are most likely to accept contributions that are:
- Addresses a LLM gap and is clearly motivated by a real use case
- Likely to be used frequently and is general (not repo-specific)
- Narrow in scope and easy to review
- Tool conscious and explicit about assumptions
- Verifiable with concrete validation steps
- Written to be durable across repo changes
We are less likely to accept contributions that:
- Add broad frameworks, meta tooling, or large reorganizations
- Duplicate guidance that already exists in another skill
- Encode private environment details, credentials, or company specific secrets
- Depend on proprietary tools or access that most contributors will not have
- Skills that make use of third party tools will be evaluated on a case by case basis. Acceptance of such skills will depend on our evaluation of the provenance and maturity of any such tools.
Proposing a new skill
Please review the What we look for section and add justification for the skill in your issue and PR.
A skill should be self-contained and:
- Clearly state what it does and when to use it.
- Frontmatter (name and description) is small and minimal, just enough for LLM to understand when to use it
- Keep the SKILL.md body under 500 lines for optimal performance. Split content into separate files when you approach this limit. Use a progressive disclosure pattern, referring to those files from the SKILL.md file where needed.
- Specify required inputs (repo context, environment, access needs).
- Prefer concrete checklists and verification steps over vague guidance.
Create a new folder under a plugin's skills/ directory:
plugins/<plugin>/skills/<skill-name>/SKILL.md
A skill should answer three questions up front:
- What outcome does the skill produce
- When should an agent use it
- How does the agent validate success
Skill naming
Use short, kebab-case names that mirror how developers naturally phrase the task, prioritizing keyword overlap over grammar — e.g., add-aspnet-auth, configure-jwt-auth, setup-identity-server. Optionally using gerund style (verb-ing) is acceptable as well - e.g., configuring-caching.
Optimize for intent matching: lead with the action verb users actually say (add, configure, setup, deploy) followed the outcome the skill is aiming to assist.
The SKILL.md is required to have front-matter at a minimum:
Create the file with required YAML frontmatter:
---
name: <skill-name>
description: <description of what the skill does, when to use it, and when not to use it>
---
Tip: The
descriptionfield is used by the agent runtime to decide whether to load the full skill. Include when to use and when not to use guidance directly in the description so the agent can select or skip skills without reading the entireSKILL.md. This avoids unnecessary token usage. Seethread-abort-migration/SKILL.mdfor a good example.
Recommended SKILL.md sections
- Purpose: one paragraph describing the outcome.
- When to use / When not to use (put the essentials in the frontmatter
description; expand here only if more detail is needed). - Inputs: what the agent needs (files, commands, permissions).
- Workflow: numbered steps with checkpoints.
- Validation: how to confirm the result (tests, linters, manual checks).
- Common pitfalls: known traps and how to avoid them.
Skill checklist
Include a SKILL.md that covers:
- Purpose and non goals
- When to use and when not to use (summarized in the frontmatter
description; body section for extended detail) - Inputs and prerequisites
- Step by step workflow with checkpoints
- Validation steps that can be run or observed
- Failure modes and recovery guidance
Also:
- Avoid duplicating text across multiple skills. Prefer referencing shared patterns.
- Do not include content copied from other repositories. If you are inspired by existing work, rewrite in your own words and adapt it to our conventions.
Proposing a new agent
An agent definition should be opinionated but bounded:
- Describe the role (e.g., "WinForms Expert", "Security Reviewer", "Docs Maintainer").
- Define boundaries (what the agent should not do).
- List the skills it expects to use and how it chooses among them.
Add an agent file under a plugin's agents/ directory:
plugins/<plugin>/agents/<agent-name>.agent.md
Agent checklist
Include documentation that explains:
- Role and intended tasks
- Boundaries and safety constraints
- Tooling assumptions
- How the agent chooses which skills to apply
- What a good completion looks like, including validation expectations
Testing and validation
Skills and agents are documentation driven, but we still treat them as production assets.
- Every change should include a validation section that a reviewer can follow.
- If your change references commands, keep them cross platform when practical. If not, state the supported environment.
- If your change depends on external services, document how a reviewer can validate without privileged access, or explain why validation is not possible.
Writing skill tests
Each skill should have an eval.yaml file that defines test scenarios. Tests live under the repo root tests/ directory, matching the plugin and skill name:
tests/<plugin>/<skill-name>/eval.yaml
A minimal eval file:
name: my-skill
description: Evaluates the <plugin>/<skill-name> skill
type: capability
config:
timeout: 3m
stimuli:
- name: "Describe what the agent should do"
prompt: |
The prompt sent to the agent.
graders:
# Deterministic graders check the produced output/artifacts.
- type: exit-success
- type: output-contains
config:
substring: "expected text in agent output"
# The `prompt` grader runs the LLM judge against the rubric below.
- type: prompt
rubric:
- The agent correctly identified the issue
- The agent suggested a concrete fix
Each skill is evaluated in up to three variants — baseline (no skills), skilled (only the skill under test), and plugin (the whole plugin loaded) — and a skill "passes" only when the skilled run is a credible improvement over baseline. To assert that a skill should stay dormant for an out-of-scope task, add expect_activation: false to that stimulus. See any existing tests/*/*/eval.yaml for a fuller example of the grader and stimulus format.
Running tests locally
Prerequisites: Node.js 20+ and the GitHub CLI signed in (gh auth login). The script checks these and tells you what's missing, so just run it:
# Run tests for a single skill
./eng/run-skill-evals.sh dotnet-msbuild binlog-failure-analysis
# Run tests for a whole plugin
./eng/run-skill-evals.sh dotnet-msbuild
# Run every skill's tests
./eng/run-skill-evals.sh
Per-skill verdicts are written to ./eval-results/<plugin>/<skill>/results.json, and the raw experiment output goes to ./eval-results/_experiment/. Model, judge model, and runs-per-stimulus come from the overrides: block in dotnet-skills.experiment.yaml.
Warning
LLM evaluations are noisy. For results you intend to share in a Pull Request, raise
runsindotnet-skills.experiment.yamlto at least 3 (5 is better) for reliable signal.
CI evaluation
Tests run automatically on pull requests that modify files under plugins/. The evaluation workflow discovers changed plugins and evaluates each one. Results are posted as a PR comment and uploaded as build artifacts.
If a scenario fails or regresses, see Investigating Results for how to download artifacts, interpret results.json, and diagnose common failure patterns.
Writing style
- Be concise and specific.
- Prefer numbered steps for workflows.
- Prefer checklists for requirements.
- Define terminology the first time it appears.
- Avoid excessive formatting and avoid clever wording that could be misread by an agent.
Security and safety
- Do not include secrets, tokens, or internal URLs.
- If you discover a security issue, do not open a public issue with sensitive details. Use the repository or organization security reporting process instead.
External references
Skills often reference external tools, documentation, and projects — this is
expected and welcome, including community and third-party resources. To help
reviewers stay aware of external dependencies, the repository includes an
automated reference scanner (integrated into skill-validator check) that runs
in CI against plugin content (SKILL.md, agent files, and reference docs).
The scanner treats all of the following as CI-blocking errors:
http://URLs wherehttps://should be used<script>tags loading external resources without anintegrity(SRI) attribute- Pipe-to-shell patterns (
curl ... | bash) - URLs pointing to domains not listed in
eng/known-domains.txt
Community tools and third-party projects are evaluated on a case-by-case basis
(see "What we look for" above). If your skill references a new external domain,
add it to eng/known-domains.txt in the same PR — the reviewer will
approve it alongside the skill content.
Review process
Maintainers may request changes for:
- Clarity and unambiguous instructions
- Reduced scope
- More explicit validation
- Compatibility with multiple agent runtimes
- Consistency with existing conventions
We may close pull requests that are out of scope or too large to review. If that happens, we are happy to suggest a smaller path forward.
Licensing and provenance
Only submit content that you have the right to contribute.
- Do not include copyrighted text from other projects.
- You may be asked to confirm that your contribution is original or appropriately licensed.
Getting help
If you are unsure where a change belongs or how to structure a skill or agent, open an issue describing:
- The user problem
- The proposed outcome
- A small example of the desired behavior
If you're not sure whether something belongs under skills/ or agents/, a good rule of thumb is:
- Put reusable task playbooks in
skills/. - Put role + operating model in
agents/.
Quality bar
Skills and agents in this repo should be:
- Actionable: the agent can follow them without guesswork.
- Minimal: no extra features or scope creep; focus on the task.
- Verifiable: always include a way to validate success.
- Tool-conscious: don't assume capabilities that might not exist in every runtime.
Skill-Validator & Evaluation workflow
Changes to eng/skill-validator or the .github/workflows/evaluation*.yml workflows must be made from a branch in the dotnet/skills repository (i.e., not from a fork). This is a security measure.
For pull requests from forks, the evaluation workflow (triggered via /evaluate) always uses the workflow YAML from the default branch of dotnet/skills and builds the validator from that default-branch checkout, so any changes to these files in the forked PR will be ignored during evaluation.