Readme 1.2.0
dotnet add package Readme --version 1.2.0
NuGet\Install-Package Readme -Version 1.2.0
<PackageReference Include="Readme" Version="1.2.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Readme" Version="1.2.0" />
<PackageReference Include="Readme"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Readme --version 1.2.0
#r "nuget: Readme, 1.2.0"
#:package Readme@1.2.0
#addin nuget:?package=Readme&version=1.2.0
#tool nuget:?package=Readme&version=1.2.0
Adds automatic package readme packing and include-directive resolution at pack time. Works with SDK Pack and NuGetizer (no NuGetizer required).
<PackageReference Include="Readme" Version="*" />
You don't need to set PrivateAssets=all: Readme is a development dependency and automatically excludes itself from packed dependencies.
When the project is packable and a readme.md (or $(PackageReadmeFile)) is present:
- The readme is included in the package automatically (
PackReadme=falseto opt out). - Include directives are resolved before pack (local files, nested includes,
#fragmentsections, HTTP(S) URLs). - NuGet-style
$token$replacements are applied to the expanded content. - Relative Markdown links/images are expanded to
raw.githubusercontent.comURLs when the project has a GitHubRepositoryUrland commit (opt out:ReadmeExpandGitHubUrls=false; auto-skipped when url/commit is missing or not github.com). - The processed file is written under
$(BaseIntermediateOutputPath)and that intermediate file is what is packed.
Example
This package's own project-level readme.md is essentially three includes:
<!-- include ../../readme.md#content -->
<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
(written as HTML comments in your actual readme, using '!' rather than '!` used above for rendering purposes)
| Include | What it does |
|---|---|
../../readme.md#content |
Local file + #fragment — pulls the docs body between matching … anchors in the repo readme |
https://…/osmf.md |
Remote HTTPS — shared Open Source Maintenance Fee / EULA notice |
https://…/footer.md |
Remote HTTPS — shared sponsors footer |
That keeps the package readme short, reuses the repo docs, and keeps EULA and sponsors in sync across packages.
Include syntax
Use an HTML comment starting with include and a path (relative file, #fragment, or http(s) URL). Nested includes are supported.
Fragments resolve in this order:
- Explicit comment anchors — matching
…pairs (when present). The markers and everything between them is included, so you control whether a section title is in the range (for example put## Usageinside the pair to keep the title, or place the pair after the heading to omit it). - GitHub heading auto-anchors — otherwise the Markdown ATX heading whose GitHub auto-anchor matches the fragment (for example
## Usagefor#usage). The heading line itself is included, through the line before the next heading of the same or higher level.
Use explicit `` markup when you need maximum control over whether the section name is included; auto-anchors always include the matching heading.
Unresolved includes log a warning and leave the marker in place (pack does not fail).
To document the include syntax itself without expansion, put example directives in a fenced code block with language exclude (as in the example above). Includes in other code fences are still resolved.
Remote includes
Absolute http(s) includes from a local file are always allowed (subject to scheme). Includes nested inside remote content resolve relative paths against that URL’s base. Absolute URLs from remote content are allowed only when the host is the same as (or a subdomain of) the including remote host, or is listed in @(ReadmeIncludeDomain) (subdomains of listed domains count too). Other schemes/hosts warn and stay unresolved.
Properties
| Property / item | Default | Description |
|---|---|---|
PackReadme |
true |
Auto-pack the package readme when present |
PackageReadmeFile |
readme.md if it exists |
Package readme path / in-package filename |
ReadmeIncludeScheme |
https |
Semicolon-separated URI schemes allowed for remote includes (add http only if needed) |
ReadmeExpandGitHubUrls |
true |
Expand relative links/images to raw.githubusercontent.com when RepositoryUrl is github.com and a commit is available |
@(ReadmeIncludeDomain) |
(empty) | Hosts allowed for absolute remote includes nested inside remote content |
@(PackageReplacementToken) |
Id, Version, Author, Authors, Title, Description, Copyright, Configuration, Product | $token$ replacements (defaults from CollectReplacementTokens) |
<PropertyGroup>
<ReadmeIncludeScheme>https;http</ReadmeIncludeScheme>
</PropertyGroup>
<ItemGroup>
<ReadmeIncludeDomain Include="cdn.example.com" />
</ItemGroup>
Replacement tokens
Supports the official NuGet replacement tokens (Readme, 1.2.0, Daniel Cazzulino, $title$, Automatic package readme packing, include-directive resolution, token replacement, and GitHub relative URL expansion at pack time. Works with SDK Pack and NuGetizer: processes includes into BaseIntermediateOutputPath and packs that file., Copyright (C) Daniel Cazzulino and Contributors. All rights reserved., Release), plus Daniel Cazzulino (MSBuild $(Authors)) and readme (as in NuGetizer). Replacements run after include expansion so tokens inside included files are replaced too.
Defaults are populated by the CollectReplacementTokens target (same item name as NuGetizer: @(PackageReplacementToken)). Duplicate names keep the last value — never an error — so Readme and NuGetizer can both contribute tokens.
Extend tokens (readme and other files)
Add items anytime; use them case-insensitively as $company$ in the readme:
<ItemGroup>
<PackageReplacementToken Include="Company" Value="$(Company)" />
</ItemGroup>
Override or remove defaults after they are collected:
<Target Name="CustomizePackageTokens" AfterTargets="CollectReplacementTokens">
<ItemGroup>
<PackageReplacementToken Remove="Product" />
<PackageReplacementToken Include="BuildDate" Value="$([System.DateTime]::UtcNow.ToString('yyyy-MM-dd'))" />
</ItemGroup>
</Target>
Pre-work before defaults (e.g. compute properties) via $(CollectReplacementTokensDependsOn) or BeforeTargets="CollectReplacementTokens".
Replace tokens in arbitrary files
ReplacePackageTokens applies the same @(PackageReplacementToken) map to any file. Pair it with Inputs / Outputs for incremental builds. Unknown remaining $token$ placeholders emit warning RDM001 (suppress with <NoWarn>$(NoWarn);RDM001</NoWarn>). The package-readme path does not warn on unknown tokens (docs may contain $…$ examples).
<Target Name="ProcessPackageEula"
DependsOnTargets="CollectReplacementTokens"
Inputs="osmfeula.txt"
Outputs="$(IntermediateOutputPath)OSMFEULA.txt">
<ReplacePackageTokens InputFile="osmfeula.txt"
OutputFile="$(IntermediateOutputPath)OSMFEULA.txt"
Tokens="@(PackageReplacementToken)" />
</Target>
GitHub relative URLs
When packing a package whose repository is on GitHub, relative Markdown links and images in the readme are rewritten so nuget.org (and other consumers) can resolve them:
See [license](license.txt) and .
becomes (pinned to the packed commit):
See [license](https://raw.githubusercontent.com/org/repo/<commit>/license.txt) and .
Requires a github.com RepositoryUrl (or SourceLink PrivateRepositoryUrl with PublishRepositoryUrl=true) and a commit from RepositoryCommit, RepositorySha, or SourceRevisionId. Absolute URLs are left unchanged. Nested clickable images ([](doc.txt)) expand both the image and the outer link.
<PropertyGroup>
<ReadmeExpandGitHubUrls>false</ReadmeExpandGitHubUrls>
</PropertyGroup>
Open Source Maintenance Fee
To ensure the long-term sustainability of this project, users of this package who generate revenue must pay an Open Source Maintenance Fee. While the source code is freely available under the terms of the License, this package and other aspects of the project require adherence to the Maintenance Fee.
To pay the Maintenance Fee, become a Sponsor at the proper OSMF tier. A single fee covers all of Devlooped packages.
Sponsors
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.