template-authoring
Skill1 starsChanged 6 days agoMITView on GitHub
How the dotnet new template is defined and packaged - .template.config/template.json and its two host files, sourceName replacement, symbols such as authorName and the include toggles, code that's left out when a toggle is off, short flags, the restore post action, what template/template.csproj packs, and how to test an install. Use when changing template options, the package contents or anything that affects generated solutions.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- LudicDynamics/WorldLinestheir own version, first seen Nov 1, 2026
- Cadasto/openehr-assistant-plugintheir own version, first seen Mar 10, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- LudicDynamics/WorldLines★ 108same name
- Cadasto/openehr-assistant-plugin★ 4same 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 repository40 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- add-a-use-caseSkill
- api-conventionsSkill
- branches-and-pull-requestsSkill
- cancellationSkill
- ci-for-your-solutionSkill
- ci-pipelineSkill
- clean-architecture-layersSkill
- configuration-and-environmentsSkill
- coverageSkill
- csharp-house-styleSkill
- data-access-ef-coreSkill
- database-migrationsSkill
- docker-and-composeSkill
- docs-and-voiceSkill
- errors-and-exceptionsSkill
- expose-a-use-caseSkill
- family-syncSkill
- health-checksSkill
- integration-testsSkill
- json-serializationSkill
- mapping-with-mapperlySkill
- mcp-inspectorSkill
- mediatorSkill
- optional-token-authSkill
- packages-and-dependenciesSkill
- pagingSkill
- presentation-integration-testsSkill
- releasesSkill
- sample-dataSkill
- security-findingsSkill
- serilogSkill
- telemetrySkill
- test-designSkill
- time-providerSkill
- unit-testsSkill
- validationSkill
- writing-a-skillSkill
- xml-docs-and-openapiSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 33
Every optional feature is a toggle, and every toggle has the same shape, so people learn it once:
- Very specific: line 54
Every template has the Lean Mean Clean Apps classification, so dotnet new list --tag "Lean Mean Clean Apps" shows the family.
- Very specific: line 62
Keep the sourceName out of identifiers.
- Distinctive: line 63
Test the install from the repository root:
- Very specific: line 90
Add a .sln. The solution is .slnx only, and primaryOutputs, the Dockerfile and the package all point at it.
- Distinctive: line 93
Add an option without testing the generated solution with it on and off.
≈ “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
Template authoring
The rule
The repository is both a working solution and a dotnet new template. .template.config/template.json defines the template; template/template.csproj packs it into a NuGet package of type Template. When someone runs dotnet new, every occurrence of the sourceName (the template's own name, such as CleanMinimalApi) in file names and contents is replaced with their project name, including CleanMinimalApi.slnx.
| Symbol | Option | Replaces |
authorName | --authorName, -an | Stephen Walsh (--author is reserved by dotnet new) |
includeAuth | --include-auth | Nothing. A toggle, off by default. Off, every line of authentication code is left out; on, authority and audience switch on through isEnabled and authority becomes required through isRequired (web templates) |
authority, audience | --authority, -iss, --audience, -aud | The empty Authentication settings in appsettings.json, only with --include-auth. Passed without it, they're ignored without a word (web templates) |
skipRestore | --no-restore | Nothing; it turns the restore post action off |
Three files in .template.config make up the template, and every symbol appears in each one that applies:
| File | Used by | Holds |
template.json | Every host | Identity, groupIdentity, precedence and generatorVersions, tags.type of solution, the standard classifications, defaultName, an SDK constraints entry matching global.json, the symbols with a displayName and a description, a HostIdentifier bind, primaryOutputs (the .slnx, and docs/RUN.md for IDEs only) and three post actions: restore, open docs/RUN.md in the IDE, and a next-steps line in the terminal |
dotnetcli.host.json | dotnet new | Each symbol's longName and short flag, and usageExamples (kept for hosts that show them; the .NET 10 --help doesn't) |
ide.host.json | Visual Studio, Rider | The icon (.template.config/icon.png, a copy of the root icon.png), platform and project type tags, and the label, description, visibility and choice labels of each symbol. The author name has a shared persistenceScope named LeanMeanCleanApps, so Visual Studio remembers it across all five templates |
The words in those files are the first thing people read, in a terminal or a dialog. Write them in our voice (docs-and-voice): plain first, then one dry line if it earns its place. The defaultName is WorksOnMyMachine.Movies (WorksOnMyMachine.Reviews in the Lambda function). Visual Studio and Rider suggest it as the project name, and dotnet new uses the folder name instead.
Feature toggles
Every optional feature is a toggle, and every toggle has the same shape, so people learn it once:
- A
boolsymbol namedinclude<Feature>intemplate.json, such asincludeAuth, with adisplayNameof "Include<feature>". Its description doesn't state the default, becausedotnet new --helpprints that under every option. - A
longNameofinclude-<feature>indotnetcli.host.json, so it's--include-authon the command line. No short flag. - A checkbox labelled "Include
<feature>" inide.host.json, whose description ends with its default, such as "Default: off.", because the IDE dialogs don't show defaults. - One row in the options table of the README,
NUGET.mdand the docs site's template options page, which list every toggle with a Default column.
Off means absent, not switched off. Files that only exist for a toggle go in a (!include<Feature>) exclude list under sources in template.json, and code inside shared files is wrapped so dotnet new can leave it out. In C#, #if includeAuth and #endif start at the beginning of the line, with no brackets (the build fails IDE0047 and IDE0055 otherwise). In project files it's <!--#if (includeAuth) --> and <!--#endif -->, and in appsettings.json it's //#if (includeAuth) and //#endif. A file type the template engine doesn't know, such as the GraphQL schema snapshot, gets #if (includeAuth) and #endif lines through SpecialCustomOperations in template.json.
The repository itself stays all on. The Presentation project and the presentation integration tests define each toggle's constant, such as includeAuth, inside <!--#if (false) -->, which dotnet new always removes. The template's skills and AGENTS.md ship either way.
A toggle's inputs, such as authority and audience, are separate symbols, enabled with isEnabled and made required with isRequired only when the toggle is on. Only dotnet new honours those two. Visual Studio and Rider show every input whatever the toggle says (dotnet/templating#7860), and Rider lists checkboxes first, then text fields in alphabetical order by label. So an input's label starts with its feature, such as "Authentication authority", to sit right under its checkbox, and its IDE description says it's only used when that box is ticked. A toggle that needs another one says so in its conditions, such as (includeTests && includeArchitectureTests). Verify Template checks the defaults, everything on, everything off, and each toggle flipped on its own.
The package includes src/, tests/, docs/RUN.md, the root build files, AGENTS.md, CLAUDE.md, the persona and the engineering skills. It also packs template/README.md as the generated solution's README.md and template/ci.yml as .github/workflows/ci.yml, while leaving the template repository's own README.md, the rest of .github/, the community files and the repository and maintainer skills out. Those skills are listed in RepositorySkills in template/template.csproj; a new one is added there. The pipeline fails a package over 1 MB.
Getting found
dotnet new search and dotnet new list match any part of the template name or of any short name, and nothing else. --tag matches a whole classification, and nuget.org and dotnet package search read the package's PackageTags. So every template puts its search words in all three:
shortNameis a list. The first entry is the template's own name in lower case, such ascleanminimalapi, and never changes. After it come one or two shorter aliases, such ascleanminimalorcleanmcp, thenlmca-<key>andleanmeancleanapps-<key>, where the key is the docs site's (minimalapi,mcp,graphql,webapi,lambda). Those two make searches for clean, lmc, lmca, lean, mean and leanmeanclean find every template. Never a bare short name such asmcp, which clashes with other people's templates.- The
nameand the packageTitlematch, and carry the words people search for that the name lacks, such as "(MCP)", "(Hot Chocolate)", "(Controllers)" or "AWS". - Every template has the
Lean Mean Clean Appsclassification, sodotnet new list --tag "Lean Mean Clean Apps"shows the family. PackageTagscarry the tags all five share, brand words included (clean,cleanarchitecture,lmc,lmca,leanmeanclean,leanmeancleanapps), then the template's own.
The README and NUGET.md name the aliases under the install commands, and the docs site's template options page lists them. The pipeline's Verify Template step uses the first short name.
Steps
- Change
template.jsonortemplate.csproj.template.csprojreferencesMicrosoft.TemplateEngine.Authoring.Tasks, Microsoft's template validator, which checks.template.configon every build and pack; keep its output free of messages, not just errors. A new option also goes indotnetcli.host.jsonwith a short flag that doesn't clash withdotnet new's own (-n,-o,-lang,-h), and inide.host.jsonwithisVisibleset, or Visual Studio hides it. - Keep the
sourceNameout of identifiers. A class calledCleanMinimalApiApplicationbecomes invalid when the name is replaced with something likeMy.Api. Test the install from the repository root:
dotnet new install ./ --force dotnet new <shortName> --help dotnet new <shortName> --name Sample --output ../Sample dotnet build ../Sample && dotnet test ../Sample dotnet new uninstall ./With
--include-auth, also create one with--include-auth --authority https://login.example.com --output ../Securedand test that. Leave the authority out anddotnet newshould stop with exit code 102.--helpshows the short flags and descriptions. Creating the solution should end withRestoring .../Sample.slnxandRestore succeeded, which is the post action at work;--no-restoreshould skip it.For package contents, also pack and look inside:
dotnet pack template/template.csproj --output packages unzip -l packages/*.nupkg- A new option goes in the README and
NUGET.mdoptions tables, and on the docs site's template options page.
Don't
- Change
identityor the firstshortName; existing installs and docs depend on them. Adding aliases after it is fine (see Getting found). - Make a primary output that isn't a project visible to the CLI. The restore post action restores every primary output it can see, so
docs/RUN.mdcarries the sameHostIdentifiercondition as the action that opens it. - Add a
.sln. The solution is.slnxonly, andprimaryOutputs, the Dockerfile and the package all point at it. - Reuse a short flag across options, or give one to
--no-restore; thedotnet newtemplates from Microsoft leave it long, and so do we. - Pack with a wildcard over the whole repository; it pulls in build output and pipeline files.
- Add an option without testing the generated solution with it on and off.
Check
The Test job's Verify Template step installs the packed template, generates a solution and checks that nothing of the template leaked into it (no includeAuth markers, no trace of the template's own name, no icon.png) and that it has README.md and .github/workflows/ci.yml, then checks its format and runs its tests. Where the template has --include-auth it does it again with the toggle on, and checks that --include-auth without --authority is refused with exit code 102.
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.

