Payload 1.0.0

dotnet add package Payload --version 1.0.0
                    
NuGet\Install-Package Payload -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Payload" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Payload" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Payload" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Payload --version 1.0.0
                    
#r "nuget: Payload, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Payload@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Payload&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Payload&version=1.0.0
                    
Install as a Cake Tool

Payload

License: MIT .NET

Payload is a build-time NuGet helper for packages that need to place bundled files into a consumer repository during build.

Use it when a package should bring along content such as:

  • .agents/skills/...
  • repository templates
  • starter configuration files
  • docs, examples, or small asset folders

Payload is intentionally narrow. It lets a parent package declare bundled content, ship that content inside the .nupkg, and copy it into the consuming repo with simple consumer-side control by PackageId + Tag. It does not try to be a deployment engine, template renderer, or config merger.

Features

  • Parent packages declare bundled content with PayloadContent
  • Parent packages can declare explicit file removals with PayloadRemove
  • Consumers control copy behavior per PackageId + Tag with PayloadPolicy
  • Content can be a single file or a whole directory
  • Directories are copied recursively while preserving relative structure
  • Copy decisions use file size plus SHA-256, not timestamps
  • Parent-package .targets are generated automatically during pack
  • Repository root detection is built in, with explicit override via PayloadRootDirectory
  • Consumer policies can override the destination base path through OverridePath

Installation

Package authors reference Payload from the package that will ship content:

dotnet add package Payload

The authoring package then declares PayloadContent items in its project. During pack, Payload generates the package's build and buildTransitive assets and includes the authored content under payload/ inside the .nupkg.

Authoring in a Parent Package

Declare one or more PayloadContent items:

<ItemGroup>
  <PayloadContent Include="content/skills/example-skill">
    <Tag>ExampleSkill</Tag>
    <TargetPath>.agents/skills/example-skill</TargetPath>
  </PayloadContent>
</ItemGroup>

Meaning:

  • Include The local file or directory to package
  • Tag The logical group name consumers can target
  • TargetPath The destination path inside the consuming repository

If the source is a directory, Payload copies all files beneath it and preserves their relative layout under TargetPath.

Parent packages may also declare CopyOnBuild on PayloadContent.

  • omitted means the parent default is true
  • CopyOnBuild="false" marks the payload as optional by default
  • a consumer may override that default with PayloadPolicy

Parent packages may also declare PayloadRemove for explicit cleanup of files that should be removed from the consumer:

<ItemGroup>
  <PayloadRemove Include=".agents/skills/example-skill/obsolete.md">
    <Tag>ExampleSkill</Tag>
    <CopyOnBuild>false</CopyOnBuild>
  </PayloadRemove>
</ItemGroup>

Meaning:

  • Include The relative destination file path to remove
  • Tag The same logical group used by PayloadContent and PayloadPolicy
  • CopyOnBuild Optional parent default for cleanup-only tags, resolved with the same precedence rules as PayloadContent

PayloadRemove is file-only. If it resolves to a directory, Payload warns and skips so it does not recursively delete consumer content.

Parent-side CopyOnBuild should be consistent within a tag. If PayloadContent and PayloadRemove items under the same PackageId + Tag disagree, Payload warns and falls back to true.

Consumer Control with PayloadPolicy

Consumers can opt out of specific tags:

<ItemGroup>
  <PayloadPolicy Include="ParentPackage"
                 Tag="ExampleSkill"
                 CopyOnBuild="false" />
</ItemGroup>

Meaning:

  • Include The package id
  • Tag The tag declared by the parent package
  • CopyOnBuild="false" Stops future synchronization for that tag

This is intentionally conservative:

  • PayloadRemove entries for that tag do not run
  • existing copied files are not deleted
  • missing files are not restored
  • future overwrites stop

CopyOnBuild resolution works like this:

  1. consumer PayloadPolicy value, if specified
  2. otherwise parent PayloadContent or PayloadRemove value, if specified
  3. otherwise true

That means a parent package can ship optional payloads by declaring:

<PayloadContent Include="content/skills/example-skill">
  <Tag>ExampleSkill</Tag>
  <TargetPath>.agents/skills/example-skill</TargetPath>
  <CopyOnBuild>false</CopyOnBuild>
</PayloadContent>

and a consumer can opt in explicitly:

<PayloadPolicy Include="ParentPackage"
               Tag="ExampleSkill"
               CopyOnBuild="true" />

File-Based Apps

Payload also works with file-based apps that use #:package.

For example:

#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk
#:package ParentPackage@0.1.0-alpha

Console.WriteLine("Hello");

The parent package's buildTransitive targets still flow in, so bundled PayloadContent can be copied during build.

There are two practical constraints:

  • Relative TargetPath values still need a detectable repo root such as .git, .hg, .svn, .vs, .idea, *.sln, or *.slnx
  • if that is not available, set PayloadRootDirectory explicitly with a file-based app property directive

Example:

#:property PayloadRootDirectory=.

Consumer-side PayloadPolicy is different. A file-based app does not have an inline ItemGroup surface, so PayloadPolicy should be declared from a sidecar Directory.Build.targets file placed next to the .cs file or in a parent directory:

<Project>
  <ItemGroup>
    <PayloadPolicy Include="ParentPackage"
                   Tag="ExampleSkill"
                   CopyOnBuild="false" />
  </ItemGroup>
</Project>

Destination Resolution

By default, destination paths are treated as relative to the detected repository root.

If a consumer wants a specific tag to use a different destination base path, they can set OverridePath on PayloadPolicy:

<ItemGroup>
  <PayloadPolicy Include="ParentPackage"
                 Tag="ExampleSkill"
                 OverridePath="/Users/david/custom-root" />
</ItemGroup>

Rules:

  • parent-authored TargetPath is always relative
  • absolute TargetPath values are rejected with a warning
  • if OverridePath is omitted, Payload uses the detected repository root or PayloadRootDirectory
  • if OverridePath is present and rooted, it becomes the destination base path
  • if OverridePath is present and relative, it is resolved relative to the consuming project directory

Example:

  • parent TargetPath: .agents/skills/example-skill
  • consumer OverridePath: /Users/david/custom-root
  • final destination: /Users/david/custom-root/.agents/skills/example-skill

How Repository Root Detection Works

Relative destinations are resolved from a detected repository root.

Payload walks upward from the consuming project directory and looks for practical repository markers such as:

  • .git
  • .hg
  • .svn
  • .vs
  • .idea
  • *.sln
  • *.slnx

Consumers can bypass detection completely:

<PropertyGroup>
  <PayloadRootDirectory>/path/to/repo/root</PayloadRootDirectory>
</PropertyGroup>

If root detection fails for a relative payload, Payload warns and skips the copy rather than guessing.

Copy Behavior

When copying is enabled:

  • file sources copy as files
  • directory sources copy recursively
  • explicit PayloadRemove entries delete matching files
  • if a PayloadRemove path resolves to a directory, Payload warns and skips it
  • local modifications are not treated as a supported customization model
  • package-provided content may overwrite local files while synchronization remains enabled

Copy decisions follow this order:

  1. destination missing → copy
  2. file size differs → copy
  3. file size equal → compare SHA-256
  4. hash differs → copy
  5. hash equal → skip

This avoids relying on modified timestamps and works for text files, binaries, docs, and assets.

When copying is disabled with CopyOnBuild="false", Payload remains conservative:

  • PayloadRemove entries for that tag are skipped
  • existing copied files are left in place
  • missing files are not restored
  • no explicit removals are executed

Generated Package Layout

When a parent package references Payload and packs successfully, Payload generates:

  • build/<PackageId>.targets
  • buildTransitive/<PackageId>.targets
  • packaged authored content under payload/...

That means the authoring package does not need to hand-maintain its own .targets file just to expose the bundled content.

Example

This repository includes an end-to-end test fixture flow:

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Payload:

Package Downloads
PrettyConsole

High performance, ultra-low-latency, allocation-free, feature rich and easy to use wrap over System.Console

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 93 3/7/2026
1.0.0-rc5 36 3/7/2026
1.0.0-rc4 33 3/7/2026
1.0.0-rc3 34 3/7/2026
1.0.0-rc2 33 3/7/2026
1.0.0-rc1 34 3/7/2026