dotnet/skills Project Structure: How the Mono-Repo Is Organized

The dotnet/skills repository is a mono-repo organized into four primary zones: plugins/ for skill definitions, tests/ for validation fixtures, eng/skill-validator/ for the execution engine, and .github/workflows/ for CI automation.

The dotnet/skills repository houses reusable, self-contained automation units called "skills" that the .NET team runs in CI, bots, or local environments. Understanding the dotnet/skills project structure is essential for contributing new capabilities or debugging existing automation. Everything is grouped by purpose, with strict conventions that allow the CI pipeline to discover and validate new skills automatically without manual registration.

Top-Level Directory Layout

The root of the repository contains standard open-source files plus four critical directories that define the project architecture:

Entry Purpose
plugins/ All skill definitions. Each sub-folder is a distinct skill plugin (e.g., dotnet-upgrade, dotnet-test).
tests/ Integration test suites that mirror the plugin hierarchy and contain validation fixtures.
eng/skill-validator/ The skill-validator tool that compiles plugins, checks schema compliance, and produces JSON reports.
.github/ GitHub Actions workflows including skill-validator.yml, skill-coverage.yml, and pr-triage.yml.
docs/ Human-readable design notes, workflow diagrams, and validator explanations.
AGENTS.md Documentation for "agents"—small helper scripts invoked by the validator or bots.
global.json Pins the .NET SDK version (currently 8.0.x) used for building the repository.

The plugins/ Directory: Skill Definitions

The plugins/ directory is the heart of the dotnet/skills project structure. Each skill lives under plugins/<category>/<skill-name>/ and follows a strict contract.

A typical plugin layout looks like this:

plugins/
├─ dotnet-upgrade/
│  ├─ skills/
│  │  └─ migrate-nullable-references/
│  │     ├─ SKILL.md          ← declarative description of the skill
│  │     └─ references/
│  │        └─ breaking‑changes.md
│  └─ plugin.json            ← metadata for the validator
└─ dotnet-test/
   └─ skills/
      └─ test‑tagging/
         └─ SKILL.md

Each skill requires three key components:

  • SKILL.md: A markdown file following a well-defined schema (documented in eng/skill-validator/src/docs/InvestigatingResults.md) that describes inputs, outputs, and execution logic. The validator consumes this to generate the JSON model used by CI pipelines.
  • plugin.json: Metadata that tells the validator which skills are present, their version, and runtime requirements.
  • references/ (optional): Supplemental markdown files (e.g., breaking-change lists) linked from the main skill description.

The tests/ Directory: Validation and Fixtures

Test projects reside under tests/ and mirror the plugin hierarchy exactly. This structure allows the skill-validator to correlate each skill with its validation suite automatically.


tests/
├─ dotnet-upgrade/
│  ├─ thread‑abort‑migration/
│  │  └─ eval.yaml               ← Vally evaluation configuration
│  └─ migrate‑nullable‑references/
│     └─ fixtures/
│        ├─ nrt‑enabled/
│        │   └─ NrtEnabled.csproj
│        └─ nrt‑disabled/
│            └─ NrtDisabled.csproj
└─ dotnet‑msbuild/
   └─ resolve‑project‑references/
      ├─ App.csproj
      ├─ LibA/
      │   └─ LibA.csproj
      └─ LibB/
          └─ LibB.csproj

Key files in the tests directory:

  • eval.yaml: Describes how a Vally evaluation should run, specifying input files and expected outputs.
  • .csproj fixtures: Minimal sample projects that serve as targets for the skill during automated testing.
  • Test results: Collected by the skill-validator and reported via the skill-validator.yml GitHub workflow.

The eng/skill-validator/ Directory: The Execution Engine

The skill-validator is the runtime engine that makes the dotnet/skills project structure executable. Located at eng/skill-validator/, this tool loads all plugin.json files, parses SKILL.md specifications, and invokes the actual skill code (typically PowerShell scripts or .NET executables).

Critical paths within this directory:

  • src/SkillValidator.csproj: The core project that orchestrates discovery and execution.
  • src/docs/: Validator documentation including troubleshooting guides like InvestigatingResults.md.
  • tests/SkillValidator.Tests.csproj: Unit tests for the validator itself.

The validator produces a JSON report consumed by the skill-coverage workflow to ensure every skill has adequate test coverage.

CI/CD and Automation

The .github/workflows/ directory enforces quality gates across the dotnet/skills project structure:

Adding a New Skill

To extend the repository, create the folder structure and metadata files following the established dotnet/skills project structure conventions:


# 1️⃣ Create the folder structure

mkdir -p plugins/dotnet-example/skills/hello-world

# 2️⃣ Write a minimal SKILL.md

cat > plugins/dotnet-example/skills/hello-world/SKILL.md <<'EOF'

# Hello‑World Skill

**Description**: Prints “Hello, world!” to the console.

**Inputs**
- `name` (string, optional): Name to greet. Default: “world”.

**Outputs**
- `greeting` (string): The greeting message.

**Execution**

```powershell
param($name = 'world')
Write-Output "Hello, $name!"

EOF

cat > plugins/dotnet-example/plugin.json <<'EOF' { "name": "dotnet-example", "version": "1.0.0", "skills": [ { "id": "hello-world", "path": "skills/hello-world" } ] } EOF

4️⃣ Add a test fixture

mkdir -p tests/dotnet-example/hello-world/fixtures/simple cat > tests/dotnet-example/hello-world/fixtures/simple/eval.yaml <<'EOF' skill: dotnet-example/hello-world inputs: name: "OpenAI" expected: greeting: "Hello, OpenAI!" EOF


The validator automatically picks up the new [`plugin.json`](https://github.com/dotnet/skills/blob/main/plugin.json), parses [`SKILL.md`](https://github.com/dotnet/skills/blob/main/SKILL.md), and runs the [`eval.yaml`](https://github.com/dotnet/skills/blob/main/eval.yaml) test during the next CI run without requiring changes to any other part of the repository.

## Running Skills Locally

You can invoke skills directly from the command line using the validator project:

```powershell

# Clone the repo

git clone https://github.com/dotnet/skills.git
cd skills

# Build the validator

dotnet build eng/skill-validator/src/SkillValidator.csproj

# Execute a skill directly

dotnet run --project eng/skill-validator/src/SkillValidator.csproj `
  --skill dotnet-upgrade/migrate-nullable-references `
  --input ProjectPath=tests/dotnet-upgrade/migrate-nullable-references/fixtures/nrt-enabled/NrtEnabled.csproj

This command loads the skill definition from plugins/dotnet-upgrade/skills/migrate-nullable-references/SKILL.md, runs the embedded PowerShell script, and prints the migration report to the console.

Summary

  • plugins/ contains all skill definitions, with each skill using SKILL.md for logic and plugin.json for metadata registration.
  • tests/ mirrors the plugin structure and houses eval.yaml Vally configurations plus .csproj fixtures for integration testing.
  • eng/skill-validator/ hosts the execution engine (SkillValidator.csproj) that parses markdown specifications and runs skill code.
  • .github/workflows/ automates validation, coverage checks, and PR triage via GitHub Actions.
  • global.json pins the .NET SDK version, while AGENTS.md documents auxiliary helper scripts.

Frequently Asked Questions

What is the role of the plugin.json file?

The plugin.json file acts as the registration manifest for the skill-validator. According to the dotnet/skills source code, it declares the plugin name, version, and an array of skill IDs with their relative paths, enabling the validator to discover and load SKILL.md files without hard-coded references.

How does the skill-validator parse SKILL.md files?

The validator, implemented in eng/skill-validator/src/SkillValidator.csproj, consumes SKILL.md files following a schema defined in eng/skill-validator/src/docs/InvestigatingResults.md. It extracts the declarative description, inputs, outputs, and execution blocks to generate a JSON model used by CI pipelines to invoke the correct automation scripts.

What is the difference between the plugins/ and tests/ directories?

The plugins/ directory contains the actual automation logic and metadata consumed by the validator, while tests/ contains validation fixtures and eval.yaml configuration files that define how to verify those skills. The directory structures mirror each other so that the skill-coverage.yml workflow can ensure every plugin has a corresponding test suite.

Can I run a skill without using the GitHub Actions pipeline?

Yes. You can execute skills locally by building eng/skill-validator/src/SkillValidator.csproj and using dotnet run with the --skill and --input arguments. This loads the skill definition directly from the plugins/ directory and executes the embedded scripts (typically PowerShell) against your specified inputs, producing the same JSON reports used in CI.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →