Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ This skill helps an agent create and validate custom `dotnet new` templates. It

## Workflow

### Rules that change the answer

Use these structures exactly; do not invent fields from other template features.

| Need | Correct structure | Never use |
|------|-------------------|-----------|
| Conditional XML in a `.csproj` | XML comments such as `<!--#if (database == "SqlServer") -->` and `<!--#endif -->` around the complete element | bare `#if` lines, which make the XML invalid |
| Restore generated projects | restore action `210D431B-A78B-4D2F-B762-4ED3E3EA9025`; use `primaryOutputs`, or `args.files` containing source-template paths/globs | run-script fields such as `executable` on the restore action |
| Restrict to the SDK host | a `host` constraint whose `args` is an array containing `{ "hostname": "dotnetcli", "version": "[10.0.100,)" }` | the invalid host ID `dotnet-cli`, or unrelated `pattern` / `value` fields |
| Restrict the active SDK version | an `sdk-version` constraint with a NuGet version/range string in `args` | a machine-specific exact patch unless the template truly requires it |
| Preserve CPM | keep generated `PackageReference` items versionless and package the owning `Directory.Packages.props` when the template is self-contained | adding inline `Version` attributes |

### Step 1: Bootstrap from existing project

Analyze the source `.csproj` and create a `.template.config/template.json`:
Expand Down Expand Up @@ -95,11 +107,36 @@ Quick summary of what gets checked:
Based on validation results and user requirements:

1. **Add parameters** with appropriate types (string, bool, choice), defaults, and descriptions
2. **Add conditional content** using `#if` preprocessor directives for optional features
2. **Add conditional content** using the file type's valid syntax. In XML use template
directives inside XML comments, not bare preprocessor lines:

```xml
<!--#if (database == "SqlServer") -->
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<!--#endif -->
<!--#if (database == "Postgres") -->
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<!--#endif -->
```
3. **Configure post-actions** for solution add, restore, or custom scripts
4. **Set constraints** to restrict which SDKs or workloads the template supports
5. **Add classifications** and tags for discoverability

For a restore post-action, prefer `primaryOutputs` when the project path is known:

```json
"primaryOutputs": [{ "path": "MyProject.csproj" }],
"postActions": [{
"description": "Restore NuGet packages.",
"manualInstructions": [{ "text": "Run 'dotnet restore'." }],
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
"continueOnError": true
}]
```

If `args.files` is needed, its paths are matched against the **source template** before
renames, for example `"files": ["**/*.csproj"]`. Explain that distinction.

### Step 4: Test the template locally

```bash
Expand All @@ -117,6 +154,8 @@ dotnet build ./test-output/TestProject
- [ ] Template can be installed, dry-run, and instantiated successfully
- [ ] Created projects build cleanly with `dotnet build`
- [ ] Conditional content produces correct output for all parameter combinations
- [ ] XML template directives are wrapped in XML comments and the generated project parses
- [ ] Host constraints use `args[].hostname`; restore actions use `primaryOutputs` or `args.files`

## Common Pitfalls

Expand All @@ -128,6 +167,7 @@ dotnet build ./test-output/TestProject
| Not testing all parameter combinations | Use `dotnet new <template> --dry-run` with different parameter values to verify conditional content works correctly. |
| Hardcoded versions in template | Use `sourceName` replacement for project names and consider parameterizing framework versions. |
| Not setting classifications | Add appropriate `classifications` (e.g., `["Web", "API"]`) for template discovery. |
| Reusing fields from a different constraint or post-action | Follow the exact schema: `host.args[].hostname`, and restore `args.files` rather than run-script fields. |

## More Info

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ a comparison table.

## Workflow

**Evidence contract:** a side-by-side table is useful only when every option claim is
grounded in the currently installed templates. Run each `--help` command sequentially,
capture the same requested dimensions for each template, and label an unavailable option
as `Not exposed` rather than guessing or borrowing a flag from another template.

### Step 1: Inspect each template

Run `dotnet new <template> --help` for each template being compared to collect its
Expand All @@ -49,8 +54,8 @@ dotnet new webapi --help
dotnet new webapp --help
```

If a template is not installed, find and install it first (`dotnet new search <keyword>`,
then `dotnet new install <package>`).
If a template is not installed, search for its provider and report the missing prerequisite.
Install it only when the user asked you to modify the environment or approved the install.

> **Run `--help` calls sequentially.** The template engine uses a global mutex, so running
> several `dotnet new <template> --help` commands concurrently can fail with a transient
Expand All @@ -67,6 +72,10 @@ Produce a side-by-side table covering:
- **Available frameworks** — e.g., net8.0, net9.0, net10.0
- **Classifications** — categories the template advertises (Web, API, Blazor, etc.)

Use one row per requested decision dimension and cite the observed option name in the cell.
Do not fill a requested row with general framework knowledge when it is specifically about
what the template generates or exposes.

Example shape:

| Aspect | `webapi` | `webapp` |
Expand All @@ -88,7 +97,8 @@ Then link to `template-instantiation` to create it. A comparison that ends witho

### Decision shortcuts for common pairs

Use these as the opinionated default when the user hasn't given a countervailing constraint. Still inspect with `--help` to confirm parameters, but lead with the verdict:
Use these only for the recommendation, not as evidence of current parameter support. Still
inspect with `--help` before filling the comparison table:

| Pair | Default pick | Because |
|------|-------------|---------|
Expand All @@ -103,6 +113,8 @@ Use these as the opinionated default when the user hasn't given a countervailing
- [ ] The comparison covers parameters, feature support, frameworks, and classifications
- [ ] Differences relevant to the user's scenario are called out explicitly
- [ ] A recommendation (or clear trade-off) is provided
- [ ] Unsupported or absent options are labeled instead of guessed
- [ ] The final recommendation is a single decisive `Recommendation:` line

## Common Pitfalls

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ This skill helps an agent find, inspect, and select the right `dotnet new` templ
> result under load, leaving the user nothing. Always close with the written recommendation, and
> never end a turn on a "let me confirm from the CLI…" teaser.

> **Inspection requests require inspection.** If the user asks for installed choices,
> exact parameters/defaults, compatibility constraints, or the exact dry-run file list,
> run the corresponding `dotnet new` command. Do not replace observed data with remembered
> flags. Report a flag only when the current template's `--help` output contains it.

## Inputs

| Input | Required | Description |
Expand Down Expand Up @@ -148,6 +153,11 @@ Use `dotnet new <template> --help` to get full parameter details for a specific
dotnet new webapi --help
```

Copy the observed option names, choices, defaults, and compatibility notes into the answer.
For example, Windows Service support is not universally a worker-template flag. If the
installed `worker --help` does not expose one, say so and distinguish template creation from
post-creation hosting configuration; never invent `--windows` or `--use-windows-service`.

### Step 4: Preview output

Use `dotnet new <template> --dry-run` to show what files and directories a template would create without writing anything to disk:
Expand All @@ -158,6 +168,10 @@ dotnet new webapi --name MyApi --auth Individual --dry-run

If the dry-run fails (transient "mutex"/"persistence" error), retry once; if it still fails, give a **representative** structure (template *family* and typical file kinds) and note it isn't CLI-confirmed. Do not invent specific values, choices, or file paths. When the dry-run **succeeds**, present the actual file list from its output faithfully — don't summarize, regroup, or invent files — and add a one-line purpose for the key entry points (e.g. `Program.cs`, `App.razor`).

If the user says not to create files, every copy-pasteable creation command must include
`--dry-run`. A plain `dotnet new ...` command contradicts that request even when you did not
execute it yourself.

### Step 5: Present findings

**Lead with the answer as a ready-to-run command**, then justify it. Required shape:
Expand All @@ -179,6 +193,8 @@ An answer without a concrete, copy-pasteable command is what makes this skill ti
- [ ] At least one template match was found for the user's intent
- [ ] Template parameters are explained with types and defaults
- [ ] User understands what the template produces before proceeding to creation
- [ ] Exact-option claims came from this template's observed `--help` output
- [ ] Advice-only commands that must not create files include `--dry-run`

## Common Pitfalls

Expand All @@ -189,6 +205,7 @@ An answer without a concrete, copy-pasteable command is what makes this skill ti
| Not checking template constraints | Some templates require specific SDKs or workloads. Use `dotnet new <template> --help` to surface constraints before recommending. |
| Recommending a template without previewing output | Always use `dotnet new <template> --dry-run` to confirm the template produces what the user expects. |
| A `dotnet new` call fails with a "mutex"/"persistence" error and you return nothing | These are transient (often from concurrent invocations). Run `dotnet new` calls sequentially, retry once, then fall back to the Step 1 intent mapping and still give the user a concrete answer. |
| Guessing a Windows Service or AOT flag from another SDK/template | Quote only options observed in `dotnet new <template> --help`; otherwise explain the post-creation path. |

## More Info

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ This skill creates .NET projects from templates using `dotnet new` CLI commands,

> **Match the workspace, then stop.** The highest-value move is aligning the new project with the repo it lands in: detect **CPM** (`Directory.Packages.props`) and the **target framework** used by neighbouring `.csproj` files, and mirror both. **Treat the discovered target framework as an explicit choice** — pass it as `--framework` so `template-smart-defaults` won't override it; deviate only when it's incompatible with a requested feature (then flag the conflict). Do this in as few steps as possible — a `--dry-run`, the create, and one `dotnet build` to confirm is usually enough. Extra exploratory turns add cost without improving the result.

| Situation | Required action |
|-----------|-----------------|
| Simple standalone project | inspect only the requested template, create at the exact path, then build |
| Existing neighboring projects | read their TFMs first and pass the matching supported `--framework` explicitly |
| `Directory.Packages.props` found | create with `--no-restore` when supported, normalize generated package references, then restore/build once |
| Multi-project solution | create each project at its final path, add references, add all projects to the solution, then build the solution once |

## When to Use

- User asks to create a new .NET project, app, or service
Expand Down Expand Up @@ -79,6 +86,12 @@ Use `dotnet new` with the template name and all parameters:
dotnet new webapi --name MyApi --output ./src/MyApi --framework net10.0 --auth Individual
```

Before running it, emit one compact decision line:

`Creating <template> at <path>; framework=<value> (<user|workspace|template>); CPM=<on|off>.`

This makes workspace adaptations explicit without adding a long report.

#### Common parameter combinations

| Template | Parameters | Example |
Expand All @@ -93,14 +106,16 @@ Note: Use `dotnet new <template> --help` to see all available parameters for any

After creation, adapt the project to Central Package Management and refresh stale versions:

1. **Detect CPM** — walk up the directory tree from the new project looking for a `Directory.Packages.props`.
2. **Strip inline versions** — if found, for each `<PackageReference Include="X" Version="Y" />` the template generated, remove the `Version` attribute from the `.csproj` (leaving `<PackageReference Include="X" />`).
3. **Centralize the version** — add or merge a `<PackageVersion Include="X" Version="Y" />` entry in `Directory.Packages.props`.
4. **Optionally refresh stale template-default versions** — templates often hardcode old versions. Keep the template's versions by default (safest for reproducibility and controlled upgrades). Only refresh when the user asks, and when you do:
1. **Detect CPM before creation** — walk up from the destination looking for `Directory.Packages.props`.
2. **Avoid a doomed automatic restore** — when CPM is active and the template exposes
`--no-restore`, pass it during creation so package centralization happens first.
3. **Strip inline versions** — for each generated `<PackageReference Include="X" Version="Y" />`, remove the `Version` attribute (leaving `<PackageReference Include="X" />`).
4. **Centralize the version** — add or merge a `<PackageVersion Include="X" Version="Y" />` entry in `Directory.Packages.props`; preserve unrelated existing entries.
5. **Optionally refresh stale template-default versions** — templates often hardcode old versions. Keep the template's versions by default (safest for reproducibility and controlled upgrades). Only refresh when the user asks, and when you do:
- Prefer a tooling-driven flow: run `dotnet list package --outdated` and confirm the proposed bumps with the user before changing anything.
- Constrain upgrades to the same **major** (or major/minor) version unless the user explicitly opts into larger upgrades, since cross-major bumps can introduce breaking changes.
- When checking the latest **stable** version of a package conceptually, the NuGet V3 flat-container `index.json` endpoint for that package ID lists published versions; never select a prerelease unless requested.
5. **Build** — run `dotnet build` to confirm the centralized/refreshed versions resolve.
6. **Build** — run `dotnet build` once to restore and confirm the centralized/refreshed versions resolve.

### Step 5: Multi-project composition (optional)

Expand Down Expand Up @@ -141,6 +156,7 @@ dotnet new uninstall Microsoft.DotNet.Web.ProjectTemplates.10.0
| Pitfall | Solution |
|---------|----------|
| Not checking for CPM before creating a project | If `Directory.Packages.props` exists, `dotnet new` creates projects with inline versions that conflict. After creation, move versions to `Directory.Packages.props` and remove them from `.csproj`. |
| Letting template restore fail before adapting CPM | Detect CPM first and use the template's `--no-restore` option when available; centralize versions before the first restore/build. |
| Creating projects without specifying the framework | Always specify `--framework` when the template supports multiple TFMs to avoid defaulting to an older version. |
| Not adding the project to the solution | After creation, run `dotnet sln add` to include the project in the solution. |
| Not verifying the project builds | Always run `dotnet build` after creation to catch missing dependencies or parameter issues early. |
Expand Down
Loading
Loading