msbuild
Skill1 starsChanged 13 days agoMITView on GitHub
Use when editing a .csproj, .sln, .slnx or .targets file, diagnosing an MSBuild or .NET build error, or finding out why a file that should be embedded or copied is missing from the output. Trigger words - WMC9997, double hyphen in XML comment, satellite assembly, EmbeddedResource missing, RuntimeIdentifier, UseWindowsForms, slnx, -getItem, -v diag.
- Deletes or force-pushes
1 other project uses a version of this.
Adopted by
Most recently taken up by
- microsoft/testfxtheir own version, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- microsoft/testfx★ 1.1ksame name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository30 other files it gives its agents.
- angular-crud-gotchasSkill
- aws-lightsail-container-deploySkill
- bannerlord-decompileSkill
- codegen-t4-templatesSkill
- csharpSkill
- delphi-code-smellsSkill
- delphi-firedacSkill
- delphiSkill
- delphi-types-and-unitsSkill
- difftasticSkill
- dockerSkill
- efcore-aspnet-reviewSkill
- git-bash-editingSkill
- github-issue-creatorSkill
- microsoft-docsSkill
- minimal-comments-and-docsSkill
- mssqlSkill
- mstest-assertionsSkill
- mysqlSkill
- nginx-config-testingSkill
- odata-generated-gridsSkill
- postgresSkill
- powershellSkill
- react-crud-gotchasSkill
- sanitize-for-open-sourceSkill
- self-contained-deploymentSkill
- skill-writerSkill
- ui-conventionsSkill
- verify-in-running-appSkill
- winui3Skill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 85
After files are regenerated (a column renamed, a control swapped), a WinUI3 project can fail with C# errors pointing into obj\...\*.g.cs …
- Very specific: line 102
Not re-run: stale obj after code generation, the output folder difference between solution and project builds, packing a tool.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill 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.
Files
MSBuild / .csproj gotchas
XML comments can't contain -- — hits .csproj AND .xaml alike
Both project files and XAML files are parsed as strict XML, and standard XML forbids -- inside a
comment (and a comment can't end in --> preceded by another -). Writing a comment the way you'd
naturally write prose — using -- as an em-dash — reliably breaks the build:
error MSB4025: The project file could not be loaded. An XML comment cannot contain '--', and '-' cannot be the last character.
error WMC9997: An XML comment cannot contain '--', and '-' cannot be the last character. (same rule, XAML compiler)This is easy to reintroduce over and over across a session (it did, repeatedly) since it's a natural
writing habit, not an obviously "wrong" thing to type. Use a real em dash (—), a colon, or a comma instead
of -- in any <!-- ... --> comment, in both .csproj/.props/.targets files and .xaml files.
// comments in .cs files are NOT affected (not XML) — only literal XML files.
EmbeddedResource silently vanishes for filenames containing a real ISO culture code
MSBuild's AssignCulture task splits each filename on dots looking for a segment that matches a known
culture code (e.g. MyResource.fr.resx → French satellite resource). A filename like
SP_Insert.tt.config has "tt" sitting in the middle — which is also the ISO 639-1 code for Tatar — so
MSBuild silently reroutes that file into a tt\ satellite resource assembly instead of the main one.
Assembly.GetManifestResourceNames() on the main assembly then just won't list it. No build warning or
error is produced — the file compiles fine, it's just quietly not where you expect it at runtime.
Fix:
<EmbeddedResource Include="Templates\**\*.*" WithCulture="false" />Diagnose this class of bug with a verbose build searching for the exact tell:
dotnet build -v diag 2>&1 | grep "Culture of"which prints e.g. Culture of "tt" was assigned to file "..\Templates\SP_Insert.tt.config". — instant
root cause once you know to look for it; otherwise it looks like the item was never included at all.
WinUI3 project properties
WindowsAppSDKSelfContained with SelfContained=false (singular RuntimeIdentifier) is in the winui3 skill, "Build and project".
Related trap: building the solution (dotnet build Foo.slnx) vs building the project directly
(dotnet build Foo.App/Foo.App.csproj) can produce different output folder structures for the exact
same project, e.g. bin\x64\Debug\net10.0-windows.../win-x64\ vs bin\Debug\net10.0-windows.../win-x64\,
because the solution build implicitly resolves $(Platform) from the solution's own platform mappings
while a bare project build may not, absent an explicit -p:Platform=x64. If a script or note says "look
in bin\x64..." and the exe isn't there, check the sibling bin\Debug\... (no x64 segment) before
assuming something is broken.
UseWindowsForms=true conflicts with a WinUI3 project's XAML
It fails the build with MC6000. The cause and the Win32 folder-picker alternative are in the winui3 skill, "Build and project".
dotnet new sln produces .slnx, not .sln, on newer SDKs
On .NET 10's SDK, dotnet new sln generates the new XML-based .slnx solution format by default, not the
classic .sln. Build commands, CI scripts, and any tooling that hardcodes a .sln filename need to target
the actual generated file (dotnet build MyProject.slnx), not assume .sln.
Quick diagnostic commands worth reaching for
- Inspect resolved items without a full build, to check whether an
Include=glob is matching what you think it is (item evaluation, before any target runs):dotnet build MyProject.csproj -getItem:EmbeddedResource dotnet build MyProject.csproj -getItem:None,Content - Trace exactly what happened to one specific file during a real build (which task touched it, what
metadata it was assigned, whether it got filtered out) by grepping a diagnostic-verbosity log for that
file's name:
This is slow (diagnostic verbosity is chatty) but is the most reliable way to find where in the pipeline a file silently stopped being what you expected, rather than guessing from thedotnet build -v diag 2>&1 | grep "SomeFile.ext".csprojalone.
A WinUI3 build full of impossible errors after a code-generation run: clear obj, restore, build twice
After files are regenerated (a column renamed, a control swapped), a WinUI3 project can fail with C# errors pointing into obj\...\*.g.cs (for example
'ItemDetailViewModel' does not contain a definition for 'ItemStatus' when the source no longer uses that name) plus XamlCompiler ... WMC9999: Object reference not set
to an instance of an object and WMC1509 No LocalAssembly parameter. Those .g.cs files are stale output of the previous XAML; the real source is fine. Fix:
rm -rf <project>/obj, dotnet restore <solution>, then dotnet build — and expect the first build after clearing obj to fail once with WMC0601 Error opening XAML
file ... App.xaml before it has copied the file; the second build succeeds. A regeneration script should do this automatically on the first failure. (A running app locks the
output instead and fails with MSB3021/MSB3027; close it first.)
Packing a command-line tool (dotnet tool)
<PackAsTool>true</PackAsTool>, <ToolCommandName>codegen</ToolCommandName>, PackageId, Version, and <None Include="..\README.md" Pack="true" PackagePath="\" /> for the readme and licence (plus PackageReadmeFile / PackageLicenseFile). dotnet pack -o <dir>, then dotnet tool install --tool-path <dir2> --add-source <dir> <id> to try it without touching the global tools. Two things bite:
- A tool's files live under
...\.store\<id>\<version>\...and are replaced on every update: a program that keeps settings, templates or output next to its exe loses them. Detect the.storesegment and use%APPDATA%\<Name>instead (with an environment variable to override). - An XML comment in the
.csprojthat mentionsdotnet tool install --globalfails the project load (--in a comment, see the first section).
How this was verified
- Written from build failures met while building CodeGenNew.
- Re-checked with the .NET SDK 10.0.401, in a throwaway project:
--in a.csprojcomment fails withMSB4025(reproduced); a fileSP_Insert.tt.configis given the culturettand attsatellite output folder appears, andWithCulture="false"removes both (reproduced, clean build before and after);dotnet new slncreates a.slnx. - Not re-run: stale
objafter code generation, the output folder difference between solution and project builds, packing a tool. TheWindowsAppSDKSelfContainedandUseWindowsFormsitems are kept in thewinui3skill. The Windows App SDK version was not recorded.
What this does not prove
- That a rule holds on an older SDK or another Windows App SDK version.
- That the culture trap covers every two-letter segment: only
ttwas tested.
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
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.

