Own concrete MSBuild ItemGroup and item-expression questions. USE FOR: Include, Remove, Update, item identity and metadata, transforms, filtering, batching, duplicate or overlapping items, and reviews
The skill file stays in the publisher's repository.
Paste the copied command in a terminal. It installs this SKILL.md into that agent.
npx skills add dotnet/skills --skill item-management -a cursor -y
Own concrete MSBuild ItemGroup and item-expression questions. USE FOR: Include, Remove, Update, item identity and metadata, transforms, filtering, batching, duplicate or overlapping items, and reviews that verify whether those operations are correct. Generated items stay in scope when the central defect is item identity, metadata, batching, duplicate declarations, or glob/Remove/Update semantics. For a generated artifact missing from compilation or output, wrong target timing/path, or FileWrites clean tracking without a broader item-semantics defect, use including-generated-files. The item operation may be broken, suspected, or already correct. Exclude property-only issues, general incrementality with no item question, broad reviews with no concrete item concern, and non-MSBuild systems.
Own concrete MSBuild ItemGroup and item-expression questions. USE FOR: Include, Remove, Update, item identity and metadata, transforms, filtering, batching, duplicate or overlapping items, and reviews that verify whether those operations are correct. Generated items stay in scope when the central defect is item identity, metadata, batching, duplicate declarations, or glob/Remove/Update semantics. For a generated artifact missing from compilation or output, wrong target timing/path, or FileWrites clean tracking without a broader item-semantics defect, use including-generated-files. The item operation may be broken, suspected, or already correct. Exclude property-only issues, general incrementality with no item question, broad reviews with no concrete item concern, and non-MSBuild systems.
Canonical patterns for working with item groups, from Microsoft.Common.CurrentVersion.targets.
| Operation | Purpose | When to use |
|---|---|---|
Include | Add new items to the group | Creating items with identity + metadata |
Remove | Remove items matching a pattern | Excluding files or clearing a group |
Update | Modify metadata on existing items | Adding/changing metadata without re-adding |
<ItemGroup>
<Compile Include="Generated\*.cs">
<AutoGen>true</AutoGen>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Remove="$(AdditionalExplicitAssemblyReferences)" />
<_CleanOrphanFileWrites Include="@(_CleanPriorFileWrites)"
Exclude="@(_CleanCurrentFileWrites)" />
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="@(EmbeddedResource)"
Condition="'%(NuGetPackageId)' == 'Microsoft.CodeAnalysis.Collections'">
<GenerateSource>true</GenerateSource>
<ClassName>Microsoft.CodeAnalysis.Collections.SR</ClassName>
</EmbeddedResource>
</ItemGroup>
Update does not add items — it only modifies items already in the group.
When %(Metadata) appears in target attributes or task parameters, MSBuild batches execution per unique metadata value.
<Target Name="GenerateSatelliteAssemblies"
Inputs="$(MSBuildAllProjects);@(_SatelliteAssemblyResourceInputs)"
Outputs="$(IntermediateOutputPath)%(Culture)\$(TargetName).resources.dll">
</Target>
<Copy SourceFiles="@(_SourceItems)"
DestinationFiles="@(_SourceItems->'$(OutDir)%(TargetPath)')">
</Copy>
<ItemGroup>
<_ResxOutput Include="@(EmbeddedResource->'%(OutputResource)')"
Condition="'%(EmbeddedResource.WithCulture)' == 'false'" />
</ItemGroup>
%(Metadata) in Condition or Outputs → target batches per unique value.%(Metadata) in task parameters → task batches per unique value.%() from different item groups in the same expression — this causes a cross-product (see Common Pitfalls).Transforms create new item lists by applying an expression to each item:
<Copy SourceFiles="@(IntermediateAssembly)"
DestinationFiles="@(IntermediateAssembly->'$(OutDir)%(Filename)%(Extension)')"/>
<Message Text="Files: @(Compile->'%(Filename)', ', ')" />
<ItemGroup>
<Compile Include="**\*.cs" Exclude="Generated\**;Tests\**" />
</ItemGroup>
Exclude only works on Include — it cannot be used with Update or Remove.
<ItemGroup Condition="'$(NetCoreBuild)' == 'true'">
<PackageReference Include="System.IO.Pipelines" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Pipelines"
Condition="'$(NetCoreBuild)' == 'true'" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="all" />
</ItemGroup>
Referencing %(Metadata) from two different item groups creates O(N×M) executions:
<Exec Command="process %(Source.Identity) with %(Config.Identity)" />
<Exec Command="process %(Source.Identity) with $(ConfigFile)" />
Write to $(IntermediateOutputPath) (obj/), not the source directory. Source-tree generation pollutes version control and can cause duplicate compilation via globs.
Every file created during a target must be added to @(FileWrites) for dotnet clean support.