Skip to content

Rewrite Copilot instructions and move to AGENTS.md#53630

Draft
lbussell wants to merge 6 commits intodotnet:mainfrom
lbussell:improve-instructions
Draft

Rewrite Copilot instructions and move to AGENTS.md#53630
lbussell wants to merge 6 commits intodotnet:mainfrom
lbussell:improve-instructions

Conversation

@lbussell
Copy link
Copy Markdown
Member

The bulk of .github/copilot-instructions.md was written before most frontier models were released. In my limited experience working with this repo, the existing instructions were mostly a waste of context/tokens and sometimes even reduced the quality of Copilot's output.

I have rewritten the instructions based on Write effective instructions | Claude Code documentation.

I am new to this repo, so suggestions/improvements are welcome.

The new instructions file is ~1,200 tokens.

dotnet test

# Run a single test by name
dotnet test --filter "FullyQualifiedName~TestMethodName"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing the test binary. Is there enough context for it to find the test dlls as well as they build to a slightly different location than redist.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also lean towards providing it the test binary location. The dotnetup copilot instructions use ./.dotnet/dotnet test path/to/project.csproj --filter "FullyQualifiedName~TestName which seemed to work well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nagilson can you point me to the dnup copilot instructions?

Copy link
Copy Markdown
Member

@nagilson nagilson Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely! I haven't reviewed it super thoroughly, but I've got it working such that it helps the agent, at least for me. It doesn't follow some of the rules I mentioned this PR should follow, FWIW 😂

SDK (slightly modified version of the existing file in main, I was thinking of syncing it once I QA'd it) https://github.com/nagilson/sdk/blob/f3f4e89b3d9cd7c7d3823d4d45e3b6ca551ce7d3/.github/copilot-instructions.md

DotnetUp
https://github.com/nagilson/sdk/blob/f3f4e89b3d9cd7c7d3823d4d45e3b6ca551ce7d3/src/Installer/.github/copilot-instructions.md

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcpopMSFT help me understand what the test binary is and when I'd use it. Does dotnet test not do The Right Thing automatically?

For example, if you made some changes to the dotnet CLI, what command would you use to run the dotnet CLI tests?

Copy link
Copy Markdown
Member Author

@lbussell lbussell Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had copilot run one single test and this is what it came up with:

 # from the repo root
 source ./eng/dogfood.sh
 # apparently that changes the working directory and you have to switch back
 cd /path/to/dotnet/sdk/repo/
 dotnet test test/dotnet.Tests/dotnet.Tests.csproj --filter "FullyQualifiedName~GivenNoSrcTestsFolder"

Copy link
Copy Markdown
Member

@nagilson nagilson Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SDK Repo contains a bootstrap SDK (.dotnet/dotnet, called Stage 0) — a complete, pre-built SDK downloaded during restore, pinned to a specific version in global.json. This Stage 0 SDK is used to compile the SDK source code. The stage 0 SDK tends to be based off daily builds and is newer than anything we've released, so without it other dotnet binaries will fail to build as they dont have awareness of the existence of say, 11.0 preview 3 as a valid target.

The build output is Stage 2 (artifacts/bin/redist/{Configuration}/dotnet/), which is created by overlaying freshly built SDK components (sdk/, host/, templates/) on top of Stage 0's runtime frameworks (shared/, packs/). This allows testing the changes in the SDK repo as if the SDK were the dotnet.exe. It assumes the code changes wer e minimal enough that copying and overwriting certain files over the daily build will work. (sometimes but rarely false)

dotnet test uses whatever is on the PATH which by default will not work... unless the PATH has the daily builds on it. So we use .dotnet/dotnet (Stage 0) to build and run tests, or source dogfood.sh to test CLI commands against Stage 2.

Sourcing the script will correctly edit the path but I've found sometimes the agent will fail to source the script or it will launch a new terminal / subagent and forget to source the script, so I prefer to give it the full local explicit path.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So at the moment global.json has 11.0.100-preview.1.26104.118 in it (permalink). After a build, dotnet --list-sdks does correctly list 11.0.100-preview.1.26104.118 [<myrepo>/.dotnet/sdk]. It seems like dotnet is correctly picking up the SDK from the global.json. The test command I listed above appears to work correctly with this configuration.

And the dogfood script seems to work correctly as well. My understanding now is that you would not necessarily want to run the repo tests i.e. dotnet test under the dogfood SDK. You would only use the dogfood SDK only for smoke testing/verifying that you correctly fixed the issue that you are trying to solve. Is that correct?

Copy link
Copy Markdown
Member

@nagilson nagilson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I think that it's a smart idea to improve the instructions we have nowadays! Left some questions to ponder.

dotnet test

# Run a single test by name
dotnet test --filter "FullyQualifiedName~TestMethodName"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also lean towards providing it the test binary location. The dotnetup copilot instructions use ./.dotnet/dotnet test path/to/project.csproj --filter "FullyQualifiedName~TestName which seemed to work well.

By default (without `-pack`), the build skips crossgen and installers (`SkipUsingCrossgen=true`, `SkipBuildingInstallers=true`) to speed up inner-loop iteration. Build output goes to `artifacts/bin/redist/<Configuration>/dotnet/`.

Key flags:
- `-c Release` — Release configuration (default: Debug)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if -c Release is something we need to tell the AI


### Using the Built SDK (Dogfooding)

After building, set up your shell to use the locally-built SDK:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skill authoring suggests writing in 3rd person - should we apply that here? https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices (this is 2nd person)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we should.

- Changes should be minimal to resolve a problem in a clean way.
- User-visible changes to behavior should be considered carefully before committing. They should always be flagged.
- Only edit the files that are necessary to address the specific issue. Do not run `dotnet format` or make formatting changes to additional files.
- Prefer using file-based namespaces for new code.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep this instruction or leave it to the formatting?

Copy link
Copy Markdown
Member Author

@lbussell lbussell Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are code formatting options roughly in order of most to least token efficient:

  1. Do nothing - most efficient.
  2. Auto format on write/save/build and enforce in PR validation (minor impact to LLM input caching if formatting changes the shape of the code substantially).
  3. Agent instructions for formatting (takes up tokens in the context window).
  4. Enforce formatting in PR validation without any kind of automation or checks (most time wasted - you have to instruct your agent to fix the problems manually).

I chose option 1 here because the previous instructions made it clear that automated formatting/dotnet format would be destructive.


### Building

```bash
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might this confuse the agent since bash is more unixy?

dotnet test --filter "ClassName=Microsoft.DotNet.Cli.SomeTests"
```

Test projects live in `test/` with naming conventions `<ProjectName>.Tests` (unit) and `<ProjectName>.IntegrationTests` (integration).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the straightforwardness of some of these prompts, definitely a nice improvement there.

dotnet test --filter "ClassName=Microsoft.DotNet.Cli.SomeTests"
```

Test projects live in `test/` with naming conventions `<ProjectName>.Tests` (unit) and `<ProjectName>.IntegrationTests` (integration).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


This puts the built SDK on your PATH so `dotnet build`, `dotnet test`, etc. use your local changes.

### Running Tests
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One use case that I have encountered a number of times recently is simulating the Helix run environment. This is described in https://github.com/dotnet/sdk/blob/main/documentation/project-docs/repro-helix-failure.md. Scenarios in which this is important is to flush out dependencies on test-assets where the available content is limited. Thoughts on if this scenario should be called out?


By default (without `-pack`), the build skips crossgen and installers (`SkipUsingCrossgen=true`, `SkipBuildingInstallers=true`) to speed up inner-loop iteration. Build output goes to `artifacts/bin/redist/<Configuration>/dotnet/`.

Key flags:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some secondary flags that can be important. e.g. BuildSdkDeb, BuildSdkRpm. I am sure there are others. Is it worth noting these or giving hints on how to self discover these?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you discover these? Are they documented somewhere centrally? Or do you just need to inspect some of the msbuild files in the repo?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know of them being called out in any docs. I always look at the build definition to see what build options/parameters it uses. For the ones I called out, they are specified here - https://github.com/dotnet/sdk/blob/main/eng/pipelines/templates/jobs/sdk-job-matrix.yml#L26

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants