[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69BNTN9VACD6EMMZ8JEFVD6":3,"skill-same:01M69BNTN9VACD6EMMZ8JEFVD6":55},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":33,"commitSha":34,"skillDirectory":35,"forksCount":14,"repositoryHtmlUrl":36,"repositoryHomepageUrl":6,"ownerHtmlUrl":37,"ownerBlogUrl":38,"ownerDescription":39,"updatedAt":40,"install":41,"resources":54},"01M69BNTN9VACD6EMMZ8JEFVD6","template-creation",null,"Create, import, or update templates in microsoft\u002Faspire-templates. Use for placing template sources, configuring template.json and aspirecli.host.json, handling prerelease NuGet packages and SDK injection, and adding automated validation. Not for creating an application from an existing template or reviewing a contribution without editing it; use template-review for independent review.","microsoft\u002Faspire-templates","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69BNRMBD2ZNYKW6CACX4G3W",0,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Faspire-templates\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Ftemplate-creation\u002FSKILL.md",[],[19,20,21,9,22,23,24,25,26,27],"template creation","review","sdk","aspire","packages","create","update","nuget","validation","2026-11-10 10:12:30",false,"---\nname: template-creation\ndescription: >-\n  Create, import, or update templates in microsoft\u002Faspire-templates. Use for placing\n  template sources, configuring template.json and aspirecli.host.json, handling\n  prerelease NuGet packages and SDK injection, and adding automated validation.\n  Not for creating an application from an existing template or reviewing a\n  contribution without editing it; use template-review for independent review.\n---\n\n# Contribute a template\n\nDeliver a complete, selectable template with generation and lifecycle coverage.\nPrefer the smallest coherent contribution; do not weaken checks to accommodate\nincomplete template support. Read the current source rather than treating this\nskill as a frozen specification.\n\n## Establish the baseline\n\nRead [README.md](..\u002F..\u002F..\u002FREADME.md), including its upstream baseline and version\npolicy. Choose the closest existing template:\n\n- `templates\u002Faspire-starter` for project-based C# AppHosts and optional tests.\n- `templates\u002Faspire-apphost-singlefile` for file-based C# AppHosts.\n- `templates\u002Faspire-py-starter` or `templates\u002Faspire-ts-starter` for TypeScript\n  AppHosts, SDK injection, polyglot conditionals, and generated ports.\n\nInspect both `.template.config\u002Ftemplate.json` and\n`.template.config\u002Faspirecli.host.json` in that template, plus its generated\nconfiguration and package references. For imports, record the upstream repository,\nfull source commit, and source directory in the README baseline; retain licensing,\nattribution, and applicable localization. This records origin, not verified\nprovenance. Signing and provenance verification are not implemented here.\n\n## Place and parameterize the source\n\nEach independently selectable template belongs at:\n\n```text\ntemplates\u002F\u003Cshort-name>\u002F\n  .template.config\u002F\n    template.json\n    aspirecli.host.json\n  ...application source and configuration...\n```\n\nUse a unique, descriptive kebab-case directory name. Its `template.json`\n`shortName` must match that directory exactly, and its `identity` must be unique;\nfollow the retained `Aspire.TemplatesLab.*` identity convention (an identifier,\nnot the repository location). Supply useful\nname, description, classifications, and language\u002Ftype tags.\n\nKeep all source for that template under its directory. Configure name\u002Fcontent\nreplacement, output paths, primary outputs, and exclusions so generation leaves\nno source-name placeholders or `.template.config` directory in the output.\nDo not include generated apps, build products, dependency directories, secrets,\nor machine-specific configuration. Do not copy upstream host constraints that\nprevent discovery by the Aspire CLI.\n\nMake options consistent across every affected file: AppHost resources, application\ncode, package declarations, configuration, and dependency manifests. Follow the\nPython template's `specialCustomOperations` when preprocessing Python\u002FTOML;\nupstream embedded-CLI placeholders and conditionals must be converted to template\nengine operations. Preserve applicable framework, HTTPS, naming, and hostname\nchoices. Generate ports and reuse each generated value consistently across\nprofiles rather than assigning a fixed port.\n\n## Configure Aspire CLI metadata\n\nUse the exact filename **`.template.config\u002Faspirecli.host.json`**.\n\n- Every `symbolInfo` key must name a symbol declared in `template.json`.\n- Give user-facing choices readable `displayName` labels, meaningful defaults,\n  and descriptions of requirements such as a container runtime.\n- Hide internal parameters with `isHidden: true`: computed package versions,\n  injected SDK identity, port overrides, framework\u002Frestore implementation controls,\n  and other parameters not intended as CLI prompts. Follow the nearest template's\n  prompt policy rather than exposing every template-engine parameter.\n- Put option dependencies in the template symbol's `isEnabled` expression.\n  Optional Redis\u002Ftest-package versions must only be enabled when their option is\n  selected. Do not resolve packages or generate references for unused features.\n- Keep any `dotnetcli.host.json` option aliases and localization consistent with\n  the symbols. The generation validator uses those aliases where present.\n- Set root-level `createNuGetConfig: true`, as required by the repository's current\n  metadata checks. This lets the CLI create a missing root NuGet configuration\n  when its effective channel needs one; it does not mean every invocation creates\n  a file. Do not bake contributor-specific feed aliases or credentials into source.\n\n## Handle SDK identity and prerelease packages\n\nKeep SDK identity separate from integration package versions. TypeScript AppHosts\ndeclare a required string parameter named `AspireVersion`, hide it in host\nmetadata, and replace their `aspire.config.json` `sdk.version` placeholder with\nthe identity supplied by the running CLI. Do not give it a stale default, resolve\nit as an integration package, or assume every package shares that version.\n\nFor each computed NuGet package version, declare a required string parameter\nwith a `replaces` token in `template.json`, without a fixed `defaultValue`.\nFor example, merge this symbol into `symbols`:\n\n```json\n{\n  \"HostingAppHostVersion\": {\n    \"type\": \"parameter\",\n    \"datatype\": \"string\",\n    \"isRequired\": true,\n    \"description\": \"The version of Aspire.Hosting.AppHost.\",\n    \"replaces\": \"HostingAppHostPackageVersion\"\n  }\n}\n```\n\nThen merge the corresponding entry into the host's `symbolInfo`:\n\n```json\n{\n  \"HostingAppHostVersion\": {\n    \"isHidden\": true,\n    \"valueSource\": {\n      \"kind\": \"nugetPackageVersion\",\n      \"packageId\": \"Aspire.Hosting.AppHost\",\n      \"versionRange\": \"*-*\",\n      \"allowPrerelease\": true\n    }\n  }\n}\n```\n\nUse the real package ID and wire its token into the relevant `.csproj`,\n`#:package` directive, or `aspire.config.json` package entry. Resolve each package\nindependently against the effective NuGet sources. The current repository policy is\n`versionRange: \"*-*\"` **and** `allowPrerelease: true`; do not silently narrow\ndiscovery to stable packages or pin a particular daily. These permissive ranges\nare experimental, not reproducible dependency locks or provenance guarantees.\n\nKeep `createNuGetConfig` enabled for TypeScript AppHosts too: a daily SDK identity\ncan require a prerelease managed SDK server unavailable on stable feeds alone.\nGeneration succeeding on a contributor's configured machine is not sufficient.\nFor non-computed dependencies, use explicit compatible versions; when importing,\nresolve upstream packaging tokens from the recorded upstream baseline rather\nthan leaving `!!REPLACE_WITH_*` values in source.\n\n## Wire automated coverage\n\nRead `eng\u002Fvalidate-templates.cs`, `eng\u002Fdiscover-e2e.cs`,\n`tests\u002FAspire.Templates.EndToEnd.Tests\u002FTemplateTests.cs`, and\n`.github\u002Fworkflows\u002Fvalidate-templates.yml` before changing coverage.\n\n1. Add the short name to the explicit `names` inventory in\n   `eng\u002Fvalidate-templates.cs`. Extend default\u002Foption assertions and applicable\n   framework or test-framework cases. Its generic option check currently assumes\n   `LocalhostTld` and an HTTP profile; adapt coverage deliberately for a different\n   template shape without inventing dummy options or weakening existing cases.\n   Synthetic, distinct prerelease package versions check substitutions without\n   network restore; they do not prove live CLI package resolution.\n2. Add exactly one `[TestMethod]` to `TemplateTests`. Its method name must be the\n   short name with `-` replaced by `_`. Use the shared `ValidateAsync` with the\n   actual generated AppHost path under the test project name `LabApp`, and the\n   actual application resource names to wait on. For example, adapting all three\n   arguments to the new template:\n\n   ```csharp\n   [TestMethod]\n   public Task aspire_example() =>\n       ValidateAsync(\"aspire-example\", \"LabApp.AppHost\u002FLabApp.AppHost.csproj\", [\"api\"]);\n   ```\n\n   Only genuinely empty AppHosts should have an empty resource list. A correctly\n   named method with an empty body is not meaningful coverage.\n3. Discovery automatically emits a daily matrix entry per template directory;\n   do not add a separate hand-maintained job list. A new directory without\n   generation inventory or a matching E2E method must fail the discovery job.\n4. If the language, project layout, or runtime is new, extend\n   `tests\u002FDocker\u002Fbuild-template`, `validate-output`, and `Dockerfile` as needed\n   so restore\u002Fbuild\u002Freadiness actually cover it. The shared harness installs the\n   CLI, generates from external source, validates output, restores, builds,\n   starts the exact AppHost in isolated mode, waits for resources, describes it,\n   and stops it. Preserve failure detection, diagnostics, and cleanup.\n\nRun from the repository root with .NET 10+; E2E additionally needs a Docker engine\nsupporting privileged Linux containers:\n\n```bash\ndotnet run --file eng\u002Fvalidate-templates.cs --verbosity quiet\ndotnet test tests\u002FAspire.Templates.EndToEnd.Tests --filter TestCategory=Harness\ndotnet run --file eng\u002Fdiscover-e2e.cs --verbosity quiet\ndocker build --tag aspire-template-validation tests\u002FDocker\n# Replace aspire_example with the new template's normalized method name.\ndotnet test tests\u002FAspire.Templates.EndToEnd.Tests \\\n  --filter FullyQualifiedName=Aspire.Templates.EndToEnd.Tests.TemplateTests.aspire_example\n```\n\nThe `eng` apps require only .NET, not Python. Python\u002FTOML parsing belongs to the\nDocker build\u002Flifecycle checks. Rebuild the image when Docker helpers change and\nrun `TestCategory=TerminalHarness` for harness\u002Fhelper changes. Run\n`TestCategory=E2E` for cross-template changes. A default lifecycle test does not\nprove every optional variant builds; add focused coverage for new runtime behavior.\n\nCI is daily-only until external template sources ship in the stable CLI. Each\nmatrix job checks out and verifies the PR head repository\u002FSHA outside the\ncontainer, then mounts its templates read-only and passes an explicit\n`--template-path`. Merely generating a built-in template with the same short name\ndoes not validate the contribution.\n\nEach Hex1b test has its own privileged Docker-in-Docker container. Never mount\nthe host Docker socket or pass GitHub credentials into it. Privileged containers\nare not a security sandbox: do not run untrusted template code locally. Generated\napps stay in `\u002Ftmp\u002Ftemplate-app`; preserve upload-readable diagnostics, terminal\nrecordings, and TRX results under `TestResults\u002F`, outside generated app directories.\n\n## Handoff\n\nUpdate the README template table, source attribution, and any affected usage or\ntest-count descriptions. Report the changed template, exposed options, package\npolicy, exact checks run, and any verification gaps. Request an independent\n[template review](..\u002Ftemplate-review\u002FSKILL.md); do not treat successful generation\nor the creation checklist as approval, and do not merge without user authorization.\n","# Contribute a template\n\nDeliver a complete, selectable template with generation and lifecycle coverage.\nPrefer the smallest coherent contribution; do not weaken checks to accommodate\nincomplete template support. Read the current source rather than treating this\nskill as a frozen specification.\n\n## Establish the baseline\n\nRead [README.md](..\u002F..\u002F..\u002FREADME.md), including its upstream baseline and version\npolicy. Choose the closest existing template:\n\n- `templates\u002Faspire-starter` for project-based C# AppHosts and optional tests.\n- `templates\u002Faspire-apphost-singlefile` for file-based C# AppHosts.\n- `templates\u002Faspire-py-starter` or `templates\u002Faspire-ts-starter` for TypeScript\n  AppHosts, SDK injection, polyglot conditionals, and generated ports.\n\nInspect both `.template.config\u002Ftemplate.json` and\n`.template.config\u002Faspirecli.host.json` in that template, plus its generated\nconfiguration and package references. For imports, record the upstream repository,\nfull source commit, and source directory in the README baseline; retain licensing,\nattribution, and applicable localization. This records origin, not verified\nprovenance. Signing and provenance verification are not implemented here.\n\n## Place and parameterize the source\n\nEach independently selectable template belongs at:\n\n```text\ntemplates\u002F\u003Cshort-name>\u002F\n  .template.config\u002F\n    template.json\n    aspirecli.host.json\n  ...application source and configuration...\n```\n\nUse a unique, descriptive kebab-case directory name. Its `template.json`\n`shortName` must match that directory exactly, and its `identity` must be unique;\nfollow the retained `Aspire.TemplatesLab.*` identity convention (an identifier,\nnot the repository location). Supply useful\nname, description, classifications, and language\u002Ftype tags.\n\nKeep all source for that template under its directory. Configure name\u002Fcontent\nreplacement, output paths, primary outputs, and exclusions so generation leaves\nno source-name placeholders or `.template.config` directory in the output.\nDo not include generated apps, build products, dependency directories, secrets,\nor machine-specific configuration. Do not copy upstream host constraints that\nprevent discovery by the Aspire CLI.\n\nMake options consistent across every affected file: AppHost resources, application\ncode, package declarations, configuration, and dependency manifests. Follow the\nPython template's `specialCustomOperations` when preprocessing Python\u002FTOML;\nupstream embedded-CLI placeholders and conditionals must be converted to template\nengine operations. Preserve applicable framework, HTTPS, naming, and hostname\nchoices. Generate ports and reuse each generated value consistently across\nprofiles rather than assigning a fixed port.\n\n## Configure Aspire CLI metadata\n\nUse the exact filename **`.template.config\u002Faspirecli.host.json`**.\n\n- Every `symbolInfo` key must name a symbol declared in `template.json`.\n- Give user-facing choices readable `displayName` labels, meaningful defaults,\n  and descriptions of requirements such as a container runtime.\n- Hide internal parameters with `isHidden: true`: computed package versions,\n  injected SDK identity, port overrides, framework\u002Frestore implementation controls,\n  and other parameters not intended as CLI prompts. Follow the nearest template's\n  prompt policy rather than exposing every template-engine parameter.\n- Put option dependencies in the template symbol's `isEnabled` expression.\n  Optional Redis\u002Ftest-package versions must only be enabled when their option is\n  selected. Do not resolve packages or generate references for unused features.\n- Keep any `dotnetcli.host.json` option aliases and localization consistent with\n  the symbols. The generation validator uses those aliases where present.\n- Set root-level `createNuGetConfig: true`, as required by the repository's current\n  metadata checks. This lets the CLI create a missing root NuGet configuration\n  when its effective channel needs one; it does not mean every invocation creates\n  a file. Do not bake contributor-specific feed aliases or credentials into source.\n\n## Handle SDK identity and prerelease packages\n\nKeep SDK identity separate from integration package versions. TypeScript AppHosts\ndeclare a required string parameter named `AspireVersion`, hide it in host\nmetadata, and replace their `aspire.config.json` `sdk.version` placeholder with\nthe identity supplied by the running CLI. Do not give it a stale default, resolve\nit as an integration package, or assume every package shares that version.\n\nFor each computed NuGet package version, declare a required string parameter\nwith a `replaces` token in `template.json`, without a fixed `defaultValue`.\nFor example, merge this symbol into `symbols`:\n\n```json\n{\n  \"HostingAppHostVersion\": {\n    \"type\": \"parameter\",\n    \"datatype\": \"string\",\n    \"isRequired\": true,\n    \"description\": \"The version of Aspire.Hosting.AppHost.\",\n    \"replaces\": \"HostingAppHostPackageVersion\"\n  }\n}\n```\n\nThen merge the corresponding entry into the host's `symbolInfo`:\n\n```json\n{\n  \"HostingAppHostVersion\": {\n    \"isHidden\": true,\n    \"valueSource\": {\n      \"kind\": \"nugetPackageVersion\",\n      \"packageId\": \"Aspire.Hosting.AppHost\",\n      \"versionRange\": \"*-*\",\n      \"allowPrerelease\": true\n    }\n  }\n}\n```\n\nUse the real package ID and wire its token into the relevant `.csproj`,\n`#:package` directive, or `aspire.config.json` package entry. Resolve each package\nindependently against the effective NuGet sources. The current repository policy is\n`versionRange: \"*-*\"` **and** `allowPrerelease: true`; do not silently narrow\ndiscovery to stable packages or pin a particular daily. These permissive ranges\nare experimental, not reproducible dependency locks or provenance guarantees.\n\nKeep `createNuGetConfig` enabled for TypeScript AppHosts too: a daily SDK identity\ncan require a prerelease managed SDK server unavailable on stable feeds alone.\nGeneration succeeding on a contributor's configured machine is not sufficient.\nFor non-computed dependencies, use explicit compatible versions; when importing,\nresolve upstream packaging tokens from the recorded upstream baseline rather\nthan leaving `!!REPLACE_WITH_*` values in source.\n\n## Wire automated coverage\n\nRead `eng\u002Fvalidate-templates.cs`, `eng\u002Fdiscover-e2e.cs`,\n`tests\u002FAspire.Templates.EndToEnd.Tests\u002FTemplateTests.cs`, and\n`.github\u002Fworkflows\u002Fvalidate-templates.yml` before changing coverage.\n\n1. Add the short name to the explicit `names` inventory in\n   `eng\u002Fvalidate-templates.cs`. Extend default\u002Foption assertions and applicable\n   framework or test-framework cases. Its generic option check currently assumes\n   `LocalhostTld` and an HTTP profile; adapt coverage deliberately for a different\n   template shape without inventing dummy options or weakening existing cases.\n   Synthetic, distinct prerelease package versions check substitutions without\n   network restore; they do not prove live CLI package resolution.\n2. Add exactly one `[TestMethod]` to `TemplateTests`. Its method name must be the\n   short name with `-` replaced by `_`. Use the shared `ValidateAsync` with the\n   actual generated AppHost path under the test project name `LabApp`, and the\n   actual application resource names to wait on. For example, adapting all three\n   arguments to the new template:\n\n   ```csharp\n   [TestMethod]\n   public Task aspire_example() =>\n       ValidateAsync(\"aspire-example\", \"LabApp.AppHost\u002FLabApp.AppHost.csproj\", [\"api\"]);\n   ```\n\n   Only genuinely empty AppHosts should have an empty resource list. A correctly\n   named method with an empty body is not meaningful coverage.\n3. Discovery automatically emits a daily matrix entry per template directory;\n   do not add a separate hand-maintained job list. A new directory without\n   generation inventory or a matching E2E method must fail the discovery job.\n4. If the language, project layout, or runtime is new, extend\n   `tests\u002FDocker\u002Fbuild-template`, `validate-output`, and `Dockerfile` as needed\n   so restore\u002Fbuild\u002Freadiness actually cover it. The shared harness installs the\n   CLI, generates from external source, validates output, restores, builds,\n   starts the exact AppHost in isolated mode, waits for resources, describes it,\n   and stops it. Preserve failure detection, diagnostics, and cleanup.\n\nRun from the repository root with .NET 10+; E2E additionally needs a Docker engine\nsupporting privileged Linux containers:\n\n```bash\ndotnet run --file eng\u002Fvalidate-templates.cs --verbosity quiet\ndotnet test tests\u002FAspire.Templates.EndToEnd.Tests --filter TestCategory=Harness\ndotnet run --file eng\u002Fdiscover-e2e.cs --verbosity quiet\ndocker build --tag aspire-template-validation tests\u002FDocker\n# Replace aspire_example with the new template's normalized method name.\ndotnet test tests\u002FAspire.Templates.EndToEnd.Tests \\\n  --filter FullyQualifiedName=Aspire.Templates.EndToEnd.Tests.TemplateTests.aspire_example\n```\n\nThe `eng` apps require only .NET, not Python. Python\u002FTOML parsing belongs to the\nDocker build\u002Flifecycle checks. Rebuild the image when Docker helpers change and\nrun `TestCategory=TerminalHarness` for harness\u002Fhelper changes. Run\n`TestCategory=E2E` for cross-template changes. A default lifecycle test does not\nprove every optional variant builds; add focused coverage for new runtime behavior.\n\nCI is daily-only until external template sources ship in the stable CLI. Each\nmatrix job checks out and verifies the PR head repository\u002FSHA outside the\ncontainer, then mounts its templates read-only and passes an explicit\n`--template-path`. Merely generating a built-in template with the same short name\ndoes not validate the contribution.\n\nEach Hex1b test has its own privileged Docker-in-Docker container. Never mount\nthe host Docker socket or pass GitHub credentials into it. Privileged containers\nare not a security sandbox: do not run untrusted template code locally. Generated\napps stay in `\u002Ftmp\u002Ftemplate-app`; preserve upload-readable diagnostics, terminal\nrecordings, and TRX results under `TestResults\u002F`, outside generated app directories.\n\n## Handoff\n\nUpdate the README template table, source attribution, and any affected usage or\ntest-count descriptions. Report the changed template, exposed options, package\npolicy, exact checks run, and any verification gaps. Request an independent\n[template review](..\u002Ftemplate-review\u002FSKILL.md); do not treat successful generation\nor the creation checklist as approval, and do not merge without user authorization.\n",{"name":5,"description":7},"main","e9690bd925a2bf161044a05216ff0642b718b612",".github\u002Fskills\u002Ftemplate-creation","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Faspire-templates","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-10-29 10:12:42",{"source":8,"skillName":5,"commands":42,"prompt":52,"zipAvailable":53},[43,46,49],{"tool":44,"command":45},"npx","npx skills add microsoft\u002Faspire-templates --skill template-creation",{"tool":47,"command":48},"bunx","bunx skills add microsoft\u002Faspire-templates --skill template-creation",{"tool":50,"command":51},"pnpm","pnpm dlx skills add microsoft\u002Faspire-templates --skill template-creation","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Faspire-templates\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Ftemplate-creation\u002FSKILL.md",true,[],[56],{"skillNo":57,"name":58,"nameZh":6,"description":59,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":60,"categories":61,"keywords":62,"publishedAt":28},"01M69BNWNGT6FYXX0411NSYKQ5","template-review","Independently review template contributions in microsoft\u002Faspire-templates for source layout, Aspire CLI prompts, prerelease package resolution, SDK identity, output correctness, and meaningful automated coverage. Use for template PRs and pre-merge review, not implementation; template-creation handles authoring.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Faspire-templates\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Ftemplate-review\u002FSKILL.md",[],[20,63,64,21,9,65,66,22],"template review","cli","merge","identity"]