Restructure template, add configurable description, remove comments

- Remove LoadPriority override from EntryPoint.cs (defaults to Medium)
- Add Description property (was already templated as a literal, now a
  configurable PluginDescription symbol like PluginAuthor)
- Move the buildable project into content/ so CLAUDE.md, .editorconfig,
  and .gitignore never ship in a generated plugin, and the project no
  longer shares its root with them
- Remove the SkipGit symbol and its manual-instructions postAction:
  automatic git init on generation was re-verified impossible (no
  --allow-scripts equivalent on dotnet 10 SDK to bypass the Run Script
  postAction's interactive Y/N gate); VS's own New Project checkbox
  already covers this
- Add content/CLAUDE.md so every generated plugin ships with LabAPI/
  toolchain/code-style context for Claude Code, since no C#/.NET/LabAPI
  Skill exists in the catalog
- Set PluginAuthor/PluginDescription defaultValue to generic "Your
  Name"/"Your Description" placeholders instead of "YourName"/a TODO
  string
- Strip all comments from the .csproj (project code style forbids them)

Verified by generating a project from the reinstalled template and
running dotnet build (0 warnings, 0 errors) after each change.
This commit is contained in:
2026-08-27 02:09:55 +02:00
parent 2151884527
commit 68fac5b913
8 changed files with 187 additions and 107 deletions
+88 -45
View File
@@ -13,10 +13,9 @@ are ordinary project files at that point, not template scaffolding.
## Repo is template *source* — read before touching any file
`.template.config/template.json` sets this folder's name as the template's
`sourceName` and defines one text-replacement `symbol`, `PluginAuthor` (plus
`SkipGit`, which only toggles the git-reminder post-generation action and replaces no
text). The dotnet templating engine does a literal, repo-wide **string replacement**
at generation time — not semantic renaming — driven by that config:
`sourceName` and defines one text-replacement `symbol`, `PluginAuthor`. The dotnet
templating engine does a literal, repo-wide **string replacement** at generation
time — not semantic renaming — driven by that config:
- The folder/project name (`sourceName` in `template.json`, currently this repo's own
folder name) → whatever `-n`/`--name` the consumer passes to `dotnet new`.
@@ -41,50 +40,86 @@ Consequences:
## Repo layout (only what affects decisions)
- `.template.config/template.json` — template identity, the symbols above plus
`SkipGit` (a display-only toggle, see below), `primaryOutputs` (points at the
project file using its pre-substitution literal name — that's correct and expected,
not a bug), and two `postActions`: the standard dotnet-templating "restore NuGet
packages" action (id `210D431B-...`; skipped in Visual Studio, which restores on
its own) and a "display manual instructions" action (id `AC1156F7-...`) that prints
a reminder to run `git init` — see "Git on generation" below for why it's just a
printed reminder and not an executed command.
- Repo root holds only template-source/maintenance files that must **never** ship in
a generated project: `.git/`, `.gitignore`, `.editorconfig`, `CLAUDE.md`, and
`.template.config/`. None of these are copied to generated output — see "content/
vs. repo root" below.
- `.template.config/template.json` — template identity, the `PluginAuthor` symbol,
a `sources` entry that maps `./content` → the output root (this is what keeps the
root-level files above out of every generated project), `primaryOutputs` (points at
the project file using its pre-substitution literal name, relative to `content/` —
that's correct and expected, not a bug), and one `postAction`: the standard
dotnet-templating "restore NuGet packages" action (id `210D431B-...`; skipped in
Visual Studio, which restores on its own).
- `.template.config/ide.host.json` — Visual Studio-only UI hints for the New Project
wizard. It does **not** rename any symbol (the CLI flags stay `PluginAuthor`/
`SkipGit` — a flag can't contain a space); it only maps each symbol's `id` to a
human-readable `name.text` label (e.g. `SkipGit` → "Skip Git") shown in VS's UI, via
`isVisible: "true"` per entry (VS hides a symbol from that UI unless explicitly
marked visible here). Ignored entirely by `dotnet new` on the CLI.
- The `.csproj` at the repo root — the project file every generated plugin ships with.
- `EntryPoint.cs` / `Config.cs` — the scaffolded plugin (`Plugin<Config>`) and its
YAML-backed settings class.
- `.editorconfig` — formatting/naming only (indentation, brace style). It does **not**
enforce the comment/language rules below — those aren't analyzer-checkable.
wizard. It does **not** rename the `PluginAuthor` symbol (a flag can't contain a
space); it only maps the symbol's `id` to a human-readable `name.text` label shown
in VS's UI, via `isVisible: "true"` (VS hides a symbol from that UI unless
explicitly marked visible here). Ignored entirely by `dotnet new` on the CLI.
- `content/` — the actual buildable project, and the only folder the `sources`
mapping in `template.json` copies into generated output: `LabApiPluginTemplate.csproj`,
`EntryPoint.cs`, `Config.cs`, and `content/CLAUDE.md`. Add any new file that should
ship with generated plugins in here, not at the repo root.
- `content/CLAUDE.md` is a **different file** from this one (the repo-root
`CLAUDE.md`, which is template-editing guidance and never ships). It's the project
memory a generated plugin ships with, so Claude Code has LabAPI/toolchain/style
context automatically in every plugin generated from this template, without
depending on any C#/.NET/LabAPI Skill existing in the catalog (none currently does —
re-check with `SearchSkills`/`ToolSearch` before assuming that's still true). Keep
its LabAPI-contract/toolchain/style sections in sync with this file's equivalent
sections when either changes; `content/CLAUDE.md` omits everything specific to
editing *this* template repo (symbols, `sources` mapping, `sourceName` traps, the
verification workflow below) since none of that applies to a generated plugin.
- No `.sln`, no test project, no CI, no packaging (`.nupkg`) project, no GitHub
Copilot instructions file currently exist in this folder. Don't assume any of them.
This repo itself does have its own git history (see `git log`) — that's unrelated
to whether a *generated* project gets one, which is what "Git on generation" below
covers.
## `content/` vs. repo root — why the project isn't at the repo root
Early versions of this template had the `.csproj`/`.cs` files sitting directly next
to `.gitignore`/`.editorconfig`/`CLAUDE.md`/`.template.config/` at the repo root, with
no `sources` entry in `template.json`. Because `dotnet new` copies everything under
the mounted template root except `.template.config/` by default, every one of those
maintenance files silently ended up inside every generated plugin too.
The fix: `content/` holds only what should be copied, and `template.json` declares
`"sources": [{ "source": "./content", "target": "./" }]`. Files outside `./content`
(root-level `.gitignore`, `.editorconfig`, `CLAUDE.md`) are never touched by
generation — no exclude-list to maintain.
Do **not** nest a folder named `LabApiPluginTemplate` inside `content/` (e.g.
`content/LabApiPluginTemplate/EntryPoint.cs`). `sourceName` substitution renames any
folder whose name matches it, so an inner folder named after the project would get
renamed too, producing a doubled-up output path like
`<output>/<ProjectName>/<ProjectName>/<ProjectName>.csproj` instead of the flat
`<output>/<ProjectName>/<ProjectName>.csproj` consumers expect. Keep the `.csproj`/
`.cs` files directly under `content/`.
## Git on generation — why there's no automated `git init`
A generated project is **not** a git repository by default; a `postAction` only
prints a reminder to run `git init && git add -A && git commit -m "Initial commit"`.
This was a deliberate choice after testing the alternative:
A generated project is **not** a git repository, and there is no `postAction` that
tries to make it one. This was verified, not assumed — re-verified against the
`dotnet` 10.0.400 SDK on this machine while working on this exact question:
- `dotnet new`'s only postAction capable of running an arbitrary process is the
"Run script" action (id `3A7C4B45-...`). Actually wiring it to run `git init`/
`git add`/`git commit` was tested and it **hangs forever** in any non-interactive
shell: the CLI's script-execution security gate demands an explicit `Y` typed at a
`Do you want to run this action [Y(yes)|N(no)]?` prompt, once per script action,
with no flag on this SDK to pre-approve it — unlike the NuGet-restore postAction,
which the CLI treats as trusted and never gates. Do not reintroduce "Run script"
postActions for this without re-verifying that gate no longer applies.
"Run script" action (id `3A7C4B45-...`). Wiring it to run `git init`/`git add`/
`git commit` hangs forever in any non-interactive shell: the CLI's script-execution
security gate demands an explicit `Y` typed at a
`Do you want to run this action [Y(yes)|N(no)]?` prompt, once per script action.
`dotnet new create --help` on this SDK exposes no `--allow-scripts` or equivalent
flag to pre-approve it (unlike the NuGet-restore postAction, which the CLI treats
as trusted and never gates). Do not reintroduce "Run script" postActions for this
without re-verifying that gate no longer applies on whatever SDK is current then.
- A previous revision compensated with a `SkipGit` symbol plus a "display manual
instructions" postAction that just printed the `git init` one-liner. That has been
removed — it wasn't automation, just a reminder to run a command any git user
already knows, so it wasn't worth the extra symbol/postAction/`ide.host.json` entry.
- Visual Studio's own "New Project" dialog already has a built-in "Create new Git
repository" checkbox that works for any template, including this one, with zero
template-side configuration — so VS users get this for free regardless.
- CLI users see the printed reminder above (governed by the `SkipGit` symbol) and run
the one-liner themselves.
template-side configuration — so VS users get real automatic git init for free.
CLI users just run `git init` themselves after generating.
## LabAPI contract (verified against northwood-studios/LabAPI source, not guessed)
@@ -121,7 +156,8 @@ assume one exists.
`NU1701` (via a per-`PackageReference` `<NoWarn>`, not a project-wide one) and
`MSB3270` (via `ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch=None`). Don't
broaden either into a blanket suppression and don't remove them without
understanding why (comments sit next to both in the `.csproj`).
understanding why (both are explained here, not in the `.csproj` — this repo's
code style forbids comments, including in the `.csproj`, see "Code style" below).
- The `Northwood.LabAPI` `PackageReference` uses a floating `Version="*"` on purpose,
so every `dotnet restore` always pulls whatever is the latest stable release on
NuGet at that moment — there's no version to bump here. This is intentionally
@@ -136,10 +172,10 @@ assume one exists.
## Code style for anything you write here
- No `//`, `/* */`, or `///` comments unless the user explicitly asks for
comments/documentation in that request. No comments restating self-explanatory code.
`EntryPoint.cs`/`Config.cs` are already comment-free — keep them that way and follow
the same standard for any new file.
- No `//`, `/* */`, `///`, or XML (`<!-- -->`) comments unless the user explicitly
asks for comments/documentation in that request. No comments restating
self-explanatory code. `EntryPoint.cs`/`Config.cs`/the `.csproj` are already
comment-free — keep them that way and follow the same standard for any new file.
- All text embedded in code defaults to **English**: string/log/console messages,
exception messages, `[Description]`/config text, any user-facing string. Example:
`Logger.Info("Plugin initialized successfully")`, not a Spanish equivalent.
@@ -170,10 +206,17 @@ Notes:
- Re-run `dotnet new uninstall .` + `dotnet new install .` after **any** edit to
`.template.config/template.json` or the scaffolded files — the template cache
keys off the installed path and stale content otherwise gets regenerated.
- `dotnet build` also works directly inside `<repo-name>` (the placeholder project
is itself valid and compilable), but that only proves the *unsubstituted*
placeholder compiles — it does not exercise symbol substitution. Always additionally
verify through an actual `dotnet new` generation before calling a change done.
- `dotnet build` also works directly inside `content/` (the placeholder project is
itself valid and compilable), but that only proves the *unsubstituted* placeholder
compiles — it does not exercise symbol substitution or the `sources` mapping.
Always additionally verify through an actual `dotnet new` generation before calling
a change done.
- If `dotnet new install .` warns about another installed template sharing this
identity (`SCPSL.LabApi.PluginTemplate`) from a different path — e.g. this repo's
own parent folder having been installed by an earlier mistaken
`dotnet new install .` run one level up — that other install shadows this one and
your edits won't be exercised. Run `dotnet new uninstall <that other path>` first.
- On Windows, if cleaning up `../_verify` fails with "resource busy", run
`dotnet build-server shutdown` first, then retry.
`dotnet build-server shutdown` first, then retry; if it still won't delete, fall
back to PowerShell's `Remove-Item -Recurse -Force`.
- Delete the `../_verify` scratch output when done; it isn't part of the template.