agentleFS
MicrosoftKnown publishermicrosoft/vstest/AGENTS.md

vstest

AGENTS.md976 starsChanged 6 months agoMITView on GitHub

This file contains project-specific knowledge for AI agents working on the VSTest test platform. VSTest is the test platform that powers dotnet test, Visual Studio Test Explorer, and Azure DevOps test tasks. It discovers and executes tests written with MSTest, xUnit, NUnit, and other frameworks. Key IPC boundary: vstest.console and testhost communicate via JSON-RPC over stdin/stdout. Wire format changes must be backward-compatible. CI builds use -c Release. Always build with Release config before submitting PRs. -projects is resolved with Resolve-Path,…

  • Reads credentials
  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository7 other files it gives its agents.

The file

We split this AGENTS.md into the rules it gives an agent

8 rules. About 0 are common, 3 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Test projects mirror source projects under test/:

    line 71
  2. Very specific:

    Test categories: Unit (fast, default), Smoke (P0 e2e), Acceptance (full e2e with --integrationTest).

    line 79
  3. Very specific:

    Use -File in any new .cmd wrapper.

    line 92
  4. Very specific:

    After packaging changes, regenerate eng/expected-nupkg-file-counts.json and eng/expected-dll-frameworks.json from a clean Release build.

    line 110
  5. Distinctive:

    Never commit to main

    line 129
  6. Distinctive:

    Never force-push PR branches — squash-merge at the end

    line 130
  7. Distinctive:

    Don't create draft PRs — undrafting forces a rebuild

    line 132
  8. Very specific:

    Use gh aw secrets set to manage secrets, NOT gh secret set.

    line 136

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md 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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

AGENTS.md — vstest

This file contains project-specific knowledge for AI agents working on the VSTest test platform.

Repository Overview

VSTest is the test platform that powers dotnet test, Visual Studio Test Explorer, and Azure DevOps test tasks. It discovers and executes tests written with MSTest, xUnit, NUnit, and other frameworks.

Architecture

vstest.console (entry point)
  ├── TestRequestManager (orchestration)
  │   ├── ProxyDiscoveryManager ──IPC──► testhost (discovery)
  │   ├── ProxyExecutionManager ──IPC──► testhost (execution)
  │   └── ProxyOperationManager (shared IPC logic)
  ├── Translation Layer (bridges old/new handler interfaces for VS/AzDO)
  └── Data Collectors (code coverage, blame, etc.)

Key IPC boundary: vstest.console and testhost communicate via JSON-RPC over stdin/stdout. Wire format changes must be backward-compatible.

Key Directories

DirectoryPurposeSensitivity
src/Microsoft.TestPlatform.ObjectModel/Public API surface (NuGet-shipped)Binary compat critical
src/Microsoft.TestPlatform.CommunicationUtilities/JSON-RPC protocol, serializationWire compat critical
src/Microsoft.TestPlatform.CrossPlatEngine/Execution engine, parallel schedulingThread safety critical
src/Microsoft.TestPlatform.CoreUtilities/Shared utilitiesHot-path perf critical
src/vstest.console/CLI entry point, arg parsing, app.configBinding redirects
src/testhost*/Test host processesAssembly loading
src/datacollector/Data collector hostBinding redirects
src/Microsoft.TestPlatform.Client/Client-side test management
src/Microsoft.TestPlatform.Common/Shared platform logic
src/Microsoft.TestPlatform.Extensions.*/Loggers (HTML, TRX, blame)

Build

ActionWindowsLinux / macOS
Restore + Build./build.cmd./build.sh
Build + Pack./build.cmd -pack./build.sh --pack
Release config./build.cmd -c Release -pack./build.sh -c Release --pack
Unit tests./test.cmd./test.sh
Specific tests./test.cmd -projects <path-or-glob>./test.sh --projects <path-or-glob>
Several test projects./test.cmd -projects "test\A\A.csproj;test\B\B.csproj"./test.sh --projects "test/A/A.csproj;test/B/B.csproj"
Smoke tests./test.cmd -smokeTest./test.sh --integrationTest (smoke is a subset)
Single test by name./test.cmd -c Release -filter "FullyQualifiedName~TestName"./test.sh --property:'TestRunnerAdditionalArguments=--filter "FullyQualifiedName~TestName"'

CI builds use -c Release. Always build with Release config before submitting PRs.

-projects is resolved with Resolve-Path, so it takes a path or a glob. A bare nickname such as smoke or htmllogger fails with Cannot find path. Test categories are switches instead: -smokeTest, -integrationTest, -compatibilityTest, -performanceTest.

Filtering by test name is a Windows-only wrapper parameter. test.cmd goes through eng/build.ps1, which owns -filter and the category switches; test.sh calls Arcade's eng/common/build.sh directly and has neither, so on Linux/macOS the filter is passed as an MSBuild property. Do not pass the filter as /p:TestRunnerAdditionalArguments="--filter ..." on Windows — eng/build.ps1 throws "Use --filter instead of passing filter as an additional argument to TestRunnerAdditionalArguments." See CONTRIBUTING.md for the Linux/macOS quoting rules.

test.cmd does not set DOTNET_ROOT, so test executables built against the repo's preview TFM fail with "You must install or update .NET to run this application." This hits unit tests too, not only integration and smoke tests. Set it first:

$env:DOTNET_ROOT = "$PWD\.dotnet"

test.cmd does not restore either. On a fresh clone, build once (./build.cmd -c Release) before running it, or pass -restore -build, otherwise it stops with Toolset version <version> has not been restored.

The .cmd wrappers pass arguments to PowerShell literally. See Wrapper scripts pass arguments literally before changing one.

.github/skills/vstest-build-test/SKILL.md is the fuller build and test reference. Keep it and this section in agreement.

Test Structure

Test projects mirror source projects under test/:

src/Microsoft.TestPlatform.ObjectModel/     → test/Microsoft.TestPlatform.ObjectModel.UnitTests/
src/Microsoft.TestPlatform.CrossPlatEngine/ → test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/
src/vstest.console/                         → test/vstest.console.UnitTests/

Test categories: Unit (fast, default), Smoke (P0 e2e), Acceptance (full e2e with --integrationTest).

Known Gotchas

Wrapper scripts pass arguments literally

build.cmd, test.cmd, restore.cmd, open-vs.cmd, open-code.cmd, and eng/RestoreInternal.cmd invoke PowerShell with -File, so everything after the script path reaches the target script as a literal argument. The first five call eng/build.ps1, eng/RestoreInternal.cmd calls eng/common/build.ps1.

They previously used the form -command "& """<script>""" %*", which spliced %* into a string that PowerShell then parsed as source code. That caused two problems, both fixed:

  • ; in an argument became a statement separator. ./test.cmd -projects "test\A\A.csproj;test\B\B.csproj" ran Build.ps1 -projects test\A\A.csproj and then executed test\B\B.csproj as its own statement. On Windows .csproj is file-associated with Visual Studio, so every entry after the first opened a full IDE. Three agents ran this form at the same time and opened eighteen instances of Visual Studio.
  • Exit codes collapsed to 1. eng/build.ps1 ends with exit $LastExitCode to forward the real code, but -command discarded it, so 8 (filter matched no tests) and every other code arrived as 1.

Use -File in any new .cmd wrapper. Do not switch back to -command.

Because arguments are no longer re-parsed, one level of quoting is enough instead of two, for wrapper parameters and /p: MSBuild properties alike. A single pair of quotes now reaches the target script intact:

./test.cmd -c Release -projects "test\Microsoft.TestPlatform.CrossPlatEngine.UnitTests\Microsoft.TestPlatform.CrossPlatEngine.UnitTests.csproj" -filter "FullyQualifiedName~MtpProxyExecutionManagerTests"

eng/common/* comes from Arcade and still uses -command. Do not edit those files here; fix them in the Arcade repository.

Independent of the wrappers: never run a .csproj or .sln path as a command. The path is always an argument, as in dotnet test <path>.csproj.

Binding Redirects

Bumping a netstandard2.0 package cascades: transitive deps need binding redirects in ALL three app.configs (vstest.console/app.config, testhost.x86/app.config, datacollector/app.config). Miss one and you get FileLoadException in net462 DTA hosts.

Package Verification

After packaging changes, regenerate eng/expected-nupkg-file-counts.json and eng/expected-dll-frameworks.json from a clean Release build. Never hand-edit these files.

Assert.Contains

Assert.Contains(expected, actual) — first param is the needle. This is the opposite of old StringAssert. This has been a recurring mistake.

Localization

*.xlf files must be manually edited to match .resx changes. They are NOT auto-generated by the build.

CI

  • CI runs on Azure DevOps, not GitHub Actions
  • DOTNET_ROLL_FORWARD=LatestMajor masks version mismatches — don't rely on it
  • Doc-only PRs skip CI builds
  • Windows builds finish first (~15 min), macOS/Ubuntu take longer

Git Workflow

  • Never commit to main
  • Never force-push PR branches — squash-merge at the end
  • Push to fork remote, PR against microsoft/vstest
  • Don't create draft PRs — undrafting forces a rebuild

Agentic Workflows (gh-aw)

  • Use gh aw secrets set to manage secrets, NOT gh secret set. Plain gh secret set creates the repo secret but gh-aw can't see it.
  • Auth is company-token first — no long-lived personal PATs. Copilot inference uses the copilot-requests: write permission (billed to the org Copilot subscription), so COPILOT_GITHUB_TOKEN is no longer referenced by any compiled workflow. Write-backs use an org-owned GitHub App (APP_ID variable + APP_PRIVATE_KEY secret) with ignore-if-missing: true, falling back to GITHUB_TOKEN until an org admin provisions it. See .github/workflows/README.md for the full secrets table and rationale (the Microsoft OSS enterprise now 403s fine-grained PATs older than 8 days).
  • lockdown: has been removed repo-wide (deprecated upstream); workflows keep min-integrity: none and use the default GITHUB_TOKEN for MCP reads.
  • Workflow source files are .md in .github/workflows/. Compiled .lock.yml files are generated — don't hand-edit them.
  • To recompile after editing a workflow: gh aw compile from the repo root.
  • .github/* and AGENTS.md are excluded from CI path triggers — editing workflows won't trigger a full build.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.