diff --git a/AGENTS.md b/AGENTS.md index 8df5f93..427813d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,9 +24,12 @@ Every repo-managed skill must include its own `evals/evals.json` file at `skills - Treat this as a required artifact for every first-party skill in this repo - Run evals **per skill**, not as one shared repo-level eval file - Run evals from a temp workspace such as `$env:TEMP/-workspace/`, never from inside this repository +- When creating or modifying a repo-managed skill, run both `with_skill` and `without_skill` comparison executions from that temp workspace before the work is considered complete +- For a brand-new skill, the baseline is `without_skill`; for an existing skill, use either `without_skill` or the previous/original skill version as the baseline, matching the `skill-creator` benchmark flow +- Generate the human-review artifacts too: aggregate the comparison into `benchmark.json` and launch `eval-viewer/generate_review.py` from the installed Anthropic `skill-creator` copy (typically under `~/.agents/skills/skill-creator/` or `~/.claude/skills/skill-creator/`) so the user can inspect `Outputs` and `Benchmark` before sign-off - Deterministic scaffold/template skills must keep local deterministic validators as well; evals supplement validators, they do not replace them -If you add a new skill or modify an existing repo-managed skill, update that skill's `evals/evals.json` before considering the work complete. +If you add a new skill or modify an existing repo-managed skill, update that skill's `evals/evals.json` before considering the work complete. Do not commit temp workspaces, benchmark outputs, or generated review files into this repository unless the user explicitly asks for checked-in artifacts. ## Git Identity @@ -138,19 +141,19 @@ Native input widgets are a **host/runtime feature**, not a guaranteed model capa - Do not switch interaction styles mid-collection unless the host explicitly upgrades from plain text to native controls - Favor consistency and low-friction UX over conversational variety during parameter collection -`FORMS.md` defines each field with: -- **type** — `text`, `single-choice`, or `multi-choice` -- **prompt** — the question to ask -- **choices** — options for choice types -- **default** — pre-filled value (mark as Recommended) -- **required** — whether the field is mandatory - -Presentation rules (enforced in every `FORMS.md`): -- Ask one field at a time — never bundle multiple questions -- Use selectable choices for `single-choice` and `multi-choice` fields — not free text -- When a default exists, present it first and append "(Recommended)" -- For `text` fields with a computed default, offer the computed value as a selectable choice alongside free text -- After all fields are collected, present a summary and ask for confirmation +`FORMS.md` defines each field with: +- **type** — `text`, `single-choice`, or `multi-choice` +- **prompt** — the question to ask +- **choices** — options for choice types +- **default** — pre-filled value (mark as Recommended) +- **required** — whether the field is mandatory + +Presentation rules (enforced in every `FORMS.md`): +- Ask one field at a time — never bundle multiple questions +- Use selectable choices for `single-choice` and `multi-choice` fields — not free text +- When a default exists, present it first and append "(Recommended)" +- For `text` fields with a computed default, offer the computed value as a selectable choice alongside free text +- After all fields are collected, present a summary and ask for confirmation This applies to all skills that collect user input, not just scaffolding skills. diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f752a..0649db3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,31 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [0.3.1] - 2026-03-19 + +This is a patch release introducing three new NuGet-focused skills and runner-agnostic benchmark tooling, with enhanced release automation, comprehensive documentation standardization, and skill refinements. + +### Added + +- `git-nuget-release-notes` skill that creates or updates per-package `.nuget/{ProjectName}/PackageReleaseNotes.txt` files from git history for .NET repositories, with per-skill evals and extracted package release-notes format reference, +- `git-nuget-readme` skill that writes package-facing NuGet READMEs from actual project metadata, git history, and source-backed capability cues, with per-skill evals and README blueprint reference, +- `skill-creator-agnostic` skill that adds runner-agnostic guardrails on top of Anthropic's skill-creator for creating, modifying, and benchmarking skills across Codex, GitHub Copilot, Opus, and similar agents, with enforced temp-workspace isolation and valid benchmark layout. + +### Changed + +- Enhanced `git-keep-a-changelog` with explicit release-intent trigger words ("finalize", "ready to release", "rtr", "release") that automatically extract and use versions from branch names, streamlining release finalization without manual version input, +- Tightened `git-visual-commits` commit body repair checks to treat short prose bodies wrapped mid-sentence as verification failures that must be repaired before success is reported, with targeted eval coverage, +- Clarified that unscoped `git bot commit` requests apply to the entire worktree unless the user explicitly narrows scope, with eval coverage ensuring yolo mode still groups the full diff, +- Standardized documentation across AGENTS.md, CONTRIBUTING.md, and README.md to explicitly instruct users to resolve the installed Anthropic skill-creator path (typically under `~/.agents/skills/skill-creator/` or `~/.claude/skills/skill-creator/`) before running benchmark and review tools, +- Updated benchmark layout specification from `eval-N` pattern to `iteration-N/eval-name/{config}/run-N/` for clarity and consistency, with PowerShell resolver logic that probes both skill-creator install locations, +- Normalized line wrapping and formatting across all SKILL.md, FORMS.md, and references/ files for improved readability and consistent presentation, removing extra blank lines and compacting multi-line YAML descriptions, +- Normalized line wrapping in shared asset templates including .github/copilot-instructions.md, asset CHANGELOG.md bootstrap files, and package documentation templates, +- Refreshed README catalog to reflect the current skill set and commit-behavior guidance, with updated benchmark and eval workflow documentation. + ## [0.3.0] - 2026-03-17 This is a minor release that introduces two complementary git workflow skills, extracts a shared commit-language reference, and backs the whole skill suite with pull-request validation plus stricter skill metadata checks. @@ -62,7 +82,8 @@ This is a minor release that introduces two complementary git workflow skills, e - Improved scaffold fidelity with hidden `.bot` asset preservation, explicit UTF-8 and BOM handling, and checks aimed at preventing mojibake or incomplete generated output. -[Unreleased]: https://github.com/codebeltnet/agentic/compare/v0.3.0...HEAD +[Unreleased]: https://github.com/codebeltnet/agentic/compare/v0.3.1...HEAD +[0.3.1]: https://github.com/codebeltnet/agentic/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/codebeltnet/agentic/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/codebeltnet/agentic/compare/v0.1.0...v0.2.0 [0.1.0]: https://github.com/codebeltnet/agentic/compare/7eaf364...v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 38f6094..a1a93cc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,31 +2,31 @@ Thanks for wanting to add or improve a skill. Here's what to know. -## Skill structure - -Each skill lives in its own folder: - -``` -skills/ - / - SKILL.md # Required — the skill content - FORMS.md # Optional — structured input collection for agents - assets/ # Optional — literal templates and static files - scripts/ # Optional — executable helpers - references/ # Optional — deeper docs loaded on demand - evals/ # Required for repo-managed skills — test prompts for validation - evals.json -``` - -## Local sync - -Repo-managed skills should be mirrored across all three locations: - -- `skills//` in this repo -- `~/.claude/skills//` -- `~/.agents/skills//` - -If you edit a local install copy first, copy the changed files back into the repo and into the other local install so every agent sees the same skill version. +## Skill structure + +Each skill lives in its own folder: + +``` +skills/ + / + SKILL.md # Required — the skill content + FORMS.md # Optional — structured input collection for agents + assets/ # Optional — literal templates and static files + scripts/ # Optional — executable helpers + references/ # Optional — deeper docs loaded on demand + evals/ # Required for repo-managed skills — test prompts for validation + evals.json +``` + +## Local sync + +Repo-managed skills should be mirrored across all three locations: + +- `skills//` in this repo +- `~/.claude/skills//` +- `~/.agents/skills//` + +If you edit a local install copy first, copy the changed files back into the repo and into the other local install so every agent sees the same skill version. ## SKILL.md format @@ -64,9 +64,9 @@ The `description` is the most important field — it's how the AI decides to loa - Specific trigger phrases (e.g. "Use when user says 'commit this' or 'stage changes'") - What it enforces or prevents -## Adding evals (required for repo-managed skills) - -Evals let you verify the skill works and measure improvement over a baseline. Every repo-managed skill in this repository must include `evals/evals.json`: +## Adding evals (required for repo-managed skills) + +Evals let you verify the skill works and measure improvement over a baseline. Every repo-managed skill in this repository must include `evals/evals.json`: ```json { @@ -81,50 +81,61 @@ Evals let you verify the skill works and measure improvement over a baseline. Ev } ``` -Aim for 3–5 evals that cover distinct scenarios: happy path, edge cases, and cases where the skill should *not* do something. - -Run evals from a temp workspace, not from this repository: - -```powershell -$workspace = Join-Path $env:TEMP '-workspace' -``` - -For scaffold/template skills, keep deterministic validators alongside evals. In this repo, `evals/evals.json` is mandatory, and validators like `scripts/validate-skill-templates.ps1` are additional protection. - -## Prefer dynamic defaults - -When a skill needs defaults for versions, paths, repository names, or support windows, prefer deriving them from a reliable source instead of baking in values that will drift. - -- Good sources: git metadata, repo folder names, environment values, official JSON feeds, vendor docs APIs -- Use hardcoded examples as examples only — not as the real defaulting mechanism — when the value can be computed - -## Template validation - -Use the repo validation harness before submitting scaffold or template changes: - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\validate-skill-templates.ps1 -``` - -Run the validator locally first for the fastest feedback loop. GitHub -Actions also runs the same script on pull requests, but CI is -the backstop, not the primary authoring loop. - -To compare a change against the initial imported version, run the same harness against a git ref: - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\validate-skill-templates.ps1 -Ref HEAD -``` - -## Checklist before submitting - -- [ ] `SKILL.md` has valid front matter with `name` and `description` -- [ ] Skill is stack-agnostic (or clearly scoped to a specific tech in the name/description) -- [ ] Examples are generic — no personal emails, usernames, or project-specific identifiers -- [ ] At least one eval in `evals/evals.json` -- [ ] The skill's `evals/evals.json` exists and its `skill_name` matches the folder/frontmatter name -- [ ] `scripts/validate-skill-templates.ps1` passes for the current working tree when changing scaffold or template behavior -- [ ] If CI is enabled for the branch, the GitHub Actions validation job passes too -- [ ] Skill evals are intended to run from `$env:TEMP/-workspace/`, not from inside the repo -- [ ] Changed skill files are synced across `skills//`, `~/.claude/skills//`, and `~/.agents/skills//` -- [ ] Skill added to the table in `README.md` +Aim for 3–5 evals that cover distinct scenarios: happy path, edge cases, and cases where the skill should *not* do something. + +Run evals from a temp workspace, not from this repository: + +```powershell +$workspace = Join-Path $env:TEMP '-workspace' +``` + +When creating or modifying a repo-managed skill, the eval workflow must include a paired comparison: + +- Resolve the installed Anthropic `skill-creator` path first, usually under `~/.agents/skills/skill-creator/` or `~/.claude/skills/skill-creator/`, then run its benchmark scripts from there +- Run each eval as `with_skill` +- Run the baseline as `without_skill` for new skills +- For an existing skill, use either `without_skill` or the previous/original skill version as the baseline, following the `skill-creator` benchmark model +- Aggregate the results into `benchmark.json` +- Launch `eval-viewer/generate_review.py` from that installed `skill-creator` copy so a human can review both `Outputs` and `Benchmark` + +This repo treats that paired `with_skill` / `without_skill` comparison as part of the required devex for skill work. The benchmark artifacts live in the temp workspace; do not commit them to this repository unless the change explicitly calls for checked-in examples. + +For scaffold/template skills, keep deterministic validators alongside evals. In this repo, `evals/evals.json` is mandatory, and validators like `scripts/validate-skill-templates.ps1` are additional protection. + +## Prefer dynamic defaults + +When a skill needs defaults for versions, paths, repository names, or support windows, prefer deriving them from a reliable source instead of baking in values that will drift. + +- Good sources: git metadata, repo folder names, environment values, official JSON feeds, vendor docs APIs +- Use hardcoded examples as examples only — not as the real defaulting mechanism — when the value can be computed + +## Template validation + +Use the repo validation harness before submitting scaffold or template changes: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\validate-skill-templates.ps1 +``` + +Run the validator locally first for the fastest feedback loop. GitHub Actions also runs the same script on pull requests, but CI is the backstop, not the primary authoring loop. + +To compare a change against the initial imported version, run the same harness against a git ref: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\validate-skill-templates.ps1 -Ref HEAD +``` + +## Checklist before submitting + +- [ ] `SKILL.md` has valid front matter with `name` and `description` +- [ ] Skill is stack-agnostic (or clearly scoped to a specific tech in the name/description) +- [ ] Examples are generic — no personal emails, usernames, or project-specific identifiers +- [ ] At least one eval in `evals/evals.json` +- [ ] The skill's `evals/evals.json` exists and its `skill_name` matches the folder/frontmatter name +- [ ] Skill changes were benchmarked from a temp workspace with both `with_skill` and `without_skill` runs +- [ ] `benchmark.json` and `eval-viewer/generate_review.py` from the installed Anthropic `skill-creator` copy were used so a human could compare `Outputs` and `Benchmark` +- [ ] `scripts/validate-skill-templates.ps1` passes for the current working tree when changing scaffold or template behavior +- [ ] If CI is enabled for the branch, the GitHub Actions validation job passes too +- [ ] Skill evals are intended to run from `$env:TEMP/-workspace/`, not from inside the repo +- [ ] Changed skill files are synced across `skills//`, `~/.claude/skills//`, and `~/.agents/skills//` +- [ ] Skill added to the table in `README.md` diff --git a/README.md b/README.md index 0c0047e..2cd86d4 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,21 @@ -# Agentic Skills - -A curated collection of [skills](https://skills.sh) — reusable instruction sets that teach AI agents how to follow specific workflows, conventions, and standards. Designed to work with any agent that supports the skills ecosystem: GitHub Copilot, Claude Code, Cursor, Codex, OpenCode, and [many more](https://skills.sh). - -## What are skills? - -Skills are Markdown files that an AI agent reads before responding. When a skill is active, the agent follows the rules it contains — consistently, across any tool or model that supports them. They're a lightweight way to encode your team's conventions once and apply them everywhere. - +# Agentic Skills + +A curated collection of [skills](https://skills.sh) — reusable instruction sets that teach AI agents how to follow specific workflows, conventions, and standards. Designed to work with any agent that supports the skills ecosystem: GitHub Copilot, Claude Code, Cursor, Codex, OpenCode, and [many more](https://skills.sh). + +## What are skills? + +Skills are Markdown files that an AI agent reads before responding. When a skill is active, the agent follows the rules it contains — consistently, across any tool or model that supports them. They're a lightweight way to encode your team's conventions once and apply them everywhere. + One repo-wide convention matters especially for scaffolding skills: prefer dynamic defaults over hardcoded values whenever a reliable source exists. Derive time-sensitive or environment-sensitive values from git metadata, repo state, or official machine-readable feeds so skills age gracefully instead of drifting. Another repo rule is intentionally strict: every repo-managed skill ships with its own `evals/evals.json`, and those evals are run per skill from a temp workspace instead of from inside this repository. -There is also an interim Codex compatibility workaround in [AGENTS.md](AGENTS.md): the repo mirrors the current `~/.codex/AGENTS.override.md` decision and code-change rules so they still apply even when a Codex build fails to auto-load that personal override file. +Another part of that workflow is now mandatory too: when a repo-managed skill is created or modified, the author must run both `with_skill` and `without_skill` comparison executions from a temp workspace, aggregate the results into `benchmark.json`, and open `eval-viewer/generate_review.py` from the installed Anthropic `skill-creator` copy, typically under `~/.agents/skills/skill-creator/` or `~/.claude/skills/skill-creator/`, so a human can review both the `Outputs` and `Benchmark` views before sign-off. For new skills the baseline is `without_skill`; for existing skills it can be `without_skill` or the previous/original skill version, matching the `skill-creator` benchmark flow. One more consistency rule matters for form-driven skills: native input fields are treated as a host feature, not something a model can rely on. Skills in this repo must stay usable with or without UI widgets, and must fall back to the same deterministic one-field-at-a-time flow when the host only supports plain chat. -Validation follows the same philosophy: run -`scripts/validate-skill-templates.ps1` locally for the fast feedback -loop, and let GitHub Actions rerun that same script on pull requests as -the safety net. That validator also checks skill frontmatter metadata -such as the 1024-character YAML description limit. - +Validation follows the same philosophy: run `scripts/validate-skill-templates.ps1` locally for the fast feedback loop, and let GitHub Actions rerun that same script on pull requests as the safety net. That validator also checks skill frontmatter metadata such as per-skill `evals/evals.json` files and the 1024-character YAML description limit; it does not replace the paired benchmark review workflow. + ## Install a skill Install any skill directly from this repository with a single command: @@ -33,46 +29,52 @@ For example: ```bash npx skills add https://github.com/codebeltnet/agentic --skill git-visual-commits ``` - -Then activate it in your agent. For example, in GitHub Copilot CLI: - -``` -Use the skill tool to invoke the "" skill. -``` - + +Then activate it in your agent. For example, in GitHub Copilot CLI: + +``` +Use the skill tool to invoke the "" skill. +``` + ## Always-on skills Depending on the agent runtime, skills installed via `npx skills add` may live in `~/.claude/skills/` and/or `~/.agents/skills/`. Treat both as personal global skill folders: if you use both toolchains, keep repo-authored skills mirrored between them so each agent sees the same version. Either way, installed skills are **automatically loaded in every session** — no manual invocation needed. The agent reads the skill's description and activates it when relevant (e.g. you say "commit this" and the `git-visual-commits` skill kicks in). - -If you want a bundle of skills always available, just install them all: - + +If you want a bundle of skills always available, just install them all: + ```bash npx skills add https://github.com/codebeltnet/agentic --skill git-visual-commits npx skills add https://github.com/codebeltnet/agentic --skill git-keep-a-changelog +npx skills add https://github.com/codebeltnet/agentic --skill git-nuget-release-notes +npx skills add https://github.com/codebeltnet/agentic --skill git-nuget-readme npx skills add https://github.com/codebeltnet/agentic --skill git-visual-squash-summary +npx skills add https://github.com/codebeltnet/agentic --skill skill-creator-agnostic npx skills add https://github.com/codebeltnet/agentic --skill trunk-first-repo npx skills add https://github.com/codebeltnet/agentic --skill dotnet-strong-name-signing # npx skills add https://github.com/codebeltnet/agentic --skill another-skill ``` - -### Scoping options - -| Location | Scope | When to use | -|----------|-------|-------------| -| `~/.agents/skills/` | All sessions, all projects | Global skills for agents that read the shared `~/.agents` install | -| `~/.claude/skills/` | All sessions, all projects | Your personal defaults — always on everywhere | -| `.claude/skills/` (in a repo) | Project-scoped | Shared team conventions for a specific codebase | -| `.github/skills/` (in a repo) | GitHub Copilot / VS Code | When your team uses Copilot agent mode in the IDE | - -> **Tip:** You can mix scopes. Install your personal favorites globally, and add project-specific skills to the repo so your whole team gets them. If you use both `~/.claude/skills/` and `~/.agents/skills/`, mirror repo-authored skills to both so sessions stay consistent. - -## Available Skills - + +### Scoping options + +| Location | Scope | When to use | +|----------|-------|-------------| +| `~/.agents/skills/` | All sessions, all projects | Global skills for agents that read the shared `~/.agents` install | +| `~/.claude/skills/` | All sessions, all projects | Your personal defaults — always on everywhere | +| `.claude/skills/` (in a repo) | Project-scoped | Shared team conventions for a specific codebase | +| `.github/skills/` (in a repo) | GitHub Copilot / VS Code | When your team uses Copilot agent mode in the IDE | + +> **Tip:** You can mix scopes. Install your personal favorites globally, and add project-specific skills to the repo so your whole team gets them. If you use both `~/.claude/skills/` and `~/.agents/skills/`, mirror repo-authored skills to both so sessions stay consistent. + +## Available Skills + | Skill | Description | |-------|-------------| | [git-visual-commits](skills/git-visual-commits/SKILL.md) | AI-driven git commit workflow with emoji (gitmoji-first), conventional prefixes, and three identity modes: bot-attributed (`git bot commit`), human-attributed (`git commit`), and collaborative (`git our commit` — agent analyzes authorship, human picks attribution). Includes commit body by default (opt out with `no-body`), semantic intent splitting, and auto-approval mode (`yolo` / `auto`). The agent does all the work either way. Stack-agnostic. | | [git-keep-a-changelog](skills/git-keep-a-changelog/SKILL.md) | Git-aware Keep a Changelog companion that creates or updates `CHANGELOG.md` from the current branch by default. Reads full commit subjects and bodies plus the net diff, infers a release heading from a branch version hint like `v0.3.0/...` when available, creates a compliant changelog if the file does not exist yet, writes a required SemVer-aware release highlight, preserves natural prose wrapping, and curates `Added` / `Changed` / `Fixed` style sections instead of dumping raw commit logs. | +| [git-nuget-release-notes](skills/git-nuget-release-notes/SKILL.md) | Git-aware NuGet release-notes companion for .NET repos that keep cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files. Discovers packable `src/` projects, resolves concrete package version and availability, creates missing files when needed, and writes per-package `ALM` / `Breaking Changes` / `New Features` / `Improvements` / `Bug Fixes` style notes from full commit context plus the net diff instead of dumping commit subjects. | +| [git-nuget-readme](skills/git-nuget-readme/SKILL.md) | Git-aware NuGet README companion for .NET repos that advertise a package from `src/`. Resolves the real packable project the README should sell, combines git history with actual package metadata, source capabilities, and relevant tests when feasible, preserves honest badge/docs/contributing sections, and writes a forthcoming, adoption-friendly `README.md` with repo-derived branding, clear value, install, framework-support, and quick-start guidance. | | [git-visual-squash-summary](skills/git-visual-squash-summary/SKILL.md) | Non-mutating grouped-summary companion to `git-visual-commits`. Turns noisy commit stacks into a curated set of compact summary lines for PR or squash contexts, preserving technical identifiers, merging overlap, dropping low-signal noise, highlighting distinct meaningful efforts, and avoiding changelog-style wording or unsupported claims. | +| [skill-creator-agnostic](skills/skill-creator-agnostic/SKILL.md) | Runner-agnostic overlay for Anthropic `skill-creator`. Adds repo and environment guardrails for skill authoring and benchmarking: temp-workspace isolation, `iteration-N/eval-name/{config}/run-N/` benchmark layout, valid `grading.json` summaries, generated `benchmark.json`, honest `MEASURED` vs `SIMULATED` labeling, and sync/README discipline for repo-managed skills. | | [dotnet-new-lib-slnx](skills/dotnet-new-lib-slnx/SKILL.md) | Scaffold a new .NET NuGet library solution following codebeltnet engineering conventions. Dynamic defaults for TFM/repository metadata, latest-stable NuGet package resolution, tuning projects plus a tooling-based benchmark runner, TFM-aware test environments, strong-name signing, NuGet packaging, DocFX documentation, CI/CD pipeline, and code quality tooling. | | [dotnet-new-app-slnx](skills/dotnet-new-app-slnx/SKILL.md) | Scaffold a new .NET standalone application solution following codebeltnet engineering conventions. Supports Console, Web, and Worker host families with Startup or Minimal hosting patterns; Web expands into Empty Web, Web API, MVC, or Web App / Razor, plus functional tests and a simplified CI pipeline. | | [trunk-first-repo](skills/trunk-first-repo/SKILL.md) | Initialize a git repository following [scaled trunk-based development](https://trunkbaseddevelopment.com/#scaled-trunk-based-development). Seeds an empty `main` branch and creates a versioned feature branch (`v0.1.0/init`), enforcing a PR-first workflow where content only reaches main through peer-reviewed pull requests. | @@ -94,12 +96,30 @@ npx skills add https://github.com/codebeltnet/agentic --skill git-visual-commits npx skills add https://github.com/codebeltnet/agentic --skill git-keep-a-changelog ``` +`git-nuget-release-notes` + +```bash +npx skills add https://github.com/codebeltnet/agentic --skill git-nuget-release-notes +``` + +`git-nuget-readme` + +```bash +npx skills add https://github.com/codebeltnet/agentic --skill git-nuget-readme +``` + `git-visual-squash-summary` ```bash npx skills add https://github.com/codebeltnet/agentic --skill git-visual-squash-summary ``` +`skill-creator-agnostic` + +```bash +npx skills add https://github.com/codebeltnet/agentic --skill skill-creator-agnostic +``` + `dotnet-new-lib-slnx` ```bash @@ -123,22 +143,23 @@ npx skills add https://github.com/codebeltnet/agentic --skill trunk-first-repo ```bash npx skills add https://github.com/codebeltnet/agentic --skill dotnet-strong-name-signing ``` - -### Why git-visual-commits? - -Commit messages are the most-read documentation in any codebase — yet they're usually an afterthought. "fix stuff", "wip", "address PR feedback" tells you nothing six months later. Writing good commits takes discipline, and when you're in flow, it's the first thing that slips. - -**git-visual-commits** handles the entire commit workflow— staging, diffing, crafting the message, choosing the right emoji — so every commit is consistent and meaningful without breaking your flow. Whether the agent authors the commit (`git bot commit`), you do (`git commit`), or you worked on it together (`git our commit`), the quality is the same. - -- **Gitmoji-first** — visual commit categories that are scannable at a glance + +### Why git-visual-commits? + +Commit messages are the most-read documentation in any codebase — yet they're usually an afterthought. "fix stuff", "wip", "address PR feedback" tells you nothing six months later. Writing good commits takes discipline, and when you're in flow, it's the first thing that slips. + +**git-visual-commits** handles the entire commit workflow— staging, diffing, crafting the message, choosing the right emoji — so every commit is consistent and meaningful without breaking your flow. Whether the agent authors the commit (`git bot commit`), you do (`git commit`), or you worked on it together (`git our commit`), the quality is the same. + +- **Gitmoji-first** — visual commit categories that are scannable at a glance - **Conventional prefixes** — `init`, `content`, `style`, `fix`, `refactor`, and `docs` as fallback when gitmoji isn't available - **Three identity modes** — bot, human, or collaborative — the agent does the work either way, you choose who gets credit - **Identity lock stays honest** — `git bot commit` means bot attribution, not just "AI did the work", and the flow now verifies the resulting author after commit - **Auto-approval** — say "yolo" or "auto" to skip the review gate when you trust the agent's judgment - **Yolo skips confirmation, not discipline** — auto-approval still requires semantic grouping, mixed-scope checks, and a visible commit plan summary before committing +- **Full worktree by default** — plain `git bot commit yolo` means "commit everything currently in git status and group it correctly", not "guess a narrower slice" - **Commit body by default** — every commit explains *why*, not just *what* — opt out with "tmi" or "no-body" - **Commit bodies are verified after write** — the workflow now checks the stored commit body so literal escape sequences like `\n` do not leak into history -- **Short bodies stay readable** — the workflow no longer hard-wraps short commit bodies at 72 characters and instead prefers normal prose with sentence-level judgment +- **Short bodies stay readable** — the workflow no longer hard-wraps short commit bodies at 72 characters, treats mid-sentence wrapping as a verification failure, and repairs the commit instead of leaving noisy prose in history - **Repo capability additions stay explicit** — adding a brand-new skill is grouped separately from refactoring an existing skill to support it - **Shared wording rules stay in lockstep** — the duplicated `commit-language.md` reference is kept byte-for-byte identical across both git-visual skills and checked locally plus in CI - **Semantic intent splitting** — groups commits by rationale, not just file type — config and test logic are always separate @@ -148,12 +169,7 @@ Commit messages are the most-read documentation in any codebase — yet they're ### Why git-visual-squash-summary? -Sometimes the history is already written and the only thing you need is -the final grouped summary. A long branch with fixups, rename follow-ups, -review nits, and repeated attempts often contains a few real change -themes buried inside a messy chronological story. That is where -**git-visual-squash-summary** fits: it reads the real history and diff, -then compresses them into a small set of truthful grouped lines. +Sometimes the history is already written and the only thing you need is the final grouped summary. A long branch with fixups, rename follow-ups, review nits, and repeated attempts often contains a few real change themes buried inside a messy chronological story. That is where **git-visual-squash-summary** fits: it reads the real history and diff, then compresses them into a small set of truthful grouped lines. - **Same visual language** — reuses the same prefix and emoji rules as `git-visual-commits` - **Grouped-lines only** — returns compact grouped lines only, not a title or body @@ -182,10 +198,51 @@ Writing `CHANGELOG.md` well is harder than it looks. Raw commit subjects are too - **Compare-link aware** — can update bottom-of-file compare links when a concrete release heading is added - **Not a commit dump** — curates the release story instead of copying git log output into Markdown +### Why git-nuget-release-notes? + +Repo-wide changelogs are useful, but NuGet packages often need package-scoped release notes that match the package actually being published. In codebelt-style repos, that means cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files with a very specific shape: concrete version and availability lines, `# ALM` first, and only the sections that the package really earned. + +**git-nuget-release-notes** reads the actual git history and net diff per packable `src/` project, resolves the package version and target framework availability, then updates the package-note files directly for review. + +- **Per-package, not repo-wide** — writes one truthful release block per publishable assembly/package +- **Concrete package metadata** — resolves `Version:` and `Availability:` from the branch/project instead of inventing placeholders +- **Current codebelt format** — follows the established `ALM`, `Breaking Changes`, `New Features`, `Improvements`, `Bug Fixes`, and optional `References` blueprint +- **Missing-file aware** — can create `.nuget/{ProjectName}/PackageReleaseNotes.txt` when a packable project should be represented +- **History-aware** — preserves cumulative newest-first package history instead of overwriting older entries +- **Not a commit dump** — uses full commit bodies plus the net diff and avoids line-by-line subject replay + +### Why git-nuget-readme? + +Choosing a NuGet package often happens fast: a developer lands on the README, scans the first screen, checks whether the package fits the problem, and looks for install guidance, supported frameworks, docs, and a quick example. If those signals are vague or buried, the package loses the moment even when the code is good. + +**git-nuget-readme** uses the actual git history, project metadata, and source-level capabilities of the advertised package to refresh the README into something that is both truthful and easier to adopt. + +- **Package-first README focus** — centers the README on the real packable project the repo is advertising +- **Devex-led structure** — pulls value proposition, installation, framework support, docs, and quick-start guidance closer to the top +- **Grounded sales copy** — improves the package pitch without inventing features, benchmarks, badges, or docs URLs +- **Source-backed examples** — prefers real namespaces, package IDs, capability areas, and test-backed usage hints from the codebase +- **Repo-derived identity** — uses the current repo's own naming and branding conventions instead of importing a `by ` pattern from another package family +- **Preserve the good parts** — keeps accurate badges, docs links, contributing guidance, and license sections when they are already working +- **Not a changelog in disguise** — uses git history for context but writes adoption-oriented README copy instead of replaying commit subjects + +### Why skill-creator-agnostic? + +Anthropic's `skill-creator` is an excellent base workflow, but the day-to-day friction usually comes from the environment around it: different runners, Windows/PowerShell encoding traps, benchmark layout mistakes, and the temptation to present a synthetic pipeline check as if it were a measured model benchmark. + +**skill-creator-agnostic** keeps the upstream workflow intact and adds the parts teams actually trip over when they want the same skill to hold up across Codex, GitHub Copilot, Opus, and similar agents. + +- **Overlay, not fork** — treats Anthropic `skill-creator` as the base and layers repo/runtime guardrails on top +- **Runner-agnostic by design** — chooses from available execution capability instead of assuming one vendor CLI +- **Benchmark-contract aware** — enforces `iteration-N/eval-name/{config}/run-N/`, valid `grading.json.summary`, and generated `benchmark.json` +- **Tool-path explicit** — points authors to the installed Anthropic `skill-creator` copy that provides `scripts/aggregate_benchmark.py` and `eval-viewer/generate_review.py` +- **Honest benchmark modes** — keeps `MEASURED` and `SIMULATED` runs clearly separated so pipeline validation never masquerades as model quality +- **PowerShell-safe** — calls out UTF-8 no BOM, stable counting, provider-path normalization, and other Windows-specific pitfalls +- **Repo-managed discipline** — keeps per-skill evals, local-install sync, and README updates in scope for first-party skills + ### Why dotnet-new-lib-slnx and dotnet-new-app-slnx? - -Starting a new .NET solution "from scratch" usually means copying from your last project, deleting half of it, and spending an hour wiring up CI, MSBuild props, versioning, and code quality tooling. Every new repo drifts slightly from the last one. Six months later, no two solutions look the same. - + +Starting a new .NET solution "from scratch" usually means copying from your last project, deleting half of it, and spending an hour wiring up CI, MSBuild props, versioning, and code quality tooling. Every new repo drifts slightly from the last one. Six months later, no two solutions look the same. + **dotnet-new-lib-slnx** and **dotnet-new-app-slnx** encode the full codebeltnet convention into repeatable scaffolds — from `Directory.Build.props` to CI pipelines to DocFX. Each skill is focused on its domain: libraries get multi-target frameworks, signing, and NuGet packaging; apps get host family selection, a conditional web-variant choice when needed, hosting patterns, and functional tests. > [!NOTE] @@ -202,7 +259,7 @@ Starting a new .NET solution "from scratch" usually means copying from your last - **Central package management stays authoritative** — app scaffolds keep NuGet versions in `Directory.Packages.props` and do not “repair” restore issues by inlining versions into generated project files - **Deterministic package resolution beats memory** — the app scaffold now ships a NuGet resolver script so agents can fetch current per-package versions instead of guessing from stale remembered examples - **Resolver script is non-interactive by default** — the app package resolver now defaults to the skill’s own `Directory.Packages.props`, so agents do not have to remember an extra template path argument during normal scaffolds -- **Library-only package set** — the library scaffold no longer carries leftover app/bootstrapper package placeholders that do not belong in class library templates +- **Library-only package set** — the library scaffold no longer carries leftover app/bootstrapper package placeholders that do not belong in class library templates - **Structured benchmarking** — the scaffold now keeps actual benchmark projects under `tuning/`, generates a solution-level `tooling/benchmark-runner` host with BenchmarkDotNet jobs derived from the selected TFMs, targets the runner itself at the highest selected supported runtime, and writes output to `reports/` - **Hidden shared assets preserved** — recursive scaffold copy includes dot-folders such as `.bot/`, so the generated repo gets the real `.bot/README.md` template instead of an improvised placeholder - **UTF-8 by default** — the scaffold explicitly tells generating agents to preserve UTF-8 when copying and writing text templates, matching the generated `.editorconfig` @@ -223,34 +280,34 @@ Starting a new .NET solution "from scratch" usually means copying from your last - **MinVer bootstrap warnings are expected** — in non-git or untagged folders, an initial `0.0.0-alpha.0` style version is expected until the repo is initialized and tagged - **Worker scaffolds build immediately** — Worker apps now include a starter `Worker.cs` template so the generated project compiles before custom logic is added - **Bootstrapper imports are explicit** — app templates now include the required `Codebelt.Bootstrapper.*` namespace imports instead of relying on missing implicit usings -- **Clear NuGet metadata mapping** — prompts and placeholders line up with package metadata such as `PackageProjectUrl` -- **Solo-friendly defaults** — company/publisher metadata can default straight from the author name for individual maintainers -- **Complete from the start** — CI pipeline, code quality, test infrastructure, and governance docs on day one -- **Template-driven** — real files with placeholders in `assets/`, not generated strings, so you can inspect and evolve them - -### Why dotnet-strong-name-signing? - -Generating a `.snk` file traditionally requires `sn.exe`, which is only available in the Visual Studio Developer PowerShell — a common pain point for developers using VS Code, Rider, or plain terminals. This skill uses `RSACryptoServiceProvider` from the .NET runtime itself, so it works in **any PowerShell or terminal** without special tooling. - -- **No `sn.exe` dependency** — uses pure .NET crypto available in any PowerShell session -- **Matches `sn.exe` defaults** — 1024-bit RSA by default, with 2048 and 4096 as options -- **Cross-platform** — works on Windows, macOS, and Linux with PowerShell 7+ or .NET runtime -- **Identity, not security** — [Microsoft's guidance](https://github.com/dotnet/runtime/blob/main/docs/project/strong-name-signing.md) is clear: strong names are about assembly identity, not cryptographic security - -### Why trunk-first? - -Most repositories start with `git init` followed by committing everything directly to `main`. This works — until someone force-pushes to main, or a half-finished feature lands without review. By the time you add branch protection, the history is already messy. - -**trunk-first-repo** flips this: main starts empty and stays clean from the very first commit. Every piece of content enters through a pull request. This gives you: - -- **Review from day one** — no "we'll add branch protection later" that never happens -- **Clean, meaningful history** — main tells the story of reviewed, approved changes -- **Version-aware branches** — `v0.0.1/spike-auth` vs `v1.0.0/release-prep` signals project maturity at a glance -- **Zero-friction setup** — one skill invocation, not a 10-step checklist - -## Repository structure - -``` +- **Clear NuGet metadata mapping** — prompts and placeholders line up with package metadata such as `PackageProjectUrl` +- **Solo-friendly defaults** — company/publisher metadata can default straight from the author name for individual maintainers +- **Complete from the start** — CI pipeline, code quality, test infrastructure, and governance docs on day one +- **Template-driven** — real files with placeholders in `assets/`, not generated strings, so you can inspect and evolve them + +### Why dotnet-strong-name-signing? + +Generating a `.snk` file traditionally requires `sn.exe`, which is only available in the Visual Studio Developer PowerShell — a common pain point for developers using VS Code, Rider, or plain terminals. This skill uses `RSACryptoServiceProvider` from the .NET runtime itself, so it works in **any PowerShell or terminal** without special tooling. + +- **No `sn.exe` dependency** — uses pure .NET crypto available in any PowerShell session +- **Matches `sn.exe` defaults** — 1024-bit RSA by default, with 2048 and 4096 as options +- **Cross-platform** — works on Windows, macOS, and Linux with PowerShell 7+ or .NET runtime +- **Identity, not security** — [Microsoft's guidance](https://github.com/dotnet/runtime/blob/main/docs/project/strong-name-signing.md) is clear: strong names are about assembly identity, not cryptographic security + +### Why trunk-first? + +Most repositories start with `git init` followed by committing everything directly to `main`. This works — until someone force-pushes to main, or a half-finished feature lands without review. By the time you add branch protection, the history is already messy. + +**trunk-first-repo** flips this: main starts empty and stays clean from the very first commit. Every piece of content enters through a pull request. This gives you: + +- **Review from day one** — no "we'll add branch protection later" that never happens +- **Clean, meaningful history** — main tells the story of reviewed, approved changes +- **Version-aware branches** — `v0.0.1/spike-auth` vs `v1.0.0/release-prep` signals project maturity at a glance +- **Zero-friction setup** — one skill invocation, not a 10-step checklist + +## Repository structure + +``` skills/ / SKILL.md # Required — the skill definition (loaded by the AI) @@ -260,11 +317,11 @@ skills/ references/ # Optional — detailed reference docs evals/ # Required for repo-managed skills — per-skill evals/evals.json ``` - -## Contributing - -See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add a new skill or improve an existing one. - -## License - -[MIT](LICENSE) + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add a new skill or improve an existing one. + +## License + +[MIT](LICENSE) diff --git a/skills/dotnet-new-app-slnx/FORMS.md b/skills/dotnet-new-app-slnx/FORMS.md index 18fb8a7..92f0687 100644 --- a/skills/dotnet-new-app-slnx/FORMS.md +++ b/skills/dotnet-new-app-slnx/FORMS.md @@ -1,6 +1,6 @@ # Parameter Form -Collect these parameters from the user before generating anything. Present each field **one at a time** using the agent's native input mechanism (e.g. `ask_user` with `choices`) when the host supports it. If native structured input widgets are unavailable, fall back to the deterministic plain-text interaction format described in the presentation rules below. Do not bundle multiple fields into a single message. +Collect these parameters from the user before generating anything. Present each field **one at a time** using the agent's native input mechanism (e.g. `ask_user` with `choices`) when the host supports it. If native structured input widgets are unavailable, fall back to the deterministic plain-text interaction format described in the presentation rules below. Do not bundle multiple fields into a single message. ## Fields @@ -10,46 +10,46 @@ Collect these parameters from the user before generating anything. Present each - **placeholder:** "e.g. PaymentService" - **required:** true -### root_namespace -- **type:** text -- **prompt:** "Root namespace prefix?" -- **placeholder:** "e.g. Acme, MyCompany" -- **default:** `{solution_name}` -- **description:** Present `{solution_name}` as the recommended namespace prefix. If the user leaves this field blank after seeing that default, accept `{solution_name}` and continue instead of asking again. -- **required:** true - -### target_framework -- **type:** text -- **prompt:** "Target framework?" -- **computed_default:** Newest generally supported .NET LTS channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json` (filter `.NET` entries where `support-phase` is `active` or `maintenance`, then pick the highest `release-type: lts` channel and format it as `net{major}.0`). -- **placeholder:** "e.g. net10.0" -- **description:** Offer every generally supported non-preview .NET LTS and STS channel from the official releases index so the user can choose any actively supported track. Present the newest LTS first as the recommended option, but keep older supported LTS and current STS choices available. Allow a custom TFM when needed. -- **required:** true +### root_namespace +- **type:** text +- **prompt:** "Root namespace prefix?" +- **placeholder:** "e.g. Acme, MyCompany" +- **default:** `{solution_name}` +- **description:** Present `{solution_name}` as the recommended namespace prefix. If the user leaves this field blank after seeing that default, accept `{solution_name}` and continue instead of asking again. +- **required:** true + +### target_framework +- **type:** text +- **prompt:** "Target framework?" +- **computed_default:** Newest generally supported .NET LTS channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json` (filter `.NET` entries where `support-phase` is `active` or `maintenance`, then pick the highest `release-type: lts` channel and format it as `net{major}.0`). +- **placeholder:** "e.g. net10.0" +- **description:** Offer every generally supported non-preview .NET LTS and STS channel from the official releases index so the user can choose any actively supported track. Present the newest LTS first as the recommended option, but keep older supported LTS and current STS choices available. Allow a custom TFM when needed. +- **required:** true + +### app_host_types +- **type:** multi-choice +- **prompt:** "What app host type(s) do you need?" +- **choices:** + - Console + - Web + - Worker +- **required:** true (at least one) + +### web_variant +- **type:** single-choice +- **prompt:** "Which web variant?" +- **show_when:** `app_host_types` includes `Web` +- **choices:** + - Web API (Recommended) + - Empty Web + - MVC + - Web App / Razor +- **default:** Web API +- **description:** Use `Web API` for HTTP APIs, `Empty Web` for a lean web host, `MVC` for controllers plus views, and `Web App / Razor` for Razor Pages. -### app_host_types -- **type:** multi-choice -- **prompt:** "What app host type(s) do you need?" -- **choices:** - - Console - - Web - - Worker -- **required:** true (at least one) - -### web_variant -- **type:** single-choice -- **prompt:** "Which web variant?" -- **show_when:** `app_host_types` includes `Web` -- **choices:** - - Web API (Recommended) - - Empty Web - - MVC - - Web App / Razor -- **default:** Web API -- **description:** Use `Web API` for HTTP APIs, `Empty Web` for a lean web host, `MVC` for controllers plus views, and `Web App / Razor` for Razor Pages. - -### hosting_pattern -- **type:** single-choice -- **prompt:** "Which hosting pattern?" +### hosting_pattern +- **type:** single-choice +- **prompt:** "Which hosting pattern?" - **choices:** - Minimal (Recommended) - Startup @@ -58,24 +58,24 @@ Collect these parameters from the user before generating anything. Present each ## Presentation Rules -1. Ask one field at a time — wait for the answer before presenting the next field. -2. Prefer the host's native structured input controls for every field when they are available. -3. If native structured input controls are unavailable, use this exact plain-text fallback: - - Start with `Field: ` - - Repeat the field prompt verbatim from this file - - For `single-choice` and `multi-choice`, show a numbered option list and let the user answer with the number or the exact option text - - For `text` fields with a `default` or `computed_default`, show `1. Use "" (Recommended)` and `2. Enter a custom value` - - After the user answers, restate the normalized value in one short line before moving on -4. For `single-choice` and `multi-choice` fields, present options as selectable choices when possible — otherwise use the numbered plain-text fallback above instead of an open free-text prompt. -5. When a field has a `default`, present it as the first choice and append "(Recommended)" if not already labeled. -6. For `text` fields with a computed default (e.g. `{solution_name}`), offer the computed value as a selectable choice alongside free text input. -7. If a field with a `default` or `computed_default` is shown to the user and they leave it blank, treat that as accepting the presented recommended value. Do not ask a second clarification question just because the typed response was empty. -8. For `target_framework`, compute one quick-pick suggestion per generally supported non-preview `.NET` channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`, sorted newest to oldest before free text: - - Present the newest supported LTS channel first and mark it as recommended (for example `net10.0` as of March 16, 2026) - - Include every other supported LTS and STS channel as additional selectable choices (for example `net9.0` and `net8.0` as of March 16, 2026) - - Label each quick-pick with its support track (`LTS` or `STS`) so the user can make an informed choice -9. Only ask `web_variant` when `app_host_types` includes `Web`. -10. If the user explicitly says `web api`, `mvc`, `razor`, or `web app`, preselect `Web` and the matching `web_variant` instead of asking them to restate it. -11. If the user explicitly says `console` or `worker`, preselect that host type and skip asking `app_host_types` again unless the user clearly requested multiple host types. -12. In plain-text fallback mode, do not add a conversational preamble before a field. Start immediately with `Field: `. -13. After all fields are collected, present a summary and ask for confirmation before proceeding. +1. Ask one field at a time — wait for the answer before presenting the next field. +2. Prefer the host's native structured input controls for every field when they are available. +3. If native structured input controls are unavailable, use this exact plain-text fallback: + - Start with `Field: ` + - Repeat the field prompt verbatim from this file + - For `single-choice` and `multi-choice`, show a numbered option list and let the user answer with the number or the exact option text + - For `text` fields with a `default` or `computed_default`, show `1. Use "" (Recommended)` and `2. Enter a custom value` + - After the user answers, restate the normalized value in one short line before moving on +4. For `single-choice` and `multi-choice` fields, present options as selectable choices when possible — otherwise use the numbered plain-text fallback above instead of an open free-text prompt. +5. When a field has a `default`, present it as the first choice and append "(Recommended)" if not already labeled. +6. For `text` fields with a computed default (e.g. `{solution_name}`), offer the computed value as a selectable choice alongside free text input. +7. If a field with a `default` or `computed_default` is shown to the user and they leave it blank, treat that as accepting the presented recommended value. Do not ask a second clarification question just because the typed response was empty. +8. For `target_framework`, compute one quick-pick suggestion per generally supported non-preview `.NET` channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`, sorted newest to oldest before free text: + - Present the newest supported LTS channel first and mark it as recommended (for example `net10.0` as of March 16, 2026) + - Include every other supported LTS and STS channel as additional selectable choices (for example `net9.0` and `net8.0` as of March 16, 2026) + - Label each quick-pick with its support track (`LTS` or `STS`) so the user can make an informed choice +9. Only ask `web_variant` when `app_host_types` includes `Web`. +10. If the user explicitly says `web api`, `mvc`, `razor`, or `web app`, preselect `Web` and the matching `web_variant` instead of asking them to restate it. +11. If the user explicitly says `console` or `worker`, preselect that host type and skip asking `app_host_types` again unless the user clearly requested multiple host types. +12. In plain-text fallback mode, do not add a conversational preamble before a field. Start immediately with `Field: `. +13. After all fields are collected, present a summary and ask for confirmation before proceeding. diff --git a/skills/dotnet-new-app-slnx/SKILL.md b/skills/dotnet-new-app-slnx/SKILL.md index 08bb235..77d3007 100644 --- a/skills/dotnet-new-app-slnx/SKILL.md +++ b/skills/dotnet-new-app-slnx/SKILL.md @@ -1,209 +1,202 @@ --- name: dotnet-new-app-slnx -description: > - Scaffold a new .NET standalone application solution following codebelt engineering conventions. - Use this skill when the user wants to create a new .NET application — Console, Web, - or Worker service. Also use when the user mentions "new app", "new console app", - "new web api", "new mvc app", "new razor app", "new web app", "new worker service", - "scaffold app", "dotnet new web", "dotnet new webapi", "dotnet new mvc", - "dotnet new webapp", "dotnet new worker", "dotnet new console", or wants a .NET - application project with CI/CD pipeline, functional tests, and code quality tooling. - ALWAYS use this skill when asked to scaffold or create a new .NET application solution. +description: > + Scaffold a new .NET standalone application solution following codebelt engineering conventions. Use this skill when the user wants to create a new .NET application — Console, Web, or Worker service. Also use when the user mentions "new app", "new console app", "new web api", "new mvc app", "new razor app", "new web app", "new worker service", "scaffold app", "dotnet new web", "dotnet new webapi", "dotnet new mvc", "dotnet new webapp", "dotnet new worker", "dotnet new console", or wants a .NET application project with CI/CD pipeline, functional tests, and code quality tooling. ALWAYS use this skill when asked to scaffold or create a new .NET application solution. --- # .NET Application Solution Setup (Codebelt Conventions) -Scaffold new .NET standalone application solutions following the codebeltnet engineering conventions — the same pattern used across [codebeltnet](https://github.com/codebeltnet). Produces a fully wired solution with CI pipeline, centralized build config, semantic versioning, code quality tooling, and proper folder structure. - -> **CRITICAL:** All application projects **must** use the `Codebelt.Bootstrapper.*` framework — never vanilla `WebApplication.CreateBuilder()` or raw `Host.CreateDefaultBuilder()`. The bootstrapper provides a uniform, convention-driven `Program.cs` (and `Startup.cs` for classic hosting). The asset templates in `assets/app/` already wire this up correctly — **always copy from templates, never write Program.cs from scratch**. - -> If a generated app fails because a bootstrapper type from the copied asset template does not resolve, first verify the copied template imports the correct `Codebelt.Bootstrapper.*` namespace and that the matching package reference is present. If the bootstrapper type still cannot be resolved, halt and report the template/package mismatch. Do **not** substitute vanilla .NET hosting code as a workaround. - -## Scope - -This skill produces a **complete solution scaffold** — project structure, build config, CI pipeline, governance docs, and bootstrapper-wired entry points. It does **not** generate application logic (endpoints, services, controllers, middleware). The scaffold is the foundation; the user adds their code on top. - -Generate the scaffold **in the user's current working directory**. Do not create an extra top-level `{REPO_SLUG}` or `{SOLUTION_NAME}` folder unless the user explicitly asks for a nested output folder. - -## Non-Negotiable Output Contract - -The scaffold is incomplete unless it produces all required artifacts for the selected host types. These are not optional, and they must not be silently skipped: - -- the solution file named `{SOLUTION_NAME}.slnx` with the original user-facing casing preserved -- the selected `src/` project or projects -- one functional test project per selected host type under `test/` -- `Directory.Build.props` -- `Directory.Packages.props` -- `testenvironments.json` -- the shared governance/docs assets copied from `assets/shared/` - -If you cannot generate any required artifact from the documented templates and rules, halt and report the mismatch instead of improvising, omitting the file, or substituting a weaker fallback. - -Treat the scaffold as a fidelity copy of the documented template set, not a "best effort" approximation. Do not cherry-pick only the files that seem important, and do not patch over structural problems by pushing configuration down into individual project files. - -**When to use this skill:** The user wants a properly structured .NET solution from scratch — with conventions, CI, and tooling baked in from day one. +Scaffold new .NET standalone application solutions following the codebeltnet engineering conventions — the same pattern used across [codebeltnet](https://github.com/codebeltnet). Produces a fully wired solution with CI pipeline, centralized build config, semantic versioning, code quality tooling, and proper folder structure. + +> **CRITICAL:** All application projects **must** use the `Codebelt.Bootstrapper.*` framework — never vanilla `WebApplication.CreateBuilder()` or raw `Host.CreateDefaultBuilder()`. The bootstrapper provides a uniform, convention-driven `Program.cs` (and `Startup.cs` for classic hosting). The asset templates in `assets/app/` already wire this up correctly — **always copy from templates, never write Program.cs from scratch**. + +> If a generated app fails because a bootstrapper type from the copied asset template does not resolve, first verify the copied template imports the correct `Codebelt.Bootstrapper.*` namespace and that the matching package reference is present. If the bootstrapper type still cannot be resolved, halt and report the template/package mismatch. Do **not** substitute vanilla .NET hosting code as a workaround. + +## Scope + +This skill produces a **complete solution scaffold** — project structure, build config, CI pipeline, governance docs, and bootstrapper-wired entry points. It does **not** generate application logic (endpoints, services, controllers, middleware). The scaffold is the foundation; the user adds their code on top. + +Generate the scaffold **in the user's current working directory**. Do not create an extra top-level `{REPO_SLUG}` or `{SOLUTION_NAME}` folder unless the user explicitly asks for a nested output folder. + +## Non-Negotiable Output Contract + +The scaffold is incomplete unless it produces all required artifacts for the selected host types. These are not optional, and they must not be silently skipped: + +- the solution file named `{SOLUTION_NAME}.slnx` with the original user-facing casing preserved +- the selected `src/` project or projects +- one functional test project per selected host type under `test/` +- `Directory.Build.props` +- `Directory.Packages.props` +- `testenvironments.json` +- the shared governance/docs assets copied from `assets/shared/` + +If you cannot generate any required artifact from the documented templates and rules, halt and report the mismatch instead of improvising, omitting the file, or substituting a weaker fallback. + +Treat the scaffold as a fidelity copy of the documented template set, not a "best effort" approximation. Do not cherry-pick only the files that seem important, and do not patch over structural problems by pushing configuration down into individual project files. + +**When to use this skill:** The user wants a properly structured .NET solution from scratch — with conventions, CI, and tooling baked in from day one. **When NOT to use this skill:** The user wants a quick, throwaway backend or a thin adapter layer. If the request is for a minimal placeholder (e.g. "just a basic API proxy"), do not invoke this skill — use standard .NET CLI tooling instead (`dotnet new web`) and let the user decide if they want to upgrade to a full scaffold later. -## Step 1: Collect Parameters - -Read `FORMS.md` and collect all parameters by presenting each field to the user one at a time using the agent's native input mechanism when the host supports it. If the host does not render native form controls, follow the deterministic plain-text fallback defined in `FORMS.md` instead of improvising your own questioning style. Do not proceed to Step 2 until all required fields are collected and the user confirms the summary. - -For fields that already present a recommended `default` or `computed_default`, treat a blank response as accepting that shown value. Do not get stuck in a clarification loop for `root_namespace`, `target_framework`, or any other defaultable field just because the user did not type over the recommended choice. - -Consistency matters more than creativity during parameter collection. Do not paraphrase field prompts, merge questions, or switch interaction styles mid-flow. - -Treat `Web` as the host family. When `Web` is selected, collect exactly one `web_variant`. If the user already said `web api`, `mvc`, `razor`, or `web app`, preselect the matching `web_variant` instead of asking them to repeat it. - -If the user already said `console` or `worker`, preselect that host type and continue with the next unresolved field instead of re-asking `app_host_types`. In plain-text fallback mode, begin each step directly with the next `Field: ` block from `FORMS.md`; do not add extra conversational lead-ins between fields. - -For `target_framework`, compute one quick-pick per generally supported non-preview `.NET` channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`, sorted newest to oldest before free text. - -- Mark the newest supported LTS channel as the recommended choice -- Include every other supported LTS and STS channel as additional first-class choices -- Label each quick-pick with its support track so the user can choose knowingly - -Filter to `.NET` entries whose `support-phase` is `active` or `maintenance`, exclude preview channels, and let the user choose any currently supported LTS or STS track. - -For each selected host type, derive `{AppType}` as follows: - -- `Console` host type → `{AppType} = Console` -- `Web` + `Empty Web` → `{AppType} = Web` -- `Web` + `Web API` → `{AppType} = Api` -- `Web` + `MVC` → `{AppType} = Mvc` -- `Web` + `Web App / Razor` → `{AppType} = WebApp` -- `Worker` host type → `{AppType} = Worker` - -Use only one web-family variant per scaffold run. The solution may still include `Console` and/or `Worker` alongside that one web-family project. - -## Step 2: Load the Variant Guide - -Read `references/app.md` for the app-specific project structure, template file mapping, hosting patterns (Startup vs Minimal), `.slnx` format, and per-host-type NuGet packages. - -## Step 3: Resolve Dynamic Dependency Versions - -Before writing `Directory.Packages.props`, resolve every `*_VERSION` placeholder in that file to the latest stable listed version for its matching package ID on NuGet.org. - -When PowerShell is available, prefer the deterministic helper in `scripts/resolve-package-versions.ps1` over manual lookup. By default it resolves placeholders from this skill's own `assets/shared/Directory.Packages.props`, so a normal scaffold run only needs `-TargetFramework`. Treat its JSON output as the source of truth for package placeholders. - -- Use the NuGet V3 service index at `https://api.nuget.org/v3/index.json` to discover the package metadata endpoints -- Prefer registration metadata so you can ignore unlisted versions and prerelease builds -- If registration metadata is unavailable, fall back to the package base address versions list from the same service index and still exclude prerelease versions -- Resolve each package independently by package ID; never reuse one generic "latest" value across multiple packages -- Never hardcode version numbers from stale examples, screenshots, or prior scaffolds -- For framework-aligned ASP.NET packages such as `Microsoft.AspNetCore.OpenApi` and `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation`, resolve the latest stable version whose **major** matches the selected `{TARGET_FRAMEWORK}` major. Example: `net9.0` must not get `10.x` ASP.NET packages. -- `Directory.Packages.props` is the authoritative source of NuGet package versions for the generated app scaffold. Do **not** inline `Version=` attributes into `.csproj` files or `Directory.Build.props` as a workaround for restore or build issues. -- Never substitute remembered, example, or previously seen package versions when this lookup step is available. If the lookup step fails, halt and report it instead of guessing. - -This includes shared and host-specific app packages such as: - -- `Codebelt.Extensions.Xunit.App` -- `Microsoft.NET.Test.Sdk` -- `MinVer` -- `coverlet.collector` -- `coverlet.msbuild` -- `xunit.v3` -- `xunit.v3.runner.console` -- `xunit.runner.visualstudio` -- `Codebelt.Bootstrapper.Console` -- `Codebelt.Bootstrapper.Web` -- `Codebelt.Bootstrapper.Worker` -- `Microsoft.AspNetCore.OpenApi` -- `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` -- `Microsoft.Extensions.Hosting` - -## Step 4: Apply the Substitution Map - -When copying template files, replace these placeholders in file contents: - -| Placeholder | Value | -|-------------|-------| -| `{SOLUTION_NAME}` | Solution name (e.g. `PaymentService`) | -| `{ROOT_NAMESPACE}` | Root namespace prefix (e.g. `Acme`) | -| `{REPO_SLUG}` | Derived from solution name (lowercased, e.g. `PaymentService` → `paymentservice`) | -| `{TARGET_FRAMEWORK}` | e.g. `net10.0` (single target) | -| `{AppType}` | Per-host-type output suffix: `Console`, `Web`, `Api`, `Mvc`, `WebApp`, or `Worker` | -| `{UBUNTU_TESTRUNNER_TAG}` | Docker runner image tag derived from `{TARGET_FRAMEWORK}`, e.g. `codebeltnet/ubuntu-testrunner:10` | - -For generated solution filenames, preserve the user-facing `{SOLUTION_NAME}` casing exactly. The solution file must be named `{SOLUTION_NAME}.slnx`, not `{REPO_SLUG}.slnx` and not any lowercased variant. - -`Directory.Packages.props` also contains package-specific placeholders such as `{CODEBELT_BOOTSTRAPPER_WEB_VERSION}`, `{MICROSOFT_ASPNETCORE_OPENAPI_VERSION}`, `{MICROSOFT_ASPNETCORE_MVC_RAZOR_RUNTIMECOMPILATION_VERSION}`, `{MICROSOFT_EXTENSIONS_HOSTING_VERSION}`, and `{MICROSOFT_NET_TEST_SDK_VERSION}`. Resolve each of them from NuGet.org in Step 3 before writing the final file. - -For `Microsoft.AspNetCore.OpenApi` and `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation`, the resolved stable version must stay aligned with the selected `{TARGET_FRAMEWORK}` major version instead of blindly using the latest stable overall. - -Keep `Directory.Packages.props` limited to packages that are actually referenced by the copied app and test templates for the selected host types, plus the shared `MinVer` package used for app versioning. Do not carry unused library-only or benchmark-only package versions into app scaffolds. - -If restore/build fails, fix the central package management inputs instead of bypassing them. Do **not** replace centralized package versions with ad-hoc inline versions in generated project files. - -`TargetFramework` belongs in the generated root `Directory.Build.props`, not in the generated app or test `.csproj` files. Do **not** "repair" framework resolution by adding `` to `src/**/*.csproj` or `test/**/*.csproj`; if framework resolution fails, fix the copied root build props or halt and report the mismatch. - -After writing `Directory.Packages.props`, re-check the generated versions against the Step 3 lookup output before finalizing the scaffold. Do not assume an earlier guess was correct just because the project restores. - -## Step 5: Generate All Files - -Generate files in this order: - -### 1. Copy shared templates -Copy every file from `assets/shared/` to the project root, preserving directory structure. Treat the **current working directory** as that project root. Apply placeholder substitution (Step 4) to all file contents during the copy. - -Do this as a recursive, dotfile-aware copy. Hidden folders and files under `assets/shared/` are part of the scaffold and must not be skipped. In particular, copy `assets/shared/.bot/README.md` as a real file in the generated repo; do not replace it with a synthetic `.gitkeep` or placeholder note. - -Do not selectively copy only "key" shared files. The intended output includes the complete shared asset inventory, including `.gitignore`, `.gitattributes`, `AGENTS.md`, `CHANGELOG.md`, `.github/`, and `.bot/`, in addition to the build and package-management files. - -Exception: update `testenvironments.json` with the derived `{UBUNTU_TESTRUNNER_TAG}` instead of leaving a hardcoded runner image tag in place. Keep the `WSL-Ubuntu` entry and use the Docker major-tag convention documented for the shared Ubuntu test runner images. - -`testenvironments.json` is a required shared scaffold asset. Do **not** silently omit it. If you cannot generate it from the shared template plus `{UBUNTU_TESTRUNNER_TAG}`, halt and report the mismatch instead of skipping the file. - -Exception: if the user selected multiple host types, rewrite the root `README.md` running section to list one `dotnet run --project ...` command per generated host project instead of leaving a single `{AppType}` placeholder example. - -### 2. Copy app `Directory.Build.props` -Copy `assets/app/Directory.Build.props` to the project root, applying placeholder substitution. - -### 3. Copy app CI pipeline -Overwrite the shared CI pipeline with `assets/app/.github/workflows/ci-pipeline.yml`. Apps have a simplified pipeline (build + test only). - -### 4. Generate app-specific files -Follow the variant guide (Step 2) for the remaining files. **Do not write these files from scratch** — use the asset templates in `assets/app/` as the source of truth: - -- **`.csproj` files** → copy from `assets/app/{type}.csproj` for Console and Worker, or from the selected web variant asset (`assets/app/web.csproj`, `assets/app/web-api.csproj`, `assets/app/web-mvc.csproj`, or `assets/app/webapp.csproj`) -- **`Program.cs`** → copy from the matching asset folder's `Program.minimal.cs` (Minimal pattern) or `Program.startup.cs` (Startup pattern) -- **`Startup.cs`** → copy from the matching asset folder's `Startup.cs` (Startup pattern only) -- **`Worker.cs`** → copy from `assets/app/worker/Worker.cs` whenever generating a Worker host type -- **MVC starter UI** → copy `Controllers/` plus `Views/` from `assets/app/web-mvc/` whenever generating the MVC variant -- **Razor starter UI** → copy `Pages/` from `assets/app/webapp/` whenever generating the Web App / Razor variant -- **Test `.csproj`** → copy from `assets/app/test.csproj` - -Apply placeholder substitution (Step 4) to all copied files. The user's business logic, endpoints, and service registrations go into `Startup.cs` (Startup pattern), the `Program.cs` configure methods (Minimal pattern), the MVC controller/view starter, the Razor Pages starter, or the default `Worker.cs` loop for Worker services — but the bootstrapper base classes must remain intact. - -Generate the `.slnx` solution file and functional test project structure per the variant guide. - -The `.slnx` file is required even for single-host scaffolds. Do not skip it just because the generated solution only contains one `src/` project and one `test/` project. - -## Step 6: Post-Generation Checklist - -After generating, verify: - -- [ ] `.slnx` references all generated src/ and test/ projects -- [ ] The generated solution filename is `{SOLUTION_NAME}.slnx` with the original user-facing casing preserved -- [ ] Every file from `assets/shared/` exists in the generated repo with the same relative path, including dotfiles and dotfolders such as `.gitignore`, `.gitattributes`, `.bot/README.md`, and `.github/*` -- [ ] `Directory.Packages.props` lists all `` packages used in the solution (including host-type-specific packages) -- [ ] `Directory.Packages.props` contains concrete version numbers with no unresolved `*_VERSION` placeholders -- [ ] No generated `.csproj` file or `Directory.Build.props` contains ad-hoc inline `Version=` attributes for packages that are supposed to be centrally managed by `Directory.Packages.props` -- [ ] No generated app or test `.csproj` file introduces ``; framework selection stays centralized in the generated root `Directory.Build.props` -- [ ] `ci-pipeline.yml` has the correct settings (build + test only) -- [ ] Root governance docs exist: `README.md`, `CHANGELOG.md`, `.github/CODE_OF_CONDUCT.md`, `.github/CONTRIBUTING.md` -- [ ] `.editorconfig` is present with file-scoped namespace enforcement -- [ ] `AGENTS.md` references `.bot/` and coding guidelines -- [ ] `.github/copilot-instructions.md` has project-specific patterns -- [ ] `.bot/` folder exists and is listed in `.gitignore` -- [ ] `.bot/README.md` exists in the generated repo and came from the shared asset template -- [ ] `testenvironments.json` uses the major-tag `codebeltnet/ubuntu-testrunner:{major}` convention for the selected target framework -- [ ] Correct hosting pattern files generated (`Program.cs` only for Minimal, `Program.cs` + `Startup.cs` for Startup) -- [ ] `Web API` is the default `web_variant` when the user asked for a generic `Web` app -- [ ] `Empty Web` uses the `Web` suffix, `Web API` uses `Api`, `MVC` uses `Mvc`, and `Web App / Razor` uses `WebApp` -- [ ] MVC and Razor variants include their starter UI assets -- [ ] Worker projects include `Worker.cs` - -If the scaffold is generated outside a git-initialized and tagged repository, expect MinVer to report a placeholder pre-release version such as `0.0.0-alpha.0` until the user initializes git and adds a version tag. Treat that as expected bootstrap state, not as a reason to remove MinVer or change the generated versioning setup. - -Summarize what was generated, note any manual steps, and mention the expected MinVer bootstrap behavior when the scaffold was created outside an initialized/tagged git repo. +## Step 1: Collect Parameters + +Read `FORMS.md` and collect all parameters by presenting each field to the user one at a time using the agent's native input mechanism when the host supports it. If the host does not render native form controls, follow the deterministic plain-text fallback defined in `FORMS.md` instead of improvising your own questioning style. Do not proceed to Step 2 until all required fields are collected and the user confirms the summary. + +For fields that already present a recommended `default` or `computed_default`, treat a blank response as accepting that shown value. Do not get stuck in a clarification loop for `root_namespace`, `target_framework`, or any other defaultable field just because the user did not type over the recommended choice. + +Consistency matters more than creativity during parameter collection. Do not paraphrase field prompts, merge questions, or switch interaction styles mid-flow. + +Treat `Web` as the host family. When `Web` is selected, collect exactly one `web_variant`. If the user already said `web api`, `mvc`, `razor`, or `web app`, preselect the matching `web_variant` instead of asking them to repeat it. + +If the user already said `console` or `worker`, preselect that host type and continue with the next unresolved field instead of re-asking `app_host_types`. In plain-text fallback mode, begin each step directly with the next `Field: ` block from `FORMS.md`; do not add extra conversational lead-ins between fields. + +For `target_framework`, compute one quick-pick per generally supported non-preview `.NET` channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`, sorted newest to oldest before free text. + +- Mark the newest supported LTS channel as the recommended choice +- Include every other supported LTS and STS channel as additional first-class choices +- Label each quick-pick with its support track so the user can choose knowingly + +Filter to `.NET` entries whose `support-phase` is `active` or `maintenance`, exclude preview channels, and let the user choose any currently supported LTS or STS track. + +For each selected host type, derive `{AppType}` as follows: + +- `Console` host type → `{AppType} = Console` +- `Web` + `Empty Web` → `{AppType} = Web` +- `Web` + `Web API` → `{AppType} = Api` +- `Web` + `MVC` → `{AppType} = Mvc` +- `Web` + `Web App / Razor` → `{AppType} = WebApp` +- `Worker` host type → `{AppType} = Worker` + +Use only one web-family variant per scaffold run. The solution may still include `Console` and/or `Worker` alongside that one web-family project. + +## Step 2: Load the Variant Guide + +Read `references/app.md` for the app-specific project structure, template file mapping, hosting patterns (Startup vs Minimal), `.slnx` format, and per-host-type NuGet packages. + +## Step 3: Resolve Dynamic Dependency Versions + +Before writing `Directory.Packages.props`, resolve every `*_VERSION` placeholder in that file to the latest stable listed version for its matching package ID on NuGet.org. + +When PowerShell is available, prefer the deterministic helper in `scripts/resolve-package-versions.ps1` over manual lookup. By default it resolves placeholders from this skill's own `assets/shared/Directory.Packages.props`, so a normal scaffold run only needs `-TargetFramework`. Treat its JSON output as the source of truth for package placeholders. + +- Use the NuGet V3 service index at `https://api.nuget.org/v3/index.json` to discover the package metadata endpoints +- Prefer registration metadata so you can ignore unlisted versions and prerelease builds +- If registration metadata is unavailable, fall back to the package base address versions list from the same service index and still exclude prerelease versions +- Resolve each package independently by package ID; never reuse one generic "latest" value across multiple packages +- Never hardcode version numbers from stale examples, screenshots, or prior scaffolds +- For framework-aligned ASP.NET packages such as `Microsoft.AspNetCore.OpenApi` and `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation`, resolve the latest stable version whose **major** matches the selected `{TARGET_FRAMEWORK}` major. Example: `net9.0` must not get `10.x` ASP.NET packages. +- `Directory.Packages.props` is the authoritative source of NuGet package versions for the generated app scaffold. Do **not** inline `Version=` attributes into `.csproj` files or `Directory.Build.props` as a workaround for restore or build issues. +- Never substitute remembered, example, or previously seen package versions when this lookup step is available. If the lookup step fails, halt and report it instead of guessing. + +This includes shared and host-specific app packages such as: + +- `Codebelt.Extensions.Xunit.App` +- `Microsoft.NET.Test.Sdk` +- `MinVer` +- `coverlet.collector` +- `coverlet.msbuild` +- `xunit.v3` +- `xunit.v3.runner.console` +- `xunit.runner.visualstudio` +- `Codebelt.Bootstrapper.Console` +- `Codebelt.Bootstrapper.Web` +- `Codebelt.Bootstrapper.Worker` +- `Microsoft.AspNetCore.OpenApi` +- `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` +- `Microsoft.Extensions.Hosting` + +## Step 4: Apply the Substitution Map + +When copying template files, replace these placeholders in file contents: + +| Placeholder | Value | +|-------------|-------| +| `{SOLUTION_NAME}` | Solution name (e.g. `PaymentService`) | +| `{ROOT_NAMESPACE}` | Root namespace prefix (e.g. `Acme`) | +| `{REPO_SLUG}` | Derived from solution name (lowercased, e.g. `PaymentService` → `paymentservice`) | +| `{TARGET_FRAMEWORK}` | e.g. `net10.0` (single target) | +| `{AppType}` | Per-host-type output suffix: `Console`, `Web`, `Api`, `Mvc`, `WebApp`, or `Worker` | +| `{UBUNTU_TESTRUNNER_TAG}` | Docker runner image tag derived from `{TARGET_FRAMEWORK}`, e.g. `codebeltnet/ubuntu-testrunner:10` | + +For generated solution filenames, preserve the user-facing `{SOLUTION_NAME}` casing exactly. The solution file must be named `{SOLUTION_NAME}.slnx`, not `{REPO_SLUG}.slnx` and not any lowercased variant. + +`Directory.Packages.props` also contains package-specific placeholders such as `{CODEBELT_BOOTSTRAPPER_WEB_VERSION}`, `{MICROSOFT_ASPNETCORE_OPENAPI_VERSION}`, `{MICROSOFT_ASPNETCORE_MVC_RAZOR_RUNTIMECOMPILATION_VERSION}`, `{MICROSOFT_EXTENSIONS_HOSTING_VERSION}`, and `{MICROSOFT_NET_TEST_SDK_VERSION}`. Resolve each of them from NuGet.org in Step 3 before writing the final file. + +For `Microsoft.AspNetCore.OpenApi` and `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation`, the resolved stable version must stay aligned with the selected `{TARGET_FRAMEWORK}` major version instead of blindly using the latest stable overall. + +Keep `Directory.Packages.props` limited to packages that are actually referenced by the copied app and test templates for the selected host types, plus the shared `MinVer` package used for app versioning. Do not carry unused library-only or benchmark-only package versions into app scaffolds. + +If restore/build fails, fix the central package management inputs instead of bypassing them. Do **not** replace centralized package versions with ad-hoc inline versions in generated project files. + +`TargetFramework` belongs in the generated root `Directory.Build.props`, not in the generated app or test `.csproj` files. Do **not** "repair" framework resolution by adding `` to `src/**/*.csproj` or `test/**/*.csproj`; if framework resolution fails, fix the copied root build props or halt and report the mismatch. + +After writing `Directory.Packages.props`, re-check the generated versions against the Step 3 lookup output before finalizing the scaffold. Do not assume an earlier guess was correct just because the project restores. + +## Step 5: Generate All Files + +Generate files in this order: + +### 1. Copy shared templates +Copy every file from `assets/shared/` to the project root, preserving directory structure. Treat the **current working directory** as that project root. Apply placeholder substitution (Step 4) to all file contents during the copy. + +Do this as a recursive, dotfile-aware copy. Hidden folders and files under `assets/shared/` are part of the scaffold and must not be skipped. In particular, copy `assets/shared/.bot/README.md` as a real file in the generated repo; do not replace it with a synthetic `.gitkeep` or placeholder note. + +Do not selectively copy only "key" shared files. The intended output includes the complete shared asset inventory, including `.gitignore`, `.gitattributes`, `AGENTS.md`, `CHANGELOG.md`, `.github/`, and `.bot/`, in addition to the build and package-management files. + +Exception: update `testenvironments.json` with the derived `{UBUNTU_TESTRUNNER_TAG}` instead of leaving a hardcoded runner image tag in place. Keep the `WSL-Ubuntu` entry and use the Docker major-tag convention documented for the shared Ubuntu test runner images. + +`testenvironments.json` is a required shared scaffold asset. Do **not** silently omit it. If you cannot generate it from the shared template plus `{UBUNTU_TESTRUNNER_TAG}`, halt and report the mismatch instead of skipping the file. + +Exception: if the user selected multiple host types, rewrite the root `README.md` running section to list one `dotnet run --project ...` command per generated host project instead of leaving a single `{AppType}` placeholder example. + +### 2. Copy app `Directory.Build.props` +Copy `assets/app/Directory.Build.props` to the project root, applying placeholder substitution. + +### 3. Copy app CI pipeline +Overwrite the shared CI pipeline with `assets/app/.github/workflows/ci-pipeline.yml`. Apps have a simplified pipeline (build + test only). + +### 4. Generate app-specific files +Follow the variant guide (Step 2) for the remaining files. **Do not write these files from scratch** — use the asset templates in `assets/app/` as the source of truth: + +- **`.csproj` files** → copy from `assets/app/{type}.csproj` for Console and Worker, or from the selected web variant asset (`assets/app/web.csproj`, `assets/app/web-api.csproj`, `assets/app/web-mvc.csproj`, or `assets/app/webapp.csproj`) +- **`Program.cs`** → copy from the matching asset folder's `Program.minimal.cs` (Minimal pattern) or `Program.startup.cs` (Startup pattern) +- **`Startup.cs`** → copy from the matching asset folder's `Startup.cs` (Startup pattern only) +- **`Worker.cs`** → copy from `assets/app/worker/Worker.cs` whenever generating a Worker host type +- **MVC starter UI** → copy `Controllers/` plus `Views/` from `assets/app/web-mvc/` whenever generating the MVC variant +- **Razor starter UI** → copy `Pages/` from `assets/app/webapp/` whenever generating the Web App / Razor variant +- **Test `.csproj`** → copy from `assets/app/test.csproj` + +Apply placeholder substitution (Step 4) to all copied files. The user's business logic, endpoints, and service registrations go into `Startup.cs` (Startup pattern), the `Program.cs` configure methods (Minimal pattern), the MVC controller/view starter, the Razor Pages starter, or the default `Worker.cs` loop for Worker services — but the bootstrapper base classes must remain intact. + +Generate the `.slnx` solution file and functional test project structure per the variant guide. + +The `.slnx` file is required even for single-host scaffolds. Do not skip it just because the generated solution only contains one `src/` project and one `test/` project. + +## Step 6: Post-Generation Checklist + +After generating, verify: + +- [ ] `.slnx` references all generated src/ and test/ projects +- [ ] The generated solution filename is `{SOLUTION_NAME}.slnx` with the original user-facing casing preserved +- [ ] Every file from `assets/shared/` exists in the generated repo with the same relative path, including dotfiles and dotfolders such as `.gitignore`, `.gitattributes`, `.bot/README.md`, and `.github/*` +- [ ] `Directory.Packages.props` lists all `` packages used in the solution (including host-type-specific packages) +- [ ] `Directory.Packages.props` contains concrete version numbers with no unresolved `*_VERSION` placeholders +- [ ] No generated `.csproj` file or `Directory.Build.props` contains ad-hoc inline `Version=` attributes for packages that are supposed to be centrally managed by `Directory.Packages.props` +- [ ] No generated app or test `.csproj` file introduces ``; framework selection stays centralized in the generated root `Directory.Build.props` +- [ ] `ci-pipeline.yml` has the correct settings (build + test only) +- [ ] Root governance docs exist: `README.md`, `CHANGELOG.md`, `.github/CODE_OF_CONDUCT.md`, `.github/CONTRIBUTING.md` +- [ ] `.editorconfig` is present with file-scoped namespace enforcement +- [ ] `AGENTS.md` references `.bot/` and coding guidelines +- [ ] `.github/copilot-instructions.md` has project-specific patterns +- [ ] `.bot/` folder exists and is listed in `.gitignore` +- [ ] `.bot/README.md` exists in the generated repo and came from the shared asset template +- [ ] `testenvironments.json` uses the major-tag `codebeltnet/ubuntu-testrunner:{major}` convention for the selected target framework +- [ ] Correct hosting pattern files generated (`Program.cs` only for Minimal, `Program.cs` + `Startup.cs` for Startup) +- [ ] `Web API` is the default `web_variant` when the user asked for a generic `Web` app +- [ ] `Empty Web` uses the `Web` suffix, `Web API` uses `Api`, `MVC` uses `Mvc`, and `Web App / Razor` uses `WebApp` +- [ ] MVC and Razor variants include their starter UI assets +- [ ] Worker projects include `Worker.cs` + +If the scaffold is generated outside a git-initialized and tagged repository, expect MinVer to report a placeholder pre-release version such as `0.0.0-alpha.0` until the user initializes git and adds a version tag. Treat that as expected bootstrap state, not as a reason to remove MinVer or change the generated versioning setup. + +Summarize what was generated, note any manual steps, and mention the expected MinVer bootstrap behavior when the scaffold was created outside an initialized/tagged git repo. diff --git a/skills/dotnet-new-app-slnx/assets/shared/.github/copilot-instructions.md b/skills/dotnet-new-app-slnx/assets/shared/.github/copilot-instructions.md index d2a42dd..e06bbae 100644 --- a/skills/dotnet-new-app-slnx/assets/shared/.github/copilot-instructions.md +++ b/skills/dotnet-new-app-slnx/assets/shared/.github/copilot-instructions.md @@ -8,8 +8,7 @@ This document provides instructions for writing unit tests for a project/solutio ## 1. Base Class -**Always inherit from the `Test` base class** for all unit test classes. -This ensures consistent setup, teardown, and output handling across all tests. +**Always inherit from the `Test` base class** for all unit test classes. This ensures consistent setup, teardown, and output handling across all tests. > Important: Do NOT add `using Xunit.Abstractions`. xUnit v3 no longer exposes that namespace; including it is incorrect and will cause compilation errors. Use the `Codebelt.Extensions.Xunit` Test base class and `using Xunit;` as shown in the examples below. If you need access to test output, rely on the Test base class (which accepts the appropriate output helper) rather than importing `Xunit.Abstractions`. @@ -56,7 +55,7 @@ namespace Your.Namespace public class Zoo { /* ... */ } } ``` - then the corresponding unit test class must use the exact same namespace: +then the corresponding unit test class must use the exact same namespace: ```csharp namespace YourProject.Foo.Bar { @@ -148,8 +147,7 @@ namespace YourProject **Pattern name:** Public Facade Testing (also referred to as *Public API Proxy Testing*) -**Description:** -Internal classes and methods must be validated by exercising the public API that consumes them. Tests should assert observable behavior exposed by the public surface rather than targeting internal implementation details directly. +**Description:** Internal classes and methods must be validated by exercising the public API that consumes them. Tests should assert observable behavior exposed by the public surface rather than targeting internal implementation details directly. ### Example Mapping @@ -190,10 +188,7 @@ Namespace rule: DO NOT append `.Benchmarks` to the namespace. Benchmarks must li public class Sha512256Benchmark { /* ... */ } } ``` -The class name must end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix). -- The benchmarks for the YourProject.Bar assembly live in the YourProject.Bar.Benchmarks assembly. -- Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the YourProject.Bar assembly would be named ZooBenchmark and placed in the YourProject.Bar namespace in the YourProject.Bar.Benchmarks assembly. -- Modify the associated .csproj file to override the root namespace, e.g., YourProject.Bar. +The class name must end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix). - The benchmarks for the YourProject.Bar assembly live in the YourProject.Bar.Benchmarks assembly. - Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the YourProject.Bar assembly would be named ZooBenchmark and placed in the YourProject.Bar namespace in the YourProject.Bar.Benchmarks assembly. - Modify the associated .csproj file to override the root namespace, e.g., YourProject.Bar. ## 2. Attributes and Configuration diff --git a/skills/dotnet-new-app-slnx/assets/shared/CHANGELOG.md b/skills/dotnet-new-app-slnx/assets/shared/CHANGELOG.md index cb950bd..79aee67 100644 --- a/skills/dotnet-new-app-slnx/assets/shared/CHANGELOG.md +++ b/skills/dotnet-new-app-slnx/assets/shared/CHANGELOG.md @@ -2,8 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] diff --git a/skills/dotnet-new-app-slnx/references/app.md b/skills/dotnet-new-app-slnx/references/app.md index f131e68..d9752c2 100644 --- a/skills/dotnet-new-app-slnx/references/app.md +++ b/skills/dotnet-new-app-slnx/references/app.md @@ -2,74 +2,74 @@ Slim guide for runnable applications. All file templates live in `assets/app/`. -## Folder Structure - -``` -. -├── src/ -│ └── {ROOT_NAMESPACE}.{AppType}/ -│ ├── {ROOT_NAMESPACE}.{AppType}.csproj -│ └── Program.cs (+ Startup.cs if startup pattern) -├── test/ -│ └── {ROOT_NAMESPACE}.{AppType}.FunctionalTests/ -│ └── {ROOT_NAMESPACE}.{AppType}.FunctionalTests.csproj -├── Directory.Build.props -├── Directory.Build.targets -├── Directory.Packages.props -└── {SOLUTION_NAME}.slnx -``` - -The tree is shown **relative to the current working directory**. Generate these files directly in the folder the user is already in; do not create an extra solution-named wrapper folder unless they explicitly ask for one. - -Preserve the solution/product name casing for the solution file itself. Use `{SOLUTION_NAME}.slnx` exactly as provided by the user, typically in `PascalCase`. Do **not** derive the `.slnx` filename from `{REPO_SLUG}` or any lowercased variant. - -Treat the files shown in this tree as required output, not aspirational examples. A single-host scaffold still requires `{SOLUTION_NAME}.slnx`, one `src/` project, one `test/` project, `Directory.Build.props`, `Directory.Build.targets`, `Directory.Packages.props`, and `testenvironments.json`. - -No `.nuget/` folder or `.snk` file (uncommon for apps). - -## Required Shared Asset Inventory - -Copy the complete contents of `assets/shared/` into the generated repo root, preserving relative paths. - -Do not cherry-pick only the files that feel essential. The shared scaffold contract includes: - -- `.editorconfig` -- `.gitattributes` -- `.gitignore` -- `AGENTS.md` -- `CHANGELOG.md` -- `Directory.Build.targets` -- `Directory.Packages.props` -- `README.md` -- `testenvironments.json` -- `.bot/README.md` -- `.github/CODE_OF_CONDUCT.md` -- `.github/CONTRIBUTING.md` -- `.github/copilot-instructions.md` -- `.github/dependabot.yml` - -Treat missing files from this shared inventory as scaffold defects, not optional omissions. +## Folder Structure + +``` +. +├── src/ +│ └── {ROOT_NAMESPACE}.{AppType}/ +│ ├── {ROOT_NAMESPACE}.{AppType}.csproj +│ └── Program.cs (+ Startup.cs if startup pattern) +├── test/ +│ └── {ROOT_NAMESPACE}.{AppType}.FunctionalTests/ +│ └── {ROOT_NAMESPACE}.{AppType}.FunctionalTests.csproj +├── Directory.Build.props +├── Directory.Build.targets +├── Directory.Packages.props +└── {SOLUTION_NAME}.slnx +``` + +The tree is shown **relative to the current working directory**. Generate these files directly in the folder the user is already in; do not create an extra solution-named wrapper folder unless they explicitly ask for one. + +Preserve the solution/product name casing for the solution file itself. Use `{SOLUTION_NAME}.slnx` exactly as provided by the user, typically in `PascalCase`. Do **not** derive the `.slnx` filename from `{REPO_SLUG}` or any lowercased variant. + +Treat the files shown in this tree as required output, not aspirational examples. A single-host scaffold still requires `{SOLUTION_NAME}.slnx`, one `src/` project, one `test/` project, `Directory.Build.props`, `Directory.Build.targets`, `Directory.Packages.props`, and `testenvironments.json`. + +No `.nuget/` folder or `.snk` file (uncommon for apps). + +## Required Shared Asset Inventory + +Copy the complete contents of `assets/shared/` into the generated repo root, preserving relative paths. + +Do not cherry-pick only the files that feel essential. The shared scaffold contract includes: + +- `.editorconfig` +- `.gitattributes` +- `.gitignore` +- `AGENTS.md` +- `CHANGELOG.md` +- `Directory.Build.targets` +- `Directory.Packages.props` +- `README.md` +- `testenvironments.json` +- `.bot/README.md` +- `.github/CODE_OF_CONDUCT.md` +- `.github/CONTRIBUTING.md` +- `.github/copilot-instructions.md` +- `.github/dependabot.yml` + +Treat missing files from this shared inventory as scaffold defects, not optional omissions. ## Testing Approach -Apps use **functional tests** (not unit tests). The test project exercises the running application as a whole — verifying endpoints, commands, or hosted service behavior — rather than testing individual classes in isolation. - -- Test project naming: `{ROOT_NAMESPACE}.{AppType}.FunctionalTests` (not `.Tests`) -- The `IsTestProject` detection in `Directory.Build.props` uses `EndsWith('Tests')`, which also matches `FunctionalTests` - -## Template File Mapping - -| Template source | Destination | -|----------------------------------|--------------------------------------------------------------------| -| `assets/app/Directory.Build.props` | `Directory.Build.props` (repo root) | -| `assets/app/console.csproj` | `src/{ROOT_NAMESPACE}.Console/{ROOT_NAMESPACE}.Console.csproj` | -| `assets/app/web.csproj` | `src/{ROOT_NAMESPACE}.Web/{ROOT_NAMESPACE}.Web.csproj` | -| `assets/app/web-api.csproj` | `src/{ROOT_NAMESPACE}.Api/{ROOT_NAMESPACE}.Api.csproj` | -| `assets/app/web-mvc.csproj` | `src/{ROOT_NAMESPACE}.Mvc/{ROOT_NAMESPACE}.Mvc.csproj` | -| `assets/app/webapp.csproj` | `src/{ROOT_NAMESPACE}.WebApp/{ROOT_NAMESPACE}.WebApp.csproj` | -| `assets/app/worker.csproj` | `src/{ROOT_NAMESPACE}.Worker/{ROOT_NAMESPACE}.Worker.csproj` | -| `assets/app/worker/Worker.cs` | `src/{ROOT_NAMESPACE}.Worker/Worker.cs` | -| `assets/app/test.csproj` | `test/{ROOT_NAMESPACE}.{AppType}.FunctionalTests/{ROOT_NAMESPACE}.{AppType}.FunctionalTests.csproj` | +Apps use **functional tests** (not unit tests). The test project exercises the running application as a whole — verifying endpoints, commands, or hosted service behavior — rather than testing individual classes in isolation. + +- Test project naming: `{ROOT_NAMESPACE}.{AppType}.FunctionalTests` (not `.Tests`) +- The `IsTestProject` detection in `Directory.Build.props` uses `EndsWith('Tests')`, which also matches `FunctionalTests` + +## Template File Mapping + +| Template source | Destination | +|----------------------------------|--------------------------------------------------------------------| +| `assets/app/Directory.Build.props` | `Directory.Build.props` (repo root) | +| `assets/app/console.csproj` | `src/{ROOT_NAMESPACE}.Console/{ROOT_NAMESPACE}.Console.csproj` | +| `assets/app/web.csproj` | `src/{ROOT_NAMESPACE}.Web/{ROOT_NAMESPACE}.Web.csproj` | +| `assets/app/web-api.csproj` | `src/{ROOT_NAMESPACE}.Api/{ROOT_NAMESPACE}.Api.csproj` | +| `assets/app/web-mvc.csproj` | `src/{ROOT_NAMESPACE}.Mvc/{ROOT_NAMESPACE}.Mvc.csproj` | +| `assets/app/webapp.csproj` | `src/{ROOT_NAMESPACE}.WebApp/{ROOT_NAMESPACE}.WebApp.csproj` | +| `assets/app/worker.csproj` | `src/{ROOT_NAMESPACE}.Worker/{ROOT_NAMESPACE}.Worker.csproj` | +| `assets/app/worker/Worker.cs` | `src/{ROOT_NAMESPACE}.Worker/Worker.cs` | +| `assets/app/test.csproj` | `test/{ROOT_NAMESPACE}.{AppType}.FunctionalTests/{ROOT_NAMESPACE}.{AppType}.FunctionalTests.csproj` | ## Startup vs Minimal Pattern @@ -77,112 +77,112 @@ Apps use **functional tests** (not unit tests). The test project exercises the r Ask the user: **"Hosting pattern: Startup (aka Classic Hosting — Program.cs + Startup.cs) or Minimal (aka Minimal Hosting — Program.cs only)?"** Default: **Minimal**. -| Pattern | Also known as | Files to copy | Source template | -|---------|---------------|---------------|-----------------| -| **Startup** | Classic Hosting | `Program.cs` + `Startup.cs` | `assets/app/{type}/Program.startup.cs` and `assets/app/{type}/Startup.cs` | -| **Minimal** | Minimal Hosting | `Program.cs` only | `assets/app/{type}/Program.minimal.cs` | - -Where `{type}` = `console`, `worker`, or the selected web asset folder: `web`, `web-api`, `web-mvc`, or `webapp`. - -Where `{AppType}` maps to the emitted project suffix: - -- `console` → `Console` -- `web` (`Empty Web`) → `Web` -- `web-api` (`Web API`) → `Api` -- `web-mvc` (`MVC`) → `Mvc` -- `webapp` (`Web App / Razor`) → `WebApp` -- `worker` → `Worker` - -Both are placed in `src/{ROOT_NAMESPACE}.{AppType}/`. - -When the user asks for a generic `Web` project, collect exactly one `web_variant` and default it to `Web API`. - -## Web Variant Starter Assets - -When `app_host_types` includes `Web`, generate exactly one web-family project using the selected `web_variant`: - -| Web variant | Asset stem/folder | Emitted suffix | Extra starter assets | -|-------------|-------------------|----------------|----------------------| -| `Empty Web` | `web` | `Web` | none | -| `Web API` | `web-api` | `Api` | none | -| `MVC` | `web-mvc` | `Mvc` | `Controllers/` and `Views/` | -| `Web App / Razor` | `webapp` | `WebApp` | `Pages/` | - -## .slnx Template (inline — dynamic project list) - -```xml - - - - - - - - -``` - -Add one `` entry per host type when a solution contains multiple app types. - -The solution file name itself must be `{SOLUTION_NAME}.slnx`, preserving the original user-facing casing. - -Even when there is only one host type, still generate the `.slnx` file and include both the `src/` and `test/` project entries. +| Pattern | Also known as | Files to copy | Source template | +|---------|---------------|---------------|-----------------| +| **Startup** | Classic Hosting | `Program.cs` + `Startup.cs` | `assets/app/{type}/Program.startup.cs` and `assets/app/{type}/Startup.cs` | +| **Minimal** | Minimal Hosting | `Program.cs` only | `assets/app/{type}/Program.minimal.cs` | + +Where `{type}` = `console`, `worker`, or the selected web asset folder: `web`, `web-api`, `web-mvc`, or `webapp`. + +Where `{AppType}` maps to the emitted project suffix: + +- `console` → `Console` +- `web` (`Empty Web`) → `Web` +- `web-api` (`Web API`) → `Api` +- `web-mvc` (`MVC`) → `Mvc` +- `webapp` (`Web App / Razor`) → `WebApp` +- `worker` → `Worker` + +Both are placed in `src/{ROOT_NAMESPACE}.{AppType}/`. + +When the user asks for a generic `Web` project, collect exactly one `web_variant` and default it to `Web API`. + +## Web Variant Starter Assets + +When `app_host_types` includes `Web`, generate exactly one web-family project using the selected `web_variant`: + +| Web variant | Asset stem/folder | Emitted suffix | Extra starter assets | +|-------------|-------------------|----------------|----------------------| +| `Empty Web` | `web` | `Web` | none | +| `Web API` | `web-api` | `Api` | none | +| `MVC` | `web-mvc` | `Mvc` | `Controllers/` and `Views/` | +| `Web App / Razor` | `webapp` | `WebApp` | `Pages/` | + +## .slnx Template (inline — dynamic project list) + +```xml + + + + + + + + +``` + +Add one `` entry per host type when a solution contains multiple app types. + +The solution file name itself must be `{SOLUTION_NAME}.slnx`, preserving the original user-facing casing. + +Even when there is only one host type, still generate the `.slnx` file and include both the `src/` and `test/` project entries. ## Additional Packages (Directory.Packages.props) -Each app type requires variant-specific NuGet packages: - -| App type | Required packages | -|----------|-------------------| -| Console | `Codebelt.Bootstrapper.Console` | -| Empty Web | `Codebelt.Bootstrapper.Web` | -| Web API | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.OpenApi` | -| MVC | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` | -| Web App / Razor | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` | -| Worker | `Codebelt.Bootstrapper.Worker`, `Microsoft.Extensions.Hosting` | - -Merge these into `Directory.Packages.props` alongside the shared packages. - -The generated `Directory.Packages.props` should include only packages that are actually referenced by the copied `assets/app/**/*.csproj` templates for the selected host types plus the shared test/build packages and `MinVer` for app versioning. Do not leave unused library-only or benchmark-only package versions in app scaffolds. - -Resolve each package-specific `*_VERSION` placeholder in `Directory.Packages.props` from NuGet.org before writing the final file. Do not leave generic `{LATEST}` or unresolved version tokens in the generated repo. - -`Directory.Packages.props` is the authoritative version source for app scaffolds. Keep the generated `PackageReference` items versionless and centrally managed; do **not** repair restore/build issues by inlining `Version=` attributes into `.csproj` files or `Directory.Build.props`. - -Keep target-framework selection centralized too: the generated root `Directory.Build.props` owns `{TARGET_FRAMEWORK}` for source and test projects. Do **not** duplicate `` inside the generated app or test `.csproj` files as a workaround. - -When PowerShell is available, prefer `scripts/resolve-package-versions.ps1` to produce the package placeholder map for this skill. The script defaults to this skill's own `assets/shared/Directory.Packages.props`, so the normal path only needs `{TARGET_FRAMEWORK}`. Its output should drive the final substitutions instead of remembered version numbers. - -For framework-aligned ASP.NET packages, keep the selected target framework major in mind when resolving the final version: - -- `Microsoft.AspNetCore.OpenApi` should use the latest stable version whose major matches `{TARGET_FRAMEWORK}` -- `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` should use the latest stable version whose major matches `{TARGET_FRAMEWORK}` -- Example: a `net9.0` app should resolve these packages to the latest stable `9.x` version, not `10.x` -- If the lookup step fails, stop and report the failure instead of guessing with stale package versions from prior runs - -## Test Environments - -Generate `testenvironments.json` from the selected target framework instead of keeping a hardcoded SDK patch tag. - -- Always include the `WSL-Ubuntu` entry -- Add one `Docker-Ubuntu` entry using `codebeltnet/ubuntu-testrunner:{major}` where `{major}` comes from `{TARGET_FRAMEWORK}` -- Example: `net10.0` → `codebeltnet/ubuntu-testrunner:10` - -`testenvironments.json` is required output for the scaffold. If you cannot render it from the shared template plus `{UBUNTU_TESTRUNNER_TAG}`, stop and report the issue instead of silently omitting the file. - -## MinVer Bootstrap Behavior - -App scaffolds keep `MinVer` wired in from day one. - -- In a fresh folder that is not yet a git repository, or in a git repo without version tags, MinVer may report a bootstrap pre-release such as `0.0.0-alpha.0` -- Treat that as expected initial state rather than a template defect -- Do not remove MinVer or replace it with hardcoded package/app versions just to suppress that warning -- Once the user initializes git and adds a version tag, MinVer will produce the intended semantic version values - -## Multiple App Types - -A single solution can host more than one app type (e.g. Web + Worker or Console + Worker). - -- Add a `src/` project and `test/` project **per host type**. -- If `Web` is selected, generate exactly one web-family project using the chosen `web_variant`. -- Add all projects to the `.slnx` under the appropriate solution folders. -- Merge the NuGet packages from each variant into `Directory.Packages.props`. +Each app type requires variant-specific NuGet packages: + +| App type | Required packages | +|----------|-------------------| +| Console | `Codebelt.Bootstrapper.Console` | +| Empty Web | `Codebelt.Bootstrapper.Web` | +| Web API | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.OpenApi` | +| MVC | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` | +| Web App / Razor | `Codebelt.Bootstrapper.Web`, `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` | +| Worker | `Codebelt.Bootstrapper.Worker`, `Microsoft.Extensions.Hosting` | + +Merge these into `Directory.Packages.props` alongside the shared packages. + +The generated `Directory.Packages.props` should include only packages that are actually referenced by the copied `assets/app/**/*.csproj` templates for the selected host types plus the shared test/build packages and `MinVer` for app versioning. Do not leave unused library-only or benchmark-only package versions in app scaffolds. + +Resolve each package-specific `*_VERSION` placeholder in `Directory.Packages.props` from NuGet.org before writing the final file. Do not leave generic `{LATEST}` or unresolved version tokens in the generated repo. + +`Directory.Packages.props` is the authoritative version source for app scaffolds. Keep the generated `PackageReference` items versionless and centrally managed; do **not** repair restore/build issues by inlining `Version=` attributes into `.csproj` files or `Directory.Build.props`. + +Keep target-framework selection centralized too: the generated root `Directory.Build.props` owns `{TARGET_FRAMEWORK}` for source and test projects. Do **not** duplicate `` inside the generated app or test `.csproj` files as a workaround. + +When PowerShell is available, prefer `scripts/resolve-package-versions.ps1` to produce the package placeholder map for this skill. The script defaults to this skill's own `assets/shared/Directory.Packages.props`, so the normal path only needs `{TARGET_FRAMEWORK}`. Its output should drive the final substitutions instead of remembered version numbers. + +For framework-aligned ASP.NET packages, keep the selected target framework major in mind when resolving the final version: + +- `Microsoft.AspNetCore.OpenApi` should use the latest stable version whose major matches `{TARGET_FRAMEWORK}` +- `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` should use the latest stable version whose major matches `{TARGET_FRAMEWORK}` +- Example: a `net9.0` app should resolve these packages to the latest stable `9.x` version, not `10.x` +- If the lookup step fails, stop and report the failure instead of guessing with stale package versions from prior runs + +## Test Environments + +Generate `testenvironments.json` from the selected target framework instead of keeping a hardcoded SDK patch tag. + +- Always include the `WSL-Ubuntu` entry +- Add one `Docker-Ubuntu` entry using `codebeltnet/ubuntu-testrunner:{major}` where `{major}` comes from `{TARGET_FRAMEWORK}` +- Example: `net10.0` → `codebeltnet/ubuntu-testrunner:10` + +`testenvironments.json` is required output for the scaffold. If you cannot render it from the shared template plus `{UBUNTU_TESTRUNNER_TAG}`, stop and report the issue instead of silently omitting the file. + +## MinVer Bootstrap Behavior + +App scaffolds keep `MinVer` wired in from day one. + +- In a fresh folder that is not yet a git repository, or in a git repo without version tags, MinVer may report a bootstrap pre-release such as `0.0.0-alpha.0` +- Treat that as expected initial state rather than a template defect +- Do not remove MinVer or replace it with hardcoded package/app versions just to suppress that warning +- Once the user initializes git and adds a version tag, MinVer will produce the intended semantic version values + +## Multiple App Types + +A single solution can host more than one app type (e.g. Web + Worker or Console + Worker). + +- Add a `src/` project and `test/` project **per host type**. +- If `Web` is selected, generate exactly one web-family project using the chosen `web_variant`. +- Add all projects to the `.slnx` under the appropriate solution folders. +- Merge the NuGet packages from each variant into `Directory.Packages.props`. diff --git a/skills/dotnet-new-lib-slnx/FORMS.md b/skills/dotnet-new-lib-slnx/FORMS.md index 52177f2..2190d00 100644 --- a/skills/dotnet-new-lib-slnx/FORMS.md +++ b/skills/dotnet-new-lib-slnx/FORMS.md @@ -1,6 +1,6 @@ # Parameter Form -Collect these parameters from the user before generating anything. Present each field **one at a time** using the agent's native input mechanism (e.g. `ask_user` with `choices`) when the host supports it. If native structured input widgets are unavailable, fall back to the deterministic plain-text interaction format described in the presentation rules below. Do not bundle multiple fields into a single message. +Collect these parameters from the user before generating anything. Present each field **one at a time** using the agent's native input mechanism (e.g. `ask_user` with `choices`) when the host supports it. If native structured input widgets are unavailable, fall back to the deterministic plain-text interaction format described in the presentation rules below. Do not bundle multiple fields into a single message. ## Fields @@ -10,17 +10,17 @@ Collect these parameters from the user before generating anything. Present each - **placeholder:** "e.g. MyLibrary" - **required:** true -### root_namespace -- **type:** text -- **prompt:** "Root namespace prefix?" -- **placeholder:** "e.g. Acme, MyCompany" -- **default:** `{solution_name}` -- **description:** Present `{solution_name}` as the recommended namespace prefix. If the user leaves this field blank after seeing that default, accept `{solution_name}` and continue instead of asking again. -- **required:** true - -### author -- **type:** text -- **prompt:** "Author name? (for NuGet metadata and git)" +### root_namespace +- **type:** text +- **prompt:** "Root namespace prefix?" +- **placeholder:** "e.g. Acme, MyCompany" +- **default:** `{solution_name}` +- **description:** Present `{solution_name}` as the recommended namespace prefix. If the user leaves this field blank after seeing that default, accept `{solution_name}` and continue instead of asking again. +- **required:** true + +### author +- **type:** text +- **prompt:** "Author name? (for NuGet metadata and git)" - **computed_default:** Git user name (via `git config user.name`). Falls back to asking the user if not configured. - **required:** true @@ -30,12 +30,12 @@ Collect these parameters from the user before generating anything. Present each - **computed_default:** Git user email (via `git config user.email`). Falls back to asking the user if not configured. - **required:** true -### company_or_person -- **type:** text -- **prompt:** "Company or person name? (for copyright and NuGet metadata)" -- **default:** `{author}` -- **description:** Use the company name when publishing under an organization, or reuse the author name for solo/independent packages. -- **required:** true +### company_or_person +- **type:** text +- **prompt:** "Company or person name? (for copyright and NuGet metadata)" +- **default:** `{author}` +- **description:** Use the company name when publishing under an organization, or reuse the author name for solo/independent packages. +- **required:** true ### copyright_year - **type:** text @@ -43,38 +43,38 @@ Collect these parameters from the user before generating anything. Present each - **default:** current year (from system time) - **required:** true -### repository_url -- **type:** text -- **prompt:** "Source repository URL? (GitHub)" -- **computed_default:** `https://github.com/OWNER/{root-folder-name}` where `{root-folder-name}` is resolved from the git repository root folder name (via `Split-Path -Leaf (git rev-parse --show-toplevel)`). Falls back to the current folder name if not in a git repo. -- **description:** Source code repository shown as the package's repository/source link. Example: `https://github.com/codebeltnet/savvyio`. -- **required:** true - -### package_project_url -- **type:** text -- **prompt:** "Project website/docs URL? (shown as 'Project website' on NuGet)" -- **computed_default:** `repository_url` -- **description:** Present the collected `repository_url` as the recommended value so the user can accept it or replace it with a dedicated website/docs URL. Example: accept `https://github.com/codebeltnet/savvyio` for simple packages, or replace it with `https://www.savvyio.net/`. -- **required:** true - -### target_frameworks -- **type:** text -- **prompt:** "Target frameworks? (semicolon-separated)" -- **computed_default:** Newest generally supported .NET LTS channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json` (filter `.NET` entries where `support-phase` is `active` or `maintenance`, then pick the highest `release-type: lts` channel and format it as `net{major}.0`). -- **placeholder:** "e.g. net10.0" -- **description:** Default to the newest generally supported .NET LTS for new libraries based on the official releases index, but also offer every other generally supported non-preview .NET LTS and STS channel so the user can choose any actively supported track. Also offer an expanded compatibility preset built from all generally supported `.NET` channels in that same index, sorted newest to oldest and formatted as semicolon-separated TFMs. Exclude preview channels. Allow custom TFMs when needed. -- **required:** true - -### benchmark_runner_project_name -- **type:** text -- **prompt:** "Benchmark runner project name?" -- **default:** `benchmark-runner` -- **description:** Solution-level tooling project that hosts `Program.cs` for BenchmarkDotNet runs. Keep the default unless the repo already uses another tooling naming convention. -- **required:** true - -### strong_name_signing -- **type:** single-choice -- **prompt:** "Enable assembly signing (.snk)?" +### repository_url +- **type:** text +- **prompt:** "Source repository URL? (GitHub)" +- **computed_default:** `https://github.com/OWNER/{root-folder-name}` where `{root-folder-name}` is resolved from the git repository root folder name (via `Split-Path -Leaf (git rev-parse --show-toplevel)`). Falls back to the current folder name if not in a git repo. +- **description:** Source code repository shown as the package's repository/source link. Example: `https://github.com/codebeltnet/savvyio`. +- **required:** true + +### package_project_url +- **type:** text +- **prompt:** "Project website/docs URL? (shown as 'Project website' on NuGet)" +- **computed_default:** `repository_url` +- **description:** Present the collected `repository_url` as the recommended value so the user can accept it or replace it with a dedicated website/docs URL. Example: accept `https://github.com/codebeltnet/savvyio` for simple packages, or replace it with `https://www.savvyio.net/`. +- **required:** true + +### target_frameworks +- **type:** text +- **prompt:** "Target frameworks? (semicolon-separated)" +- **computed_default:** Newest generally supported .NET LTS channel from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json` (filter `.NET` entries where `support-phase` is `active` or `maintenance`, then pick the highest `release-type: lts` channel and format it as `net{major}.0`). +- **placeholder:** "e.g. net10.0" +- **description:** Default to the newest generally supported .NET LTS for new libraries based on the official releases index, but also offer every other generally supported non-preview .NET LTS and STS channel so the user can choose any actively supported track. Also offer an expanded compatibility preset built from all generally supported `.NET` channels in that same index, sorted newest to oldest and formatted as semicolon-separated TFMs. Exclude preview channels. Allow custom TFMs when needed. +- **required:** true + +### benchmark_runner_project_name +- **type:** text +- **prompt:** "Benchmark runner project name?" +- **default:** `benchmark-runner` +- **description:** Solution-level tooling project that hosts `Program.cs` for BenchmarkDotNet runs. Keep the default unless the repo already uses another tooling naming convention. +- **required:** true + +### strong_name_signing +- **type:** single-choice +- **prompt:** "Enable assembly signing (.snk)?" - **choices:** - Yes (Recommended) - No @@ -95,20 +95,20 @@ Collect these parameters from the user before generating anything. Present each ## Presentation Rules -1. Ask one field at a time — wait for the answer before presenting the next field. -2. Prefer the host's native structured input controls for every field when they are available. -3. If native structured input controls are unavailable, use this exact plain-text fallback: - - Start with `Field: ` - - Repeat the field prompt verbatim from this file - - For `single-choice` and `multi-choice`, show a numbered option list and let the user answer with the number or the exact option text - - For `text` fields with a `default` or `computed_default`, show `1. Use "" (Recommended)` and `2. Enter a custom value` - - After the user answers, restate the normalized value in one short line before moving on -4. For `single-choice` and `multi-choice` fields, present options as selectable choices when possible — otherwise use the numbered plain-text fallback above instead of an open free-text prompt. -5. When a field has a `default`, present it as the first choice and append "(Recommended)" if not already labeled. -6. For `text` fields with a computed default (e.g. `{solution_name}` or `repository_url`), offer the computed value as a selectable choice alongside free text input. -7. If a field with a `default` or `computed_default` is shown to the user and they leave it blank, treat that as accepting the presented recommended value. Do not ask a second clarification question just because the typed response was empty. -8. For `target_frameworks`, compute quick-pick suggestions from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`: - - Recommended: newest generally supported LTS channel only (for example `net10.0` as of March 16, 2026) - - Include one additional single-target quick-pick for every other supported LTS or STS channel, sorted newest to oldest and labeled with its support track (for example `net9.0` and `net8.0` as of March 16, 2026) - - Expanded scope: all generally supported `.NET` channels, newest to oldest, excluding preview channels (for example `net10.0;net9.0;net8.0` as of March 16, 2026) -9. After all fields are collected, present a summary and ask for confirmation before proceeding. +1. Ask one field at a time — wait for the answer before presenting the next field. +2. Prefer the host's native structured input controls for every field when they are available. +3. If native structured input controls are unavailable, use this exact plain-text fallback: + - Start with `Field: ` + - Repeat the field prompt verbatim from this file + - For `single-choice` and `multi-choice`, show a numbered option list and let the user answer with the number or the exact option text + - For `text` fields with a `default` or `computed_default`, show `1. Use "" (Recommended)` and `2. Enter a custom value` + - After the user answers, restate the normalized value in one short line before moving on +4. For `single-choice` and `multi-choice` fields, present options as selectable choices when possible — otherwise use the numbered plain-text fallback above instead of an open free-text prompt. +5. When a field has a `default`, present it as the first choice and append "(Recommended)" if not already labeled. +6. For `text` fields with a computed default (e.g. `{solution_name}` or `repository_url`), offer the computed value as a selectable choice alongside free text input. +7. If a field with a `default` or `computed_default` is shown to the user and they leave it blank, treat that as accepting the presented recommended value. Do not ask a second clarification question just because the typed response was empty. +8. For `target_frameworks`, compute quick-pick suggestions from `https://raw.githubusercontent.com/dotnet/core/refs/heads/main/release-notes/releases-index.json`: + - Recommended: newest generally supported LTS channel only (for example `net10.0` as of March 16, 2026) + - Include one additional single-target quick-pick for every other supported LTS or STS channel, sorted newest to oldest and labeled with its support track (for example `net9.0` and `net8.0` as of March 16, 2026) + - Expanded scope: all generally supported `.NET` channels, newest to oldest, excluding preview channels (for example `net10.0;net9.0;net8.0` as of March 16, 2026) +9. After all fields are collected, present a summary and ask for confirmation before proceeding. diff --git a/skills/dotnet-new-lib-slnx/SKILL.md b/skills/dotnet-new-lib-slnx/SKILL.md index c0965d7..305cf7f 100644 --- a/skills/dotnet-new-lib-slnx/SKILL.md +++ b/skills/dotnet-new-lib-slnx/SKILL.md @@ -1,13 +1,7 @@ --- name: dotnet-new-lib-slnx description: > - Scaffold a new .NET NuGet library solution following codebelt engineering conventions. - Use this skill when the user wants to create a new NuGet library, class library, or - reusable .NET package. Also use when the user mentions "new library", "new NuGet package", - "scaffold library", "class library solution", "dotnet new classlib", or wants a .NET - library project with multi-target frameworks, strong-name signing, NuGet packaging, - DocFX documentation, CI/CD pipeline, and code quality tooling. - ALWAYS use this skill when asked to scaffold or create a new .NET library solution. + Scaffold a new .NET NuGet library solution following codebelt engineering conventions. Use this skill when the user wants to create a new NuGet library, class library, or reusable .NET package. Also use when the user mentions "new library", "new NuGet package", "scaffold library", "class library solution", "dotnet new classlib", or wants a .NET library project with multi-target frameworks, strong-name signing, NuGet packaging, DocFX documentation, CI/CD pipeline, and code quality tooling. ALWAYS use this skill when asked to scaffold or create a new .NET library solution. --- # .NET Library Solution Setup (Codebelt Conventions) diff --git a/skills/dotnet-new-lib-slnx/assets/library/nuget-readme.md b/skills/dotnet-new-lib-slnx/assets/library/nuget-readme.md index 30fb329..9f91c0c 100644 --- a/skills/dotnet-new-lib-slnx/assets/library/nuget-readme.md +++ b/skills/dotnet-new-lib-slnx/assets/library/nuget-readme.md @@ -1,12 +1,12 @@ -## {PROJECT_NAME} +## {PROJECT_NAME} Brief description of this specific package. ### Installation -```bash -dotnet add package {PROJECT_NAME} -``` +```bash +dotnet add package {PROJECT_NAME} +``` ### Usage @@ -14,4 +14,4 @@ dotnet add package {PROJECT_NAME} // Show a minimal usage example ``` -For full documentation visit [{PACKAGE_PROJECT_URL}]({PACKAGE_PROJECT_URL}). +For full documentation visit [{PACKAGE_PROJECT_URL}]({PACKAGE_PROJECT_URL}). diff --git a/skills/dotnet-new-lib-slnx/assets/shared/.github/copilot-instructions.md b/skills/dotnet-new-lib-slnx/assets/shared/.github/copilot-instructions.md index e0d5033..60ed32d 100644 --- a/skills/dotnet-new-lib-slnx/assets/shared/.github/copilot-instructions.md +++ b/skills/dotnet-new-lib-slnx/assets/shared/.github/copilot-instructions.md @@ -8,8 +8,7 @@ This document provides instructions for writing unit tests for a project/solutio ## 1. Base Class -**Always inherit from the `Test` base class** for all unit test classes. -This ensures consistent setup, teardown, and output handling across all tests. +**Always inherit from the `Test` base class** for all unit test classes. This ensures consistent setup, teardown, and output handling across all tests. > Important: Do NOT add `using Xunit.Abstractions`. xUnit v3 no longer exposes that namespace; including it is incorrect and will cause compilation errors. Use the `Codebelt.Extensions.Xunit` Test base class and `using Xunit;` as shown in the examples below. If you need access to test output, rely on the Test base class (which accepts the appropriate output helper) rather than importing `Xunit.Abstractions`. @@ -56,7 +55,7 @@ namespace Your.Namespace public class Zoo { /* ... */ } } ``` - then the corresponding unit test class must use the exact same namespace: +then the corresponding unit test class must use the exact same namespace: ```csharp namespace YourProject.Foo.Bar { @@ -148,8 +147,7 @@ namespace YourProject **Pattern name:** Public Facade Testing (also referred to as *Public API Proxy Testing*) -**Description:** -Internal classes and methods must be validated by exercising the public API that consumes them. Tests should assert observable behavior exposed by the public surface rather than targeting internal implementation details directly. +**Description:** Internal classes and methods must be validated by exercising the public API that consumes them. Tests should assert observable behavior exposed by the public surface rather than targeting internal implementation details directly. ### Example Mapping @@ -190,10 +188,7 @@ Namespace rule: DO NOT append `.Benchmarks` to the namespace. Benchmarks must li public class Sha512256Benchmark { /* ... */ } } ``` -The class name must end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix). -- The benchmarks for the YourProject.Bar assembly live in the YourProject.Bar.Benchmarks assembly. -- Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the YourProject.Bar assembly would be named ZooBenchmark and placed in the YourProject.Bar namespace in the YourProject.Bar.Benchmarks assembly. -- Modify the associated .csproj file to override the root namespace, e.g., YourProject.Bar. +The class name must end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix). - The benchmarks for the YourProject.Bar assembly live in the YourProject.Bar.Benchmarks assembly. - Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the YourProject.Bar assembly would be named ZooBenchmark and placed in the YourProject.Bar namespace in the YourProject.Bar.Benchmarks assembly. - Modify the associated .csproj file to override the root namespace, e.g., YourProject.Bar. ## 2. Attributes and Configuration diff --git a/skills/dotnet-new-lib-slnx/assets/shared/CHANGELOG.md b/skills/dotnet-new-lib-slnx/assets/shared/CHANGELOG.md index cb950bd..79aee67 100644 --- a/skills/dotnet-new-lib-slnx/assets/shared/CHANGELOG.md +++ b/skills/dotnet-new-lib-slnx/assets/shared/CHANGELOG.md @@ -2,8 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] diff --git a/skills/dotnet-new-lib-slnx/references/library.md b/skills/dotnet-new-lib-slnx/references/library.md index 6cc36de..73e4db4 100644 --- a/skills/dotnet-new-lib-slnx/references/library.md +++ b/skills/dotnet-new-lib-slnx/references/library.md @@ -198,10 +198,8 @@ Validation source: Examples: -- `net10.0` - Produces one Docker entry with `dockerImage: "codebeltnet/ubuntu-testrunner:10"` -- `net9.0;net10.0` - Produces two Docker entries with tags `9` and `10` +- `net10.0` Produces one Docker entry with `dockerImage: "codebeltnet/ubuntu-testrunner:10"` +- `net9.0;net10.0` Produces two Docker entries with tags `9` and `10` Example structure: diff --git a/skills/dotnet-strong-name-signing/SKILL.md b/skills/dotnet-strong-name-signing/SKILL.md index 4ad56bc..03c6625 100644 --- a/skills/dotnet-strong-name-signing/SKILL.md +++ b/skills/dotnet-strong-name-signing/SKILL.md @@ -1,14 +1,7 @@ --- name: dotnet-strong-name-signing -description: > - Generate a strong name key (.snk) file for signing .NET assemblies using pure - .NET cryptography — no Visual Studio Developer PowerShell or sn.exe required. - Works in any terminal. Use this skill when the user wants to create a strong - name key, generate an .snk file, sign .NET assemblies, or mentions - "strong-name", "snk", "AssemblyOriginatorKeyFile", "SignAssembly", or asks - how to sign a .NET library. Also use when scaffolding .NET libraries or NuGet - packages that need assembly signing. ALWAYS use this skill when asked to - generate or create a strong name key file. +description: > + Generate a strong name key (.snk) file for signing .NET assemblies using pure .NET cryptography — no Visual Studio Developer PowerShell or sn.exe required. Works in any terminal. Use this skill when the user wants to create a strong name key, generate an .snk file, sign .NET assemblies, or mentions "strong-name", "snk", "AssemblyOriginatorKeyFile", "SignAssembly", or asks how to sign a .NET library. Also use when scaffolding .NET libraries or NuGet packages that need assembly signing. ALWAYS use this skill when asked to generate or create a strong name key file. --- # Strong Name Signing for .NET @@ -23,9 +16,9 @@ Strong names in .NET are about **identity, not security** ([Microsoft's guidance ## Workflow -### Step 1: Collect Parameters - -Read `FORMS.md`, compute the defaults silently, and present a single summary for confirmation. Only ask follow-up questions for individual fields if the user wants to override a computed or default value. Do not proceed to Step 2 until the user confirms the summary. +### Step 1: Collect Parameters + +Read `FORMS.md`, compute the defaults silently, and present a single summary for confirmation. Only ask follow-up questions for individual fields if the user wants to override a computed or default value. Do not proceed to Step 2 until the user confirms the summary. ### Step 2: Generate the Key File diff --git a/skills/git-keep-a-changelog/SKILL.md b/skills/git-keep-a-changelog/SKILL.md index 733707c..08cad50 100644 --- a/skills/git-keep-a-changelog/SKILL.md +++ b/skills/git-keep-a-changelog/SKILL.md @@ -1,57 +1,33 @@ --- name: git-keep-a-changelog description: > - Create or update CHANGELOG.md from git history using Keep a Changelog - 1.1.0 style. Use this skill whenever the user asks to create or update - the changelog, draft release notes from the current branch, summarize commits into - Added/Changed/Fixed style sections, or mentions Keep a Changelog, - CHANGELOG.md, release highlights, or SemVer-aware release summaries. - Treat requests like "create the changelog", "update the changelog", - "write release notes from git", "draft the changelog for this branch", - or "summarize these commits into CHANGELOG.md" as automatic triggers. - This skill reads full commit subjects and bodies plus the net diff, - infers a version heading from the branch when possible, creates a - compliant changelog when missing, writes a required SemVer-aware - release highlight, edits CHANGELOG.md directly for review, preserves - natural prose wrapping, and avoids raw commit-log dumps or unsupported - claims. + Create or update CHANGELOG.md from git history using Keep a Changelog 1.1.0 style. Use when the user asks to create/update changelog, draft release notes, or mentions SemVer-aware summaries. Trigger phrases: "finalize", "ready to release", "rtr", "release" (especially with version branches like v0.3.1/...). Reads full commit bodies and diffs, creates compliant structure with required SemVer highlights, infers versions from branches, edits directly for review, preserves prose wrapping, avoids commit-log dumps. --- # Git Keep A Changelog -This skill creates or updates `CHANGELOG.md` directly using the Keep a -Changelog 1.1.0 structure. It is git-aware, changelog-focused, and -optimized for a human-readable release summary rather than generated -release-note noise. +This skill creates or updates `CHANGELOG.md` directly using the Keep a Changelog 1.1.0 structure. It is git-aware, changelog-focused, and optimized for a human-readable release summary rather than generated release-note noise. ## Non-Negotiable Rules - Create or update `CHANGELOG.md` directly, then stop for user review. -- If `CHANGELOG.md` does not exist, create a compliant one before - populating it. +- If `CHANGELOG.md` does not exist, create a compliant one before populating it. - Read full commit subjects and bodies before writing the changelog. - Inspect the net diff too; do not infer the release from subjects alone. -- If the current branch starts with a version hint such as `v0.3.0/`, - use that to target a concrete release heading. +- If the current branch starts with a version hint such as `v0.3.0/`, use that to target a concrete release heading. - Otherwise, target `## [Unreleased]`. - Always write a release highlight immediately below the target heading. -- The release highlight must explicitly classify the release as `major`, - `minor`, or `patch`. -- Use the standard Keep a Changelog section order: - `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`. +- The release highlight must explicitly classify the release as `major`, `minor`, or `patch`. +- Use the standard Keep a Changelog section order: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`. - Omit empty sections instead of emitting placeholders. -- Preserve natural line breaks and readable prose. Do not apply any fixed - column limit or artificial hard wrapping to changelog paragraphs or - bullets. -- End each bullet with `,` and end the last bullet in each section with - `.`. +- Preserve natural line breaks and readable prose. Do not apply any fixed column limit or artificial hard wrapping to changelog paragraphs or bullets. +- End each bullet with `,` and end the last bullet in each section with `.`. - Do not dump commit subjects verbatim into the changelog. - Do not invent unsupported changes, risks, or migration guidance. ## Release Highlight Contract -Every updated changelog entry must begin with a short human-written -highlight paragraph directly below the heading. +Every updated changelog entry must begin with a short human-written highlight paragraph directly below the heading. That highlight must: @@ -72,8 +48,7 @@ validator hardening, and clearer changelog automation guidance. ... ``` -When the history clearly carries migration risk or upgrade caveats, add -an advisory block such as: +When the history clearly carries migration risk or upgrade caveats, add an advisory block such as: ```md > [!WARNING] @@ -88,12 +63,10 @@ Only add callouts when the commits or diff justify them. Use the most explicit range the user gave you. -- If the user named a range, branch comparison, base branch, or PR range, - use that. +- If the user named a range, branch comparison, base branch, or PR range, use that. - Otherwise, compare the current branch to its upstream merge-base. - If no upstream is configured, try `main`, then `master`. -- If no safe comparison point can be established, stop and ask for a - base branch or range instead of guessing. +- If no safe comparison point can be established, stop and ask for a base branch or range instead of guessing. Helpful commands: @@ -108,26 +81,26 @@ git merge-base HEAD master ### Step 2: Resolve the changelog target -Determine whether to write a concrete release section or update -`[Unreleased]`. +Determine whether to write a concrete release section or update `[Unreleased]`. -- If the branch name starts with a version prefix such as - `v0.3.0/feature-name`, target `## [0.3.0] - YYYY-MM-DD`. -- Strip the leading `v` from the visible changelog heading, but keep tag - comparisons in `vX.Y.Z` form. +When the user asks to "finalize", "ready to release", "rtr", "release", "publish", or "ship" (or similar release-intent words): +- Extract the version from the current branch name if it starts with a version prefix such as `v0.3.0/feature-name`. +- Target `## [X.Y.Z] - YYYY-MM-DD` (today's date) for that extracted version. +- This is a strong signal that the user wants to finalize that specific release in the changelog. + +Otherwise: +- If the branch name starts with a version prefix such as `v0.3.0/feature-name`, target `## [0.3.0] - YYYY-MM-DD`. +- Strip the leading `v` from the visible changelog heading, but keep tag comparisons in `vX.Y.Z` form. - If no version hint exists, target `## [Unreleased]`. -- If the target heading already exists, update it in place instead of - duplicating it. +- If the target heading already exists, update it in place instead of duplicating it. ### Step 3: Read the full history and net effect Read enough git history to understand what the release actually changed. - Read the full commit message bodies, not just `--oneline`. -- Inspect the net diff so fixups and partial reversals do not distort the - changelog. -- Prefer the final user-visible or maintainer-meaningful outcome over the - implementation path. +- Inspect the net diff so fixups and partial reversals do not distort the changelog. +- Prefer the final user-visible or maintainer-meaningful outcome over the implementation path. Helpful commands: @@ -142,55 +115,37 @@ git diff ..HEAD Infer the SemVer class from the actual change set. -- `major` when the release includes breaking removals, required migration, - incompatible contract changes, or other true breaking behavior. -- `minor` when the release adds meaningful new capabilities without - breaking existing consumers. -- `patch` when the release is primarily fixes, service updates, docs, - validation, maintenance, dependency work, or other non-breaking - refinement. +- `major` when the release includes breaking removals, required migration, incompatible contract changes, or other true breaking behavior. +- `minor` when the release adds meaningful new capabilities without breaking existing consumers. +- `patch` when the release is primarily fixes, service updates, docs, validation, maintenance, dependency work, or other non-breaking refinement. -Do not over-classify from dramatic wording in a commit subject. The net -effect matters more than the phrasing of one commit. +Do not over-classify from dramatic wording in a commit subject. The net effect matters more than the phrasing of one commit. ### Step 5: Curate the changelog content Write the release highlight first, then the populated sections. -- Map the net effect into `Added`, `Changed`, `Deprecated`, `Removed`, - `Fixed`, and `Security`. +- Map the net effect into `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, and `Security`. - Keep bullets curated and human-written. -- Merge overlapping commits into one bullet when they describe the same - real outcome. -- Drop low-signal churn such as typo-only commits, trivial fixups, or - mechanical follow-ups unless they materially change the release story. -- Use natural prose line breaks. Keep paragraphs and bullets readable, but - do not column-wrap them artificially or target a fixed line width. -- End each bullet with `,` except the final bullet in a populated section, - which must end with `.`. +- Merge overlapping commits into one bullet when they describe the same real outcome. +- Drop low-signal churn such as typo-only commits, trivial fixups, or mechanical follow-ups unless they materially change the release story. +- Use natural prose line breaks. Keep paragraphs and bullets readable, but do not column-wrap them artificially or target a fixed line width. +- End each bullet with `,` except the final bullet in a populated section, which must end with `.`. ### Step 6: Update CHANGELOG.md carefully Preserve the file's existing structure while editing. -- If `CHANGELOG.md` is missing, create it with the standard title, - intro paragraph, `## [Unreleased]`, and compare-link footer before - inserting release content. +- If `CHANGELOG.md` is missing, create it with the standard title, intro paragraph, `## [Unreleased]`, and compare-link footer before inserting release content. - Keep the introduction and existing release history intact. -- If writing a concrete release section, insert it below `## [Unreleased]` - and above older releases. -- If writing to `## [Unreleased]`, keep the heading and update only its - content. -- Update compare links at the bottom when adding a concrete version: - `[Unreleased]` should compare from the new version to `HEAD`, and the - new version should compare from the previous version tag to the new tag. -- Do not remove existing links or historical entries unless they are - demonstrably wrong. +- If writing a concrete release section, insert it below `## [Unreleased]` and above older releases. +- If writing to `## [Unreleased]`, keep the heading and update only its content. +- Update compare links at the bottom when adding a concrete version: `[Unreleased]` should compare from the new version to `HEAD`, and the new version should compare from the previous version tag to the new tag. +- Do not remove existing links or historical entries unless they are demonstrably wrong. ### Step 7: Stop after the edit -After updating `CHANGELOG.md`, stop and let the user review the file. -Do not commit, tag, push, or create a release unless the user asks. +After updating `CHANGELOG.md`, stop and let the user review the file. Do not commit, tag, push, or create a release unless the user asks. ## Good Output Characteristics @@ -200,8 +155,7 @@ Do not commit, tag, push, or create a release unless the user asks. - Creates a compliant `CHANGELOG.md` scaffold when the file is missing. - Reflects the meaning of full commit bodies and the net diff. - Preserves natural prose wrapping with no fixed column-width target. -- Keeps bullets specific, concrete, non-repetitive, and consistently - punctuated. +- Keeps bullets specific, concrete, non-repetitive, and consistently punctuated. - Preserves existing compare-link structure when updating versions. ## Bad Output Characteristics @@ -211,7 +165,6 @@ Do not commit, tag, push, or create a release unless the user asks. - Failing to classify the release as major, minor, or patch. - Refusing to proceed just because `CHANGELOG.md` does not exist yet. - Using any artificial fixed-width wrapping for changelog prose. -- Mixing bullet punctuation or leaving section bullets without the - required trailing `,` / final `.` pattern. +- Mixing bullet punctuation or leaving section bullets without the required trailing `,` / final `.` pattern. - Emitting empty `Added` / `Changed` / `Fixed` headings. - Claiming breaking changes, fixes, or security work not supported by git. diff --git a/skills/git-nuget-readme/SKILL.md b/skills/git-nuget-readme/SKILL.md new file mode 100644 index 0000000..79c187c --- /dev/null +++ b/skills/git-nuget-readme/SKILL.md @@ -0,0 +1,194 @@ +--- +name: git-nuget-readme +description: > + Create or update a NuGet package README.md from git history and real .NET project metadata for repositories that ship a package from `src/`. Use this skill whenever the user asks to write a package README, refresh NuGet-facing docs, improve the repo README for a library, summarize the current branch into README copy, or make a package more compelling to adopt on NuGet. Treat requests like "update the README for this package", "write a NuGet README from git", "refresh the library README", "make this NuGet package easier to pick", or "generate a devex-friendly README for this assembly" as automatic triggers. The skill discovers the advertised packable project, grounds the README in real package and source metadata, preserves honest claims, and writes forthcoming, adoption-friendly copy instead of generic marketing fluff. +--- + +# Git NuGet README + +This skill creates or updates a package-facing `README.md` for a .NET repository by combining git history, actual project/package metadata, and concrete source-level capabilities. It improves the developer experience by pulling install guidance, package value, and a quick start closer to the top while keeping branding and tone derived from the current repository rather than from any hardcoded ecosystem template. + +Read `references/nuget-readme-blueprint.md` before writing or rewriting the README. + +## Non-Negotiable Rules + +- Create or update `README.md` directly, then stop for user review. +- Anchor the README to the real advertised packable project or package, not to a vague repo-wide theme. +- Discover packable projects under `src/`; ignore `test/`, `tuning/`, `tooling/`, and projects that are explicitly non-packable. +- If the target project is ambiguous, stop and ask instead of guessing. +- Read full commit subjects and bodies before refreshing README copy. +- Inspect the net diff too; do not write the README from commit subjects alone. +- When feasible, inspect unit or functional tests associated with the advertised package and use them as supporting hints for scenarios, examples, or capability wording. +- Ground every capability claim in actual source, project metadata, existing docs, relevant tests, or the current diff. +- Use the exact project/package/assembly name the README is advertising. +- Derive branding, owner naming, and repo voice from the current repo, package metadata, and existing README when present. +- Never inject ecosystem- or vendor-specific branding such as `Codebelt` unless the current repository already uses it explicitly. +- Keep the tone forthcoming, concrete, and developer-first. +- Make the package easy to evaluate quickly: value proposition, install path, supported frameworks, docs, and a small getting-started example should be easy to find. +- Do not fabricate badges, benchmarks, stars, docs URLs, compatibility, or package relationships. +- Preserve useful stable sections such as contributing, license, documentation, or badge groups when they are still accurate. +- Prefer improving and reorganizing an existing README over replacing it wholesale when stable sections can be kept. +- Do not dump commit subjects verbatim into the README. +- Do not write generic AI-marketing copy such as "powerful solution", "seamless integration", or "cutting-edge toolkit" unless the concrete substance is immediately explained. + +## Workflow + +### Step 1: Resolve the advertised project + +Identify which packable project the README is meant to advertise. + +Use this order: + +1. Explicit project, package, or assembly named by the user. +2. Existing README title/package focus if it is already clearly scoped. +3. The primary packable project under `src/` that matches the repo name, package ID, or solution identity. + +If multiple packable projects could plausibly own the README and the repo does not already make the primary one obvious, stop and ask which package the README should center. + +Helpful commands: + +```bash +git status --short --branch +rg --files src -g *.csproj +rg -n "||||" src +``` + +### Step 2: Resolve the source range + +Use the most explicit range the user gave you. + +- If the user named a branch comparison, PR range, or base branch, use that. +- Otherwise, compare the current branch to its upstream merge-base. +- If no upstream exists, try `main`, then `master`. +- If no safe comparison point can be established, stop and ask for a base branch or range instead of guessing. + +Helpful commands: + +```bash +git rev-parse --abbrev-ref HEAD +git rev-parse --abbrev-ref --symbolic-full-name @{upstream} +git merge-base HEAD @{upstream} +git merge-base HEAD main +git merge-base HEAD master +``` + +### Step 3: Gather package metadata and README anchors + +Collect the concrete facts the README should advertise. + +- Project/package/assembly name +- Package ID +- Repo owner or organization naming when relevant +- Description and repository/project URLs from the project when present +- Target framework(s) +- Existing docs or DocFx links when present +- Existing README sections worth preserving +- Existing title/branding conventions already used by the repo +- Real package relationships if this is an umbrella/meta package + +Prefer explicit project metadata over inference. When a docs site or package URL cannot be proven from the repo, omit it instead of inventing it. Apply the same rule to branding: use the repository's actual identity, not a remembered template from another ecosystem. + +Helpful commands: + +```bash +rg -n "||<Description>|<PackageProjectUrl>|<RepositoryUrl>|<AssemblyName>" src README.md Directory.Build.props Directory.Build.targets +rg -n "DocFx|docfx|nuget.org|PackageReference" README.md .docfx src +git remote -v +``` + +### Step 4: Inspect the actual project changes and capabilities + +Understand what the package really offers and what changed in the chosen range. + +- Read full commit bodies for the selected range. +- Inspect the net diff for the target project plus shared packaging or docs files that materially affect the package. +- Inspect the main source folders to confirm the real capability areas. +- When the repo has corresponding unit or functional tests for the advertised package, inspect those tests too for user-facing examples, realistic scenarios, or terminology the README can reuse honestly. +- Prefer the net effect over the implementation path when there are fixups or reversals. + +Helpful commands: + +```bash +git log --reverse --format=medium <range> -- <paths> +git log --reverse --stat --format=medium <range> -- <paths> +git diff --stat <base>..HEAD -- <paths> +git diff <base>..HEAD -- <paths> +rg -n "namespace |public (class|interface|struct|record|enum)|extension" src/<ProjectName> +rg --files test -g *Tests*.cs +rg -n "<ProjectName>|<PackageId>|namespace " test +``` + +### Step 5: Draft the README from the blueprint + +Use the structure and tone from `references/nuget-readme-blueprint.md`. + +Default shape: + +1. Title and existing badge strip when the repo already uses one +2. Short "About" or value proposition section +3. Supported framework statement +4. Why pick this package / key capabilities +5. Installation or package section +6. Quick start or minimal example when the codebase justifies it +7. Documentation link when available +8. Contributing and license + +Strong README characteristics: + +- The first screen tells the developer what the package is for and why they might choose it. +- The copy speaks to actual scenarios, not abstract superlatives. +- The title and tone match the repo's own identity instead of importing branding from unrelated repositories. +- Installation is easy to find. +- The example is minimal, truthful, and uses real types or namespaces. +- When feasible, the example or scenario wording is reinforced by associated unit or functional tests rather than invented usage. +- Supported frameworks are explicit. +- The README sounds welcoming and opinionated without overselling. + +### Step 6: Preserve and improve intelligently + +When the repo already has a README, keep the accurate parts and improve the experience: + +- Preserve badges, contributing, license, and docs links when still valid. +- Reorder sections when that improves first-time package evaluation. +- Tighten vague copy into concrete benefits and scenarios. +- Replace stale claims with current, source-backed wording. +- Avoid deleting useful historical context unless it is clearly wrong or the user asked for a leaner rewrite. + +### Step 7: Write the README.md + +Write or update `README.md` directly. + +Editing rules: + +- Keep headings concise and scan-friendly. +- Prefer short paragraphs and flat bullets. +- Put installation before deeper reference material. +- If you include a code example, keep it small and runnable-looking. +- Use fenced code blocks with language tags. +- Keep product/package names exact. +- Link to real docs or package pages only when the repo supports them. +- Keep org or vendor naming repo-derived. If the current repo never says `by <owner>` or uses a branded suffix, do not add one just because another repo family does. + +### Step 8: Stop after the edit + +After updating `README.md`, stop and let the user review it. Do not commit, tag, push, pack, or publish unless the user asks. + +## Good Output Characteristics + +- Reads like a package README a developer would want to skim before installing. +- Leads with a clear value proposition and concrete capability areas. +- Makes install, supported frameworks, and docs easy to find. +- Uses real package names, namespaces, and examples from the codebase. +- Adapts branding and heading style from repo metadata instead of hardcoding another ecosystem's naming pattern. +- Preserves stable repo sections while improving adoption-oriented copy. +- Sounds welcoming and credible rather than generic or overhyped. + +## Bad Output Characteristics + +- A README that could apply to almost any .NET library. +- Claims about performance, reliability, compatibility, or integrations that are not proven by the repo. +- Hiding installation or framework support deep in the file. +- Generic marketing phrases with no technical substance. +- Injecting branding, docs hostnames, or title conventions copied from a different repo family. +- Examples that invent APIs, namespaces, or package IDs. +- Blindly replacing an existing good badge/docs/contributing structure with a totally different template. diff --git a/skills/git-nuget-readme/evals/evals.json b/skills/git-nuget-readme/evals/evals.json new file mode 100644 index 0000000..d860fca --- /dev/null +++ b/skills/git-nuget-readme/evals/evals.json @@ -0,0 +1,69 @@ +{ + "skill_name": "git-nuget-readme", + "evals": [ + { + "id": 1, + "prompt": "Update the README.md for the current branch from git history and actual project metadata. Refresh the package-facing copy directly in the file and stop for my review.", + "expected_output": "README.md is updated in place with package-facing copy grounded in git history and project metadata rather than only drafted in chat.", + "expectations": [ + "Updates README.md directly instead of only proposing README text in chat", + "Reads full commit subjects and bodies before refreshing README copy", + "Uses the current branch versus merge-base as the default source when no explicit range is given", + "Stops after editing the README for user review" + ] + }, + { + "id": 2, + "prompt": "This repo has multiple packable projects under src. Refresh the README for the advertised package, but do not guess which package it should sell if the repo does not make that obvious.", + "expected_output": "The skill either resolves the advertised package from repo/project cues or stops to ask instead of guessing when the target is ambiguous.", + "expectations": [ + "Discovers packable src projects instead of treating test or tooling projects as publishable packages", + "Uses explicit package/repo cues to resolve the advertised project when possible", + "Stops and asks instead of guessing when multiple packable projects are plausible README targets" + ] + }, + { + "id": 3, + "prompt": "Rewrite the package README so it has a better developer experience: make the value proposition clearer, surface installation and supported target frameworks, and keep the claims honest.", + "expected_output": "The README leads with a concrete package value proposition and makes install/framework support easy to find without drifting into generic marketing copy.", + "expectations": [ + "Uses the exact package or project name the README is advertising", + "Makes installation guidance easy to find near the top of the README", + "Derives supported frameworks from actual project metadata instead of guessing", + "Keeps the tone developer-first and avoids generic hype language", + "Grounds capability claims in actual source, project metadata, docs, or the current diff", + "Derives branding and title style from the current repo instead of hardcoding another ecosystem's naming pattern" + ] + }, + { + "id": 4, + "prompt": "Our existing README already has badges, docs links, contributing guidance, and license info. Refresh the adoption-focused sections without throwing away those stable parts.", + "expected_output": "The README keeps accurate stable sections while improving the package-facing pitch and section order.", + "expectations": [ + "Preserves useful existing badge, docs, contributing, or license sections when they are still accurate", + "Improves and reorganizes the README instead of blindly replacing stable sections", + "Keeps documentation links only when they are supported by the repo" + ] + }, + { + "id": 5, + "prompt": "If the codebase supports it, add a small quick-start example with real namespaces or types so a NuGet user can understand the package in 30 seconds.", + "expected_output": "A truthful, concise quick-start example is included when the codebase clearly supports one, and it uses real APIs rather than invented ones.", + "expectations": [ + "Adds a small quick-start example only when the codebase justifies it", + "Uses real namespaces, package IDs, or types from the repo instead of invented APIs", + "Keeps the example concise and developer-oriented" + ] + }, + { + "id": 6, + "prompt": "When feasible, pick up hints from unit or functional tests associated with the advertised package so the README examples and scenarios sound like real usage instead of invented marketing copy.", + "expected_output": "The README refresh uses associated tests as supporting hints when they exist, especially for scenario wording or quick-start examples, without inventing APIs or claims.", + "expectations": [ + "Inspects associated unit or functional tests when the repo makes them available and relevant", + "Uses test-backed scenarios or terminology as supporting hints for README copy when feasible", + "Does not invent unsupported APIs, workflows, or examples when no suitable tests exist" + ] + } + ] +} diff --git a/skills/git-nuget-readme/references/nuget-readme-blueprint.md b/skills/git-nuget-readme/references/nuget-readme-blueprint.md new file mode 100644 index 0000000..fa445a5 --- /dev/null +++ b/skills/git-nuget-readme/references/nuget-readme-blueprint.md @@ -0,0 +1,192 @@ +# NuGet README Blueprint + +This reference distills a recurring package-README shape observed in the inspiration set and folds in a few improvements aimed at package adoption and first-run developer experience. Treat the inspiration as a pattern library, not as branding that should be copied into every repo. + +## Observed Common Denominators + +Across the inspected `.NET` repos, the README pattern repeatedly includes: + +1. A product-style title tied to the repo's own identity +2. A badge strip near the top +3. A short `About` section with a benefit-oriented summary +4. A supported-framework statement +5. A documentation/DocFx link +6. A `Standalone Packages` or package section +7. Contributing and license sections + +Common voice patterns: + +- welcoming but technical +- package-focused rather than company-focused +- one or two short positioning lines +- minimal friction to discover docs and package feeds + +Examples of recurring ideas from the inspiration set: + +- "Your ... companion for modern development" +- explicit `.NET` support statements +- concrete package IDs and docs links +- clear contribution/license follow-through + +## Recommended Improvements + +The current pattern is already solid, but a NuGet adoption-focused README can improve on it by: + +1. Moving the package value proposition even closer to the top +2. Making install guidance immediately visible +3. Adding a "why pick this package" section with concrete capability bullets +4. Including a 30-second quick-start example when the API surface makes that safe and truthful +5. Turning vague positioning into scenario-backed copy + +## Recommended Section Order + +Use this order unless the existing README has a strong reason to differ: + +1. Title +2. Existing badge strip, if present and still accurate +3. `About` or short value proposition +4. Supported frameworks +5. Why pick this package +6. Installation / package section +7. Quick start +8. Documentation +9. Contributing +10. License + +## Section Guidance + +### Title + +Prefer the exact advertised project or package name and derive any branding suffix from the current repo itself. + +Examples: + +- `# Unitify API` +- `# Shared Kernel API` +- `# Extensions for AWS Signature Version 4 API` + +If the current repo already uses a title shape such as `by <owner>` or a branded suffix, preserve it. If not, do not inject one from another ecosystem's README style. + +### About + +Use 1-3 short paragraphs that answer: + +- what the package is +- what problem it helps solve +- why a .NET developer might choose it + +Good pattern: + +- exact package domain +- concrete scope +- one clear positioning sentence +- repo-derived naming and tone + +Avoid: + +- empty adjectives +- inflated "enterprise-grade" claims unless the repo truly supports them + +### Supported Frameworks + +State framework support explicitly and read it from actual project metadata. + +Examples: + +- `Your companion for modern development with .NET 9 and .NET 10.` +- `Targets the latest supported LTS and STS .NET releases.` + +Do not guess supported frameworks from memory. + +### Why Pick This Package + +Use a short flat bullet list grounded in real capabilities. + +Good bullets usually cover: + +- the core capability area +- a differentiator or opinionated design choice +- where it fits in a developer workflow + +Example shapes: + +- `Focused API for ...` +- `Consistent extension model for ...` +- `Designed for ... scenarios in modern .NET solutions` + +### Installation / Package Section + +Make package installation easy to spot. + +Recommended elements: + +- package ID +- `dotnet add package ...` +- NuGet page link when known +- package matrix only when the repo ships multiple relevant packages + +If the repo already uses a `Standalone Packages` section, preserve that concept and tighten the copy around it. + +### Quick Start + +Only include a code sample when the repo can support it honestly. + +Good sample characteristics: + +- small and readable +- real namespaces or types from the package +- aligned with realistic usage patterns visible in source or associated unit/functional tests when those tests exist +- enough to give the reader a first success path + +Avoid speculative or pseudo-code APIs. + +### Documentation + +If a real docs site exists, link it clearly and early enough that the reader can find it without scanning the entire file. + +Examples: + +- `Full documentation (generated by DocFx) is available at ...` + +Do not invent a docs URL just because similar repos use one. + +### Contributing and License + +These are usually stable and should be preserved when already correct. + +Keep them short and welcoming. + +## Tone + +The README should feel: + +- forthcoming +- credible +- developer-first +- easy to skim +- honest about scope + +It should not feel: + +- like generic startup copy +- like a raw changelog +- like a commit summary pasted into Markdown + +## Good Example Characteristics + +- "About" section explains the real problem space +- install guidance is near the top +- package IDs and framework support are exact +- the quick start helps the reader imagine using the package +- usage language can be traced back to real source or associated tests +- branding and title style are derived from the current repo rather than copied from the inspiration set +- contributing/license sections remain intact + +## Bad Example Characteristics + +- opening with badges and no explanation of the package +- hiding install steps below long prose +- using phrases like "revolutionary toolkit" or "seamless synergy" +- copying a `by <brand>` title pattern when the current repo does not actually use that branding +- claiming package relationships, docs, or supported TFMs that are not backed by the repo +- showing fake namespaces or made-up APIs diff --git a/skills/git-nuget-release-notes/SKILL.md b/skills/git-nuget-release-notes/SKILL.md new file mode 100644 index 0000000..aad4c21 --- /dev/null +++ b/skills/git-nuget-release-notes/SKILL.md @@ -0,0 +1,182 @@ +--- +name: git-nuget-release-notes +description: > + Create or update per-package NuGet release notes from git history for .NET repositories that store cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files. Use this skill whenever the user asks for NuGet release notes, `PackageReleaseNotes.txt`, per-assembly or per-package release notes, or wants git commits turned into package release notes instead of a repo-wide changelog. Treat requests like "update PackageReleaseNotes.txt", "write NuGet release notes from git", "summarize this release per assembly", or "create missing package release notes under .nuget" as automatic triggers. The skill discovers packable `src/` projects, resolves concrete release version and availability per package, creates missing files when needed, preserves cumulative newest-first history, and avoids raw commit-log dumps or unsupported claims. +--- + +# Git NuGet Release Notes + +This skill creates or updates cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files for packable .NET projects by reading git history and the actual project/package metadata. It is intentionally closer to the package-note style used in codebelt repositories than to a repo-wide `CHANGELOG.md`. + +Read `references/package-release-notes-format.md` before writing any release-note block. + +## Critical + +- Create or update `.nuget/{ProjectName}/PackageReleaseNotes.txt` directly, then stop for user review. +- Discover packable projects under `src/`; ignore `test/`, `tuning/`, `tooling/`, and projects that are explicitly non-packable. +- Prefer an existing `.nuget/{ProjectName}/` folder when one already exists for the packable project. If none exists, create `.nuget/<MSBuildProjectName>/PackageReleaseNotes.txt`. +- For repo-wide requests, every packable `src/` project should end up represented by a corresponding `PackageReleaseNotes.txt` file. +- Read full commit subjects and bodies before writing the package notes. +- Inspect the net diff too; do not classify a package from commit subjects alone. +- Use cumulative newest-first history. +- If the target version already exists at the top of the file, rewrite that block in place instead of duplicating it. +- If the target version is not present, prepend the new block above the older history. +- Normalize the block you write to `Version:` and `Availability:`. +- Always include `# ALM` in the block you write. +- Use only this section order when sections are populated: `ALM`, `Breaking Changes`, `New Features`, `Improvements`, `Bug Fixes`, `References`. +- Omit empty sections instead of emitting placeholders. +- Start every bullet with an all-caps action verb such as `ADDED`, `CHANGED`, `REMOVED`, `FIXED`, `EXTENDED`, `OPTIMIZED`, `MOVED`, `RENAMED`, `DEPRECATED`, or `REFACTORED`. +- Keep package/type/member identifiers exact where possible. +- Do not dump commit subjects verbatim into the release notes. +- Do not invent unsupported changes, package references, or availability. +- Ignore odd historical spacing such as non-breaking spaces in older entries; normalize only the block you are writing unless the user asks for a larger cleanup. + +## Workflow + +### Step 1: Resolve the source range + +Use the most explicit range the user gave you. + +- If the user named a range, branch comparison, base branch, or PR range, use that. +- Otherwise, compare the current branch to its upstream merge-base. +- If no upstream is configured, try `main`, then `master`. +- If no safe comparison point can be established, stop and ask for a base branch or range instead of guessing. + +Helpful commands: + +```bash +git status --short --branch +git rev-parse --abbrev-ref HEAD +git rev-parse --abbrev-ref --symbolic-full-name @{upstream} +git merge-base HEAD @{upstream} +git merge-base HEAD main +git merge-base HEAD master +``` + +### Step 2: Discover the target packages + +Discover the packable `src/` projects that belong in `.nuget/`. + +- Enumerate `src/**/*.csproj`. +- Exclude projects that live outside `src/` or are clearly test, benchmark, sample, or tooling projects. +- Exclude projects with `IsPackable` explicitly set to `false`. +- Keep project identity anchored to the packable project name or the existing `.nuget/{ProjectName}/` folder already used by the repo. +- When the user asked for repo-wide release notes coverage, ensure every packable project is represented. Otherwise, focus on the projects affected by the requested range. + +Helpful commands: + +```bash +rg --files src -g *.csproj +git diff --name-only <base>..HEAD -- src .nuget Directory.Build.props Directory.Build.targets Directory.Packages.props +``` + +### Step 3: Resolve the concrete release version + +Each release-note block needs a real package version, not an `[Unreleased]` placeholder. + +Use this order: + +1. Explicit version provided by the user. +2. Branch prefix such as `v0.3.1/feature-name` -> `0.3.1`. +3. Evaluated package version from the project if it is concrete and safe to use. + +If you cannot determine a safe concrete version, stop and ask instead of guessing. + +Do not infer a version by bumping the previous entry manually unless the user explicitly asked you to choose the next version. + +### Step 4: Resolve the availability line + +Derive `Availability:` from the package's target frameworks. + +- Read `TargetFramework` or `TargetFrameworks` from the project and any inherited repo-level props when needed. +- Preserve the project order when rendering frameworks. +- Convert TFMs to the human-readable style used by the existing files. +- Join the final list with commas and `and`. + +Examples: + +- `net10.0;net9.0` -> `.NET 10 and .NET 9` +- `net10.0;net9.0;netstandard2.0` -> `.NET 10, .NET 9 and .NET Standard 2.0` +- `net10.0;net9.0;netstandard2.1;netstandard2.0` -> `.NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0` + +Do not guess availability from memory if the project file or evaluated MSBuild properties can answer it. + +### Step 5: Inspect the actual package changes + +For each target package, read enough history and diff to understand the real release story for that package. + +- Read the full commit bodies for the selected range. +- Inspect the net diff for the package's project folder plus shared packaging/build files that materially affect that package. +- Include shared files such as `Directory.Packages.props`, `Directory.Build.props`, `Directory.Build.targets`, and `.nuget/{ProjectName}/` when they affect the package. +- Prefer the net effect over the implementation path when there are fixups or reversals. + +Helpful commands: + +```bash +git log --reverse --format=medium <range> -- <paths> +git log --reverse --stat --format=medium <range> -- <paths> +git diff --stat <base>..HEAD -- <paths> +git diff <base>..HEAD -- <paths> +``` + +### Step 6: Classify the content into the package-note format + +Use the normalized section order from `references/package-release-notes-format.md`. + +Classification guidance: + +- `# ALM`: dependency upgrades, TFM support added/removed, packaging metadata changes, or other release-engineering/package-management changes. +- `# Breaking Changes`: incompatible renames, removals, moved APIs, changed contracts, or behavior that requires consumer action. +- `# New Features`: additive new APIs, capabilities, packages, or newly exposed options. +- `# Improvements`: non-breaking enhancements such as `CHANGED`, `EXTENDED`, `OPTIMIZED`, `DEPRECATED`, or other refinements. +- `# Bug Fixes`: defects corrected for existing behavior. +- `# References`: package IDs only, and only when the package is an umbrella/meta package or the existing file already carries a references section the current release should preserve. + +Prefer a minimal truthful block over an inflated one. ALM-only releases are valid when the real change was only dependency or TFM maintenance. + +### Step 7: Write or update PackageReleaseNotes.txt + +Write the block in this normalized shape: + +```text +Version: 0.3.1 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +# New Features +- ADDED ... +``` + +Editing rules: + +- If the file is missing, create it with the new block only. +- If the top block already targets the resolved version, replace that top block in place and leave older history below it intact. +- If the top block targets an older version, prepend the new block and a blank line before the existing history. +- Preserve older release blocks below the edited one unless the user explicitly asked for a historical cleanup. +- Keep bullets concise, concrete, and single-line unless a longer line is genuinely needed for clarity. +- Do not add decorative Markdown, tables, or changelog callouts. + +### Step 8: Stop after the edit + +After updating the relevant `PackageReleaseNotes.txt` files, stop and let the user review them. Do not commit, tag, push, pack, or publish unless the user asks. + +## Good Output Characteristics + +- Reads like curated package release notes, not a repo-wide changelog. +- Keeps one truthful release block per package/version. +- Uses concrete package/type/member names and namespaces. +- Writes the newest release first while preserving older history. +- Keeps ALM details explicit when dependencies or TFMs changed. +- Creates missing files when the package should be represented. +- Keeps availability aligned with actual target frameworks. + +## Bad Output Characteristics + +- Writing one repo-level summary and copying it into every package file. +- Using `Unreleased` or omitting the concrete version line. +- Guessing availability instead of reading project metadata. +- Dumping commit subjects line by line into the file. +- Creating empty headings or filler bullets like "misc updates". +- Claiming breaking changes, fixes, or references not supported by git and the project/package metadata. diff --git a/skills/git-nuget-release-notes/evals/evals.json b/skills/git-nuget-release-notes/evals/evals.json new file mode 100644 index 0000000..d718d4c --- /dev/null +++ b/skills/git-nuget-release-notes/evals/evals.json @@ -0,0 +1,63 @@ +{ + "skill_name": "git-nuget-release-notes", + "evals": [ + { + "id": 1, + "prompt": "Update the NuGet package release notes for the current branch from git history. Use the default branch comparison, update the relevant .nuget/*/PackageReleaseNotes.txt files directly, and stop for my review.", + "expected_output": "The relevant PackageReleaseNotes.txt files are updated in place from git history rather than being drafted only in chat.", + "expectations": [ + "Updates .nuget/<ProjectName>/PackageReleaseNotes.txt files directly instead of only drafting release notes in chat", + "Reads full commit subjects and bodies before writing the package release notes", + "Uses the current branch versus merge-base as the default source when no explicit range is given", + "Discovers packable src projects instead of treating test or tooling projects as publishable packages", + "Stops after editing the release-note files for user review" + ] + }, + { + "id": 2, + "prompt": "My branch is named v0.3.1/nuget-skills. Generate per-package PackageReleaseNotes.txt entries from git history and use that branch hint if it is safe.", + "expected_output": "The release-note block uses the concrete version from the branch hint and avoids an Unreleased-style placeholder.", + "expectations": [ + "Treats a leading branch version such as v0.3.1/ as a concrete release hint", + "Uses a concrete Version line instead of an Unreleased placeholder", + "Rewrites the top block in place when the resolved version already exists there", + "Prepends a new block when the file exists but targets an older version", + "Stops and asks instead of guessing when no safe concrete version can be determined" + ] + }, + { + "id": 3, + "prompt": "Some of our packable projects under src do not have .nuget/<ProjectName>/PackageReleaseNotes.txt yet. Create the missing files as part of this release-note pass and derive Availability from the actual target frameworks.", + "expected_output": "Missing PackageReleaseNotes.txt files are created for the relevant packable projects and each new block includes a human-readable availability line derived from project target frameworks.", + "expectations": [ + "Creates missing .nuget/<ProjectName>/PackageReleaseNotes.txt files when the package should be represented", + "Derives Availability from TargetFramework or TargetFrameworks instead of guessing from memory", + "Renders framework lists in the normalized human-readable style used by existing package release-note files", + "Normalizes the block it writes to Version: and Availability:" + ] + }, + { + "id": 4, + "prompt": "Write the package release notes in the codebelt-style PackageReleaseNotes.txt format. Keep ALM first, use only the established section vocabulary, and do not dump commit subjects verbatim.", + "expected_output": "The package notes follow the normalized codebelt-style section order with ALM first and concise verb-led bullets rather than raw commit log output.", + "expectations": [ + "Always includes ALM in the written release block", + "Uses only the established section order ALM, Breaking Changes, New Features, Improvements, Bug Fixes, References", + "Omits empty sections instead of inserting placeholders", + "Starts bullets with an all-caps action verb such as ADDED, CHANGED, REMOVED, FIXED, EXTENDED, or OPTIMIZED", + "Does not dump commit subjects verbatim into the release-note file" + ] + }, + { + "id": 5, + "prompt": "We have an umbrella package that mostly bundles sibling packages. Preserve or add a References section only if the package shape justifies it, and do not invent package references that are not actually there.", + "expected_output": "The package release notes use References only when the package is a real umbrella/meta package or the file already carries that section, and the listed package IDs remain truthful.", + "expectations": [ + "Uses References only when the package is an umbrella/meta package or the existing file already carries that section", + "Keeps reference bullets as plain package IDs", + "Does not invent unsupported package references", + "Keeps the output grounded in git history plus actual project/package metadata" + ] + } + ] +} diff --git a/skills/git-nuget-release-notes/references/package-release-notes-format.md b/skills/git-nuget-release-notes/references/package-release-notes-format.md new file mode 100644 index 0000000..8638945 --- /dev/null +++ b/skills/git-nuget-release-notes/references/package-release-notes-format.md @@ -0,0 +1,93 @@ +# Package Release Notes Blueprint + +This reference captures the normalized `PackageReleaseNotes.txt` shape used across the linked codebelt repositories. + +## Core Shape + +Each file is a cumulative history ordered newest first. Each release block uses this normalized structure: + +```text +Version: 0.3.1 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +# Breaking Changes +- REMOVED ... + +# New Features +- ADDED ... + +# Improvements +- EXTENDED ... + +# Bug Fixes +- FIXED ... + +# References +- Package.One +- Package.Two +``` + +## Section Order + +Use sections in this order and omit empty ones: + +1. `# ALM` +2. `# Breaking Changes` +3. `# New Features` +4. `# Improvements` +5. `# Bug Fixes` +6. `# References` + +## Section Intent + +`# ALM` - Release-engineering and package-maintenance facts. - Typical bullets cover dependency upgrades, supported TFM additions, or TFM removals. - ALM-only releases are normal and should not be padded with weaker sections. + +`# Breaking Changes` - Consumer-visible incompatibilities. - Typical verbs: `REMOVED`, `RENAMED`, `MOVED`, `CHANGED`. + +`# New Features` - Additive API or capability work. - Typical verb: `ADDED`. + +`# Improvements` - Non-breaking enhancements and refinements. - Typical verbs: `CHANGED`, `EXTENDED`, `OPTIMIZED`, `DEPRECATED`, `REFACTORED`. + +`# Bug Fixes` - Corrections to incorrect prior behavior. - Typical verb: `FIXED`. + +`# References` - Plain package IDs only. - Use this only for umbrella/meta packages or when the repo already uses a references section for that package. + +## Wording Pattern + +- Start every bullet with an all-caps action verb. +- Follow the verb with the concrete subject: package, type, member, namespace, or behavior that changed. +- Prefer exact technical identifiers over vague prose. +- Avoid punctuation-heavy embellishment and avoid copying commit subjects verbatim. + +Examples: + +- `- ADDED AssemblyContext class in the Cuemon.Reflection namespace that provides filtered discovery of assemblies in the current application domain` +- `- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)` +- `- FIXED World class in the Cuemon.Globalization namespace where retrieving countries by code in GetStatisticalRegion was not included` + +## Availability Rendering + +Render frameworks in a human-readable list based on project order: + +- `net10.0` -> `.NET 10` +- `net9.0` -> `.NET 9` +- `net8.0` -> `.NET 8` +- `netstandard2.1` -> `.NET Standard 2.1` +- `netstandard2.0` -> `.NET Standard 2.0` +- `net48` -> `.NET Framework 4.8` + +Combine them with commas and `and`: + +- `.NET 10 and .NET 9` +- `.NET 10, .NET 9 and .NET Standard 2.0` + +## Historical Whitespace + +Some historical files contain odd spaces or inconsistent `Version` headers. Treat those as legacy formatting noise. + +- Normalize the block you are writing to `Version:` and `Availability:` +- Do not rewrite older blocks solely to clean up whitespace unless the user asked for a formatting pass +- Preserve older history below the new block to avoid unnecessary churn diff --git a/skills/git-visual-commits/SKILL.md b/skills/git-visual-commits/SKILL.md index b8ccb33..722ff8e 100644 --- a/skills/git-visual-commits/SKILL.md +++ b/skills/git-visual-commits/SKILL.md @@ -1,92 +1,100 @@ --- name: git-visual-commits -description: > - Structured git commit workflow with emoji prefixes and identity-aware - modes: `git bot commit`, regular `git commit`, and `git our commit`. - Use this skill whenever the user asks to commit changes, stage files, - write a commit message, or review what should be committed. Also use it - when the user says "commit this", "make a commit", "commit your - changes", "commit what you just did", "what should my commit message - be", "stage and commit", "git bot commit", "git our commit", or - combines a commit request with "yolo" or "auto". Treat commit wording - as an automatic trigger for this skill, not as a casual hint. Supports - auto-approval mode and enforces emoji plus lowercase prefixes, max 70 - chars, one logical change per commit, technology-aware grouping, and - post-commit identity verification. ---- - -# Git Visual Commits - -This skill drives the entire git commit workflow — reviewing changes, grouping them logically, composing messages with the right emoji and prefix, and running the commit. It supports three identity modes: bot-attributed (`git bot commit`), human-attributed (`git commit`), and collaborative (`git our commit`). - -## Critical Rules - -### Identity Lock - -- If the user asked for `git bot commit`, you must use `git bot commit`. -- If the user asked for `git commit`, you must use `git commit`. -- If the user asked for `git our commit`, follow the attribution workflow and then use the matching command per group. -- Never silently downgrade a requested `git bot commit` to `git commit`. -- If the required `git bot` alias is unavailable, halt and report that exact blocker instead of falling back to human identity. - -### Auto-Approval Guard - -`yolo` / `auto` skips user confirmation only. It never skips: - -- skill activation -- identity selection -- semantic grouping -- mixed-scope validation -- post-commit author verification - -### Post-Commit Verification - -After every commit, run: - -```bash -git log -1 --format="%an <%ae>" -``` - -Confirm that the author matches the requested identity mode. If the author is wrong, treat the commit as invalid and repair it before reporting success. - -Then verify the stored commit message body too: - -```bash -git log -1 --format=%B -``` - -If the body contains literal escape sequences such as `\n` instead of real line breaks, treat the commit message as invalid and repair it before reporting success. - -### Umbrella Commit Rejection - -Reject a single umbrella commit when the diff spans multiple intents such as: - -- skill instructions (`SKILL.md`, `FORMS.md`, `references/`, `evals/`) -- scaffold/template/runtime files (`assets/`, scaffold helper scripts) -- validation/tooling (`scripts/`, repo validators) -- repo docs or repo policy (`README.md`, `AGENTS.md`, `CONTRIBUTING.md`) - -`yolo`, small file count, or "the changes are related" are not valid reasons to collapse these into one commit. - -## Prerequisites - -The `git bot commit` command requires a one-time alias setup in your global git config. Run this once per machine: +description: > + Structured git commit workflow with emoji prefixes and identity-aware modes: `git bot commit`, regular `git commit`, and `git our commit`. Use this skill whenever the user asks to commit changes, stage files, write a commit message, or review what should be committed. Also use it when the user says "commit this", "make a commit", "commit your changes", "commit what you just did", "what should my commit message be", "stage and commit", "git bot commit", "git our commit", or combines a commit request with "yolo" or "auto". Treat commit wording as an automatic trigger for this skill, not as a casual hint. Supports auto-approval mode and enforces emoji plus lowercase prefixes, max 70 chars, one logical change per commit, technology-aware grouping, and post-commit identity verification. +--- + +# Git Visual Commits + +This skill drives the entire git commit workflow — reviewing changes, grouping them logically, composing messages with the right emoji and prefix, and running the commit. It supports three identity modes: bot-attributed (`git bot commit`), human-attributed (`git commit`), and collaborative (`git our commit`). + +## Critical Rules + +### Identity Lock + +- If the user asked for `git bot commit`, you must use `git bot commit`. +- If the user asked for `git commit`, you must use `git commit`. +- If the user asked for `git our commit`, follow the attribution workflow and then use the matching command per group. +- Never silently downgrade a requested `git bot commit` to `git commit`. +- If the required `git bot` alias is unavailable, halt and report that exact blocker instead of falling back to human identity. + +### Auto-Approval Guard + +`yolo` / `auto` skips user confirmation only. It never skips: + +- skill activation +- identity selection +- semantic grouping +- mixed-scope validation +- post-commit author verification + +### Default Scope Rule + +If the user says `git bot commit`, `git commit`, or `git our commit` without narrowing language, treat the request as covering the full current worktree. + +- The default scope is **all current changes visible in git status**. +- Your job is to group that full worktree into the right number of commits by semantic intent. +- Never silently narrow the scope to "just the files from the last thing I worked on", "just the files I touched", or "just the newest skill" unless the user explicitly said to do that. +- `yolo` keeps this same full-worktree default. It removes the approval wait; it does not narrow scope. + +Narrow scope only when the user explicitly does one of these: + +- names a specific path, file, module, project, or technology slice +- says `just`, `only`, `for this`, `for X`, `commit the README changes`, or equivalent limiting language +- asks for a review/plan for a subset before committing + +If the user did not narrow scope, do not invent a narrower scope on their behalf. + +### Post-Commit Verification + +After every commit, run: + +```bash +git log -1 --format="%an <%ae>" +``` + +Confirm that the author matches the requested identity mode. If the author is wrong, treat the commit as invalid and repair it before reporting success. + +Then verify the stored commit message body too: + +```bash +git log -1 --format=%B +``` + +If the body contains literal escape sequences such as `\n` instead of real line breaks, treat the commit message as invalid and repair it before reporting success. + +Also reject a stored short prose body when it was split across lines only to chase a 72-column habit. If a non-empty body line ends mid-sentence and the next non-empty line simply continues that same sentence, treat the commit message as invalid and repair it before reporting success. A single short paragraph should usually stay as one natural prose line; add manual line breaks only for real paragraphing, lists, quotes, or readability-driven separation. + +### Umbrella Commit Rejection + +Reject a single umbrella commit when the diff spans multiple intents such as: + +- skill instructions (`SKILL.md`, `FORMS.md`, `references/`, `evals/`) +- scaffold/template/runtime files (`assets/`, scaffold helper scripts) +- validation/tooling (`scripts/`, repo validators) +- repo docs or repo policy (`README.md`, `AGENTS.md`, `CONTRIBUTING.md`) + +`yolo`, small file count, or "the changes are related" are not valid reasons to collapse these into one commit. + +## Prerequisites + +The `git bot commit` command requires a one-time alias setup in your global git config. Run this once per machine: ```bash git config --global alias.bot '!git -c user.name="<bot-name>" -c user.email="<bot-email>"' ``` -Replace `<bot-name>` and `<bot-email>` with the identity you want AI-authored commits to appear under. - -Verify it works: +Replace `<bot-name>` and `<bot-email>` with the identity you want AI-authored commits to appear under. + +Verify it works: ```bash git bot commit --allow-empty -m "test bot identity" git log -1 --format="%an <%ae>" # should show bot name and email -git reset HEAD~1 # undo the test commit -``` - -If `git config --global --get alias.bot` returns nothing when the user asked for `git bot commit`, stop and report that the bot alias is missing. Do not proceed with `git commit` as a fallback. +git reset HEAD~1 # undo the test commit +``` + +If `git config --global --get alias.bot` returns nothing when the user asked for `git bot commit`, stop and report that the bot alias is missing. Do not proceed with `git commit` as a fallback. --- @@ -119,19 +127,19 @@ When the user says "our commit" (or similar), the agent attributes each commit t ``` 1. 🙈 add gitignore (👤 you) Files: .gitignore - 2. 🦾 init: add agent agreements (🤖 bot) - Files: AGENTS.md - 3. 🍱 add photo and hero image assets (👤 you) - Files: assets/dj-photo.jpg, assets/hero.png - ``` - The user confirms or adjusts the plan — they can override any attribution. -5. **Commit** each group with its assigned identity — no `Co-authored-by` trailer (GitHub's PR flow already tracks collaboration) + 2. 🦾 init: add agent agreements (🤖 bot) + Files: AGENTS.md + 3. 🍱 add photo and hero image assets (👤 you) + Files: assets/dj-photo.jpg, assets/hero.png + ``` + The user confirms or adjusts the plan — they can override any attribution. +5. **Commit** each group with its assigned identity — no `Co-authored-by` trailer (GitHub's PR flow already tracks collaboration) The commit message format, emoji conventions, grouping strategy, and everything else is **identical** for both. The profile is the only thing that changes. -Never add or modify git remotes. Never set `git user.name` or `git user.email` locally. - ---- +Never add or modify git remotes. Never set `git user.name` or `git user.email` locally. + +--- ## Commit Message Format @@ -141,30 +149,24 @@ Never add or modify git remotes. Never set `git user.name` or `git user.email` l <body> ``` -- **Emoji** comes first — picked from `references/commit-language.md` -- **Prefix** is lowercase (see `references/commit-language.md`) — **never use `feat:`** -- **Description** is lowercase, imperative, max 70 characters total (including emoji and prefix) -- **Body** is included by default — a short paragraph explaining *why* the change was made, not just *what* changed. Separate from the subject with a blank line. Do **not** hard-wrap commit bodies at 72 characters; keep short bodies as normal prose and add line breaks only when they improve readability. Can be suppressed with `no-body` (see below). -- One logical change per commit — don't bundle unrelated things - -### Prefix and Emoji Reference - -Read `references/commit-language.md` before choosing a prefix or emoji. -It contains the allowed prefixes, the gitmoji-first table, and the -extended emoji fallback guidance shared with -`git-visual-squash-summary`. -Keep that duplicated reference byte-for-byte aligned with the -`git-visual-squash-summary` copy; the validator and CI both enforce that -sync contract. - ---- +- **Emoji** comes first — picked from `references/commit-language.md` +- **Prefix** is lowercase (see `references/commit-language.md`) — **never use `feat:`** +- **Description** is lowercase, imperative, max 70 characters total (including emoji and prefix) +- **Body** is included by default — a short paragraph explaining *why* the change was made, not just *what* changed. Separate from the subject with a blank line. Do **not** hard-wrap commit bodies at 72 characters; keep short bodies as normal prose and add line breaks only when they improve readability. Can be suppressed with `no-body` (see below). +- **Body repair rule** — if verification shows the stored body was split mid-sentence just to fit an arbitrary width, amend the commit before reporting success. +- One logical change per commit — don't bundle unrelated things + +### Prefix and Emoji Reference + +Read `references/commit-language.md` before choosing a prefix or emoji. It contains the allowed prefixes, the gitmoji-first table, and the extended emoji fallback guidance shared with `git-visual-squash-summary`. Keep that duplicated reference byte-for-byte aligned with the `git-visual-squash-summary` copy; the validator and CI both enforce that sync contract. + +--- ## Auto-Approval Mode By default, the agent presents a commit plan and waits for user confirmation before staging and committing (Step 4). Auto-approval mode skips this wait — the plan is still displayed for transparency, but the agent proceeds immediately. -**What auto-approval skips:** user confirmation only. -**What auto-approval never skips:** classification (Step 2), grouping validation (Step 3), and the mixed-scope guard. These self-checks run unconditionally — they exist to catch bad groupings before they become commits, regardless of whether a human is reviewing the plan. +**What auto-approval skips:** user confirmation only. **What auto-approval never skips:** classification (Step 2), grouping validation (Step 3), and the mixed-scope guard. These self-checks run unconditionally — they exist to catch bad groupings before they become commits, regardless of whether a human is reviewing the plan. ### Per-request activation @@ -212,19 +214,23 @@ Say **"enable no-body mode"** or **"enable tmi mode"** to suppress commit bodies ### Step 1: Review changes -Run `git status` and `git diff` (and `git diff --staged` if there are staged changes) to understand what has changed. Don't commit blindly — understand what each file is doing before grouping. +Run `git status` and `git diff` (and `git diff --staged` if there are staged changes) to understand what has changed. + +Unless the user explicitly narrowed scope, inspect the **entire current worktree** and build the commit plan from that full set of changes. Do not default to the last task only. + +Don't commit blindly — understand what each file is doing before grouping. ### Step 2: Classify changes Before composing any commit message, bucket every changed file by its **semantic intent** — not just its file type. Read the actual diff for each file and ask: *"What is this change trying to accomplish?"* Two files of the same type (e.g. two test files) may have completely different intents and belong in separate commits. -Derive categories from the actual diff — don't assume a fixed set. Common categories include: - -- **New repo capabilities** — introducing a new repo-managed skill, workflow, or top-level capability -- **Existing skill refactors** — restructuring or extracting shared rules from an already existing skill -- **Project/solution files** — build system metadata that defines project structure -- **Preprocessor/build-only changes** — conditional compilation, build-target switches -- **Build/tooling** — CI workflows, container definitions, build scripts +Derive categories from the actual diff — don't assume a fixed set. Common categories include: + +- **New repo capabilities** — introducing a new repo-managed skill, workflow, or top-level capability +- **Existing skill refactors** — restructuring or extracting shared rules from an already existing skill +- **Project/solution files** — build system metadata that defines project structure +- **Preprocessor/build-only changes** — conditional compilation, build-target switches +- **Build/tooling** — CI workflows, container definitions, build scripts - **Environment/configuration** — test environment config, connection strings, runner settings, infra setup - **Source moves/renames** — renamed files, moved namespaces, updated imports - **Breaking removals** — removed public types, deleted forwarding attributes, dropped compatibility shims @@ -232,9 +238,9 @@ Derive categories from the actual diff — don't assume a fixed set. Common cate - **Application code** — new features, bug fixes, refactors, business logic - **Test logic** — changed assertions, updated expectations, new test cases, modified test behavior -**Critical distinction:** "Environment/configuration" and "Test logic" are separate categories even when both live under a test project. A test environment config file (`testenvironments.json`, `appsettings.test.json`) describes *how tests run*. A test assertion file describes *what tests verify*. These are different intents. - -**Repo-skill distinction:** Adding a brand-new skill folder is a **new repo capability**. Extracting shared wording, tightening an existing skill, or adding validator coverage for that skill is a different intent. Even when all of that work is related, do not collapse "new skill introduced" and "existing skill refactored" into one commit. +**Critical distinction:** "Environment/configuration" and "Test logic" are separate categories even when both live under a test project. A test environment config file (`testenvironments.json`, `appsettings.test.json`) describes *how tests run*. A test assertion file describes *what tests verify*. These are different intents. + +**Repo-skill distinction:** Adding a brand-new skill folder is a **new repo capability**. Extracting shared wording, tightening an existing skill, or adding validator coverage for that skill is a different intent. Even when all of that work is related, do not collapse "new skill introduced" and "existing skill refactored" into one commit. This classification drives grouping in Step 3. Files with different semantic intents almost never belong in the same commit. @@ -268,10 +274,10 @@ Common groupings: - Config/setup files together (app host, bootstrapping) - Environment and infrastructure config together (test runners, CI matrix, container settings) - New feature or module code together -- Data contracts, types, and interfaces together -- Database models, migrations, and schema changes together -- Test logic and assertions together (when they share the same rationale) -- Documentation and inline comments together +- Data contracts, types, and interfaces together +- Database models, migrations, and schema changes together +- Test logic and assertions together (when they share the same rationale) +- Documentation and inline comments together When in doubt, one commit per "thing that changes" is better than one big commit. @@ -281,24 +287,24 @@ After grouping, validate each proposed commit. If a single commit contains files This guard runs unconditionally — including in auto-approval mode. -#### Documentation separation rule - -Documentation files (`CHANGELOG.md`, `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, release notes) are **separate-by-default**. They only belong in the same commit as non-doc files when the commit is explicitly documentation-focused (e.g. `📝 docs: add api usage guide` where the docs are the point, not a side effect). - -#### Repo-aligned grouping example - -When a repo like this one mixes skill changes, scaffold assets, validators, and repo docs, split them by intent: - -- **New repo-managed skill** — a newly introduced `skills/<name>/` folder and its local `evals/` or `references/` -- **Existing skill refactor** — extracting shared rules, renaming sections, or reorganizing an existing skill -- **Skill contract files** — `SKILL.md`, `FORMS.md`, `references/`, `evals/` -- **Template/runtime files** — `assets/`, scaffold helper scripts -- **Validation/tooling** — validator scripts, repo checks -- **Repo docs/rules** — `README.md`, `AGENTS.md`, `CONTRIBUTING.md` - -Do not merge these into one commit unless the diff is truly single-purpose and the explanation still fits one sentence without using "and". - -If a commit both introduces a brand-new skill and refactors an existing skill to support it, prefer separate commits. "Related" is not enough — the repo history should make it obvious which commit added the capability and which commit reorganized existing behavior around it. +#### Documentation separation rule + +Documentation files (`CHANGELOG.md`, `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, release notes) are **separate-by-default**. They only belong in the same commit as non-doc files when the commit is explicitly documentation-focused (e.g. `📝 docs: add api usage guide` where the docs are the point, not a side effect). + +#### Repo-aligned grouping example + +When a repo like this one mixes skill changes, scaffold assets, validators, and repo docs, split them by intent: + +- **New repo-managed skill** — a newly introduced `skills/<name>/` folder and its local `evals/` or `references/` +- **Existing skill refactor** — extracting shared rules, renaming sections, or reorganizing an existing skill +- **Skill contract files** — `SKILL.md`, `FORMS.md`, `references/`, `evals/` +- **Template/runtime files** — `assets/`, scaffold helper scripts +- **Validation/tooling** — validator scripts, repo checks +- **Repo docs/rules** — `README.md`, `AGENTS.md`, `CONTRIBUTING.md` + +Do not merge these into one commit unless the diff is truly single-purpose and the explanation still fits one sentence without using "and". + +If a commit both introduces a brand-new skill and refactors an existing skill to support it, prefer separate commits. "Related" is not enough — the repo history should make it obvious which commit added the capability and which commit reorganized existing behavior around it. #### Rename vs removal distinction @@ -321,19 +327,21 @@ Before staging or committing anything, present the full commit plan to the user. Files: tests/Identity.Tests/ ``` -**If auto-approval is active** (via "yolo"/"auto" keyword or session-level setting), display a one-line summary and proceed immediately to Step 5: +**If auto-approval is active** (via "yolo"/"auto" keyword or session-level setting), display a one-line summary and proceed immediately to Step 5: + +``` +Auto-committing: 🔧 build config → 🚚 rename auth to identity → ✅ identity tests → 📝 update changelog +``` -``` -Auto-committing: 🔧 build config → 🚚 rename auth to identity → ✅ identity tests → 📝 update changelog -``` - -Even in auto-approval mode, surface the commit buckets explicitly before committing. Auto-approval removes the wait, not the planning step. +Even in auto-approval mode, surface the commit buckets explicitly before committing. Auto-approval removes the wait, not the planning step. -**Otherwise**, wait for the user to confirm or adjust. They may say things like: -- "Looks good" → proceed to stage and commit -- "Change #1 to ♻️" → swap the emoji and re-present -- "Merge 1 and 2 into one commit" → regroup and re-present -- "Use refactor: prefix on #1" → adjust and re-present +If the user did not narrow scope, the plan you surface must account for the full worktree rather than an arbitrarily chosen subset. + +**Otherwise**, wait for the user to confirm or adjust. They may say things like: +- "Looks good" → proceed to stage and commit +- "Change #1 to ♻️" → swap the emoji and re-present +- "Merge 1 and 2 into one commit" → regroup and re-present +- "Use refactor: prefix on #1" → adjust and re-present Only proceed to Step 5 after the user approves the plan. @@ -346,20 +354,22 @@ Before committing, validate each message against its file list: ### Step 5: Stage and commit each group -For each group: -1. `git add <specific files>` — be precise, don't use `git add .` unless everything belongs in one commit -2. Compose the commit message (see format above) +For each group: +1. `git add <specific files>` — be precise, don't use `git add .` unless everything belongs in one commit +2. Compose the commit message (see format above) 3. Run the appropriate commit command: - `git bot commit -m "<subject>"` — if the user asked the AI to commit (bot identity) - `git commit -m "<subject>"` — if the user asked to commit under their own identity - For `git our commit` — use whichever command matches the attribution the human chose - **With body:** use `-m "<subject>" -m "<body>"` to add the optional description paragraph - -When a commit body spans multiple lines, use real multiline input such as multiple `-m` arguments or a shell construct that preserves actual line breaks. Do not pass literal `\n` escape sequences and assume the shell will rewrite them. Prefer grammatical sentence and paragraph breaks over column-based hard wrapping. -### Step 6: Verify - -After committing, run `git log --oneline -5` to confirm the commit looks right. Then always run `git log -1 --format="%an <%ae>"` and verify that the author matches the requested identity mode before reporting success. Also run `git log -1 --format=%B` and verify the stored body contains readable prose with real line breaks, not literal escape sequences such as `\n`, and is not hard-wrapped mid-sentence just to satisfy a column limit. +When a commit body spans multiple lines, use real multiline input such as multiple `-m` arguments or a shell construct that preserves actual line breaks. Do not pass literal `\n` escape sequences and assume the shell will rewrite them. Prefer grammatical sentence and paragraph breaks over column-based hard wrapping. + +When the body is just one short explanatory paragraph, prefer a single natural prose line in the stored commit message. Do not press Enter mid-sentence to satisfy an arbitrary width target. + +### Step 6: Verify + +After committing, run `git log --oneline -5` to confirm the commit looks right. Then always run `git log -1 --format="%an <%ae>"` and verify that the author matches the requested identity mode before reporting success. Also run `git log -1 --format=%B` and verify the stored body contains readable prose with real line breaks, not literal escape sequences such as `\n`, and is not hard-wrapped mid-sentence just to satisfy a column limit. If that verification fails, amend the commit immediately instead of merely warning about it. --- @@ -377,9 +387,7 @@ With body (when context adds value): ``` 🚚 rename templates/ to assets/ per Anthropic skill conventions -Align with the official skill directory structure: SKILL.md, scripts/, -references/, and assets/. Updates all path references in SKILL.md, -reference docs, and AGENTS.md for both app and library skills. +Align with the official skill directory structure: SKILL.md, scripts/, references/, and assets/. Updates all path references in SKILL.md, reference docs, and AGENTS.md for both app and library skills. ``` ``` @@ -389,6 +397,13 @@ Replace inline parameter table with structured FORMS.md form definition. Step 1 now references FORMS.md instead of listing 12 fields inline. ``` +With body repair after a bad first attempt: +``` +📝 docs: add git release-note guidance + +Clarify when the repo should keep release-note docs separate from code changes so commit history stays easier to scan and review. +``` + ## Bad Examples (and why) ``` @@ -398,15 +413,23 @@ feat: add submission endpoint ← "feat:" is not an allowed prefix ⚙️ config: setup api ← "config:" is not an allowed prefix ``` +``` +📝 docs: add git release-note guidance + +Clarify when the repo should keep release-note docs separate +from code changes so commit history stays easier to scan and review. + ← bad wrap: short prose split mid-sentence for width only +``` + --- ## Branching (for reference) Branch format: `[version]/[description]` -Examples: -- `v1.0.0/mvp` — initial MVP -- `v1.1.0/validation` — adding validation -- `v1.2.0/admin-dashboard` — new feature area +Examples: +- `v1.0.0/mvp` — initial MVP +- `v1.1.0/validation` — adding validation +- `v1.2.0/admin-dashboard` — adding a new feature area Don't create, rename, or delete branches unless the user explicitly asks. diff --git a/skills/git-visual-commits/evals/evals.json b/skills/git-visual-commits/evals/evals.json index 79e6edb..79f135f 100644 --- a/skills/git-visual-commits/evals/evals.json +++ b/skills/git-visual-commits/evals/evals.json @@ -79,6 +79,28 @@ "Separates validator changes from skill contract changes when the rationale differs", "Keeps README or changelog updates in their own documentation-focused commit" ] + }, + { + "id": 8, + "prompt": "You already created a git bot commit, but `git log -1 --format=%B` shows the body split across short lines mid-sentence even though it is just a short prose paragraph. Repair the commit before reporting success.", + "expected_output": "A repaired bot-attributed commit whose stored body is rewritten as normal prose instead of arbitrary 72-column wrapping.", + "expectations": [ + "Treats a short body that is hard-wrapped mid-sentence as an invalid commit result", + "Amends or otherwise repairs the commit instead of merely warning about the bad wrapping", + "Preserves bot identity while repairing the stored commit message", + "Verifies the repaired stored body again with git log -1 --format=%B before success is reported" + ] + }, + { + "id": 9, + "prompt": "git bot commit yolo", + "expected_output": "An auto-approved bot commit flow that treats the full current worktree as the default scope and groups it into multiple commits when the changes span multiple intents.", + "expectations": [ + "Treats an unqualified git bot commit request as applying to the full current worktree", + "Does not silently narrow scope to only the most recently touched files or task slice", + "Groups the full worktree into multiple commits when semantic intent differs", + "Reserves scope narrowing for explicit user language such as just, only, for this, or named paths/modules" + ] } ] } diff --git a/skills/git-visual-commits/references/commit-language.md b/skills/git-visual-commits/references/commit-language.md index b5b7afd..b5248f1 100644 --- a/skills/git-visual-commits/references/commit-language.md +++ b/skills/git-visual-commits/references/commit-language.md @@ -1,9 +1,6 @@ ### Allowed Prefixes -Prefixes are **optional** — only include one when it adds clarity beyond -what the emoji already conveys. Many commits need no prefix at all (e.g. -`🚚 rename auth module to identity`, `➕ add validation library`). When you -do use a prefix, pick from this list: +Prefixes are **optional** — only include one when it adds clarity beyond what the emoji already conveys. Many commits need no prefix at all (e.g. `🚚 rename auth module to identity`, `➕ add validation library`). When you do use a prefix, pick from this list: | Prefix | Use When | |--------|----------| @@ -16,9 +13,7 @@ do use a prefix, pick from this list: ### Emoji Selection — Gitmoji First, Fallback Second -**Always prefer an official [gitmoji](https://gitmoji.dev) emoji** when -the semantic meaning is a good fit. Only use a non-gitmoji emoji when no -official entry matches well enough. +**Always prefer an official [gitmoji](https://gitmoji.dev) emoji** when the semantic meaning is a good fit. Only use a non-gitmoji emoji when no official entry matches well enough. #### Primary: Gitmoji @@ -90,10 +85,7 @@ official entry matches well enough. #### Fallback: Extended Emoji Reference -When no gitmoji entry fits, consult **[this curated extended -reference](https://gist.github.com/marcellodesales/aba1152a91d69f9b39745a08fd73a6f9)** -— a multi-source collection covering languages, platforms, cloud infra, -and programming strategies that gitmoji doesn't address. +When no gitmoji entry fits, consult **[this curated extended reference](https://gist.github.com/marcellodesales/aba1152a91d69f9b39745a08fd73a6f9)** — a multi-source collection covering languages, platforms, cloud infra, and programming strategies that gitmoji doesn't address. Key entries from that reference, by category: diff --git a/skills/git-visual-squash-summary/SKILL.md b/skills/git-visual-squash-summary/SKILL.md index e5642d8..f551556 100644 --- a/skills/git-visual-squash-summary/SKILL.md +++ b/skills/git-visual-squash-summary/SKILL.md @@ -1,49 +1,25 @@ --- name: git-visual-squash-summary description: > - Turn many commits into a curated grouped squash summary - compatible with the opinionated wording style of - git-visual-commits. Use this skill whenever the user asks to squash a - branch into a concise summary, write a squash-and-merge summary, - summarize a commit range or PR as grouped lines, clean up noisy commit - history, or asks for a curated summary without committing. - Treat phrases - like "squash summary", "squash commit message", "summarize this branch", - "turn these commits into one summary", "rewrite these 10+ commits", or - "draft the squash summary" as automatic triggers. This skill is - non-mutating: it inspects git history and diffs, then returns grouped - summary lines only. It preserves technical identifiers where possible, - groups by intent rather than chronology, merges overlapping commits, - drops low-signal noise, uses strong concrete verbs, favors readable - GitHub and terminal output, keeps every output line at or below 72 - characters, and does not invent unsupported changes or drift into - changelog wording. + Turn many commits into a curated grouped squash summary compatible with the opinionated wording style of git-visual-commits. Use this skill whenever the user asks to squash a branch into a concise summary, write a squash-and-merge summary, summarize a commit range or PR as grouped lines, clean up noisy commit history, or asks for a curated summary without committing. Treat phrases like "squash summary", "squash commit message", "summarize this branch", "turn these commits into one summary", "rewrite these 10+ commits", or "draft the squash summary" as automatic triggers. This skill is non-mutating: it inspects git history and diffs, then returns grouped summary lines only. It preserves technical identifiers where possible, groups by intent rather than chronology, merges overlapping commits, drops low-signal noise, uses strong concrete verbs, favors readable GitHub and terminal output, keeps every output line at or below 72 characters, and does not invent unsupported changes or drift into changelog wording. --- # Git Visual Squash Summary -This skill turns a stack of commits into a curated grouped summary -without touching the index, the worktree, or git history. It is the -wording companion to `git-visual-commits`: same opinionated emoji and -prefix language, but non-mutating and optimized for the grouped summary -shown beneath a PR title or in a squash-and-merge description field. +This skill turns a stack of commits into a curated grouped summary without touching the index, the worktree, or git history. It is the wording companion to `git-visual-commits`: same opinionated emoji and prefix language, but non-mutating and optimized for the grouped summary shown beneath a PR title or in a squash-and-merge description field. -This skill is non-mutating: it inspects history and diffs, then returns -grouped summary lines only. +This skill is non-mutating: it inspects history and diffs, then returns grouped summary lines only. ## Non-Negotiable Rules - Never stage, commit, amend, rebase, or otherwise mutate git state. - Read `references/commit-language.md` before choosing any emoji or prefix. -- Keep `references/commit-language.md` byte-for-byte aligned with the - `git-visual-commits` copy; the validator and CI both enforce that sync - contract. +- Keep `references/commit-language.md` byte-for-byte aligned with the `git-visual-commits` copy; the validator and CI both enforce that sync contract. - Preserve technical identifiers exactly where possible. - Group by intent, not chronology. - Retain only distinct high-signal change groups. - Merge repetition and overlapping commits into their parent group. -- Drop low-signal noise such as typo-only, fixup-only, and trivial follow-up - commits unless they materially change a retained group. +- Drop low-signal noise such as typo-only, fixup-only, and trivial follow-up commits unless they materially change a retained group. - Prefer strong concrete verbs and concise phrasing. - Favor readable GitHub and terminal output over cleverness. - Avoid vague filler such as "various improvements". @@ -58,12 +34,10 @@ grouped summary lines only. Use the most explicit source the user gave you: -- If the user provided a commit range, branch comparison, PR branch, or - base branch, use that. +- If the user provided a commit range, branch comparison, PR branch, or base branch, use that. - Otherwise, try the current branch against its upstream merge-base. - If no upstream is configured, try `main`, then `master`. -- If you still cannot determine a safe comparison point, stop and ask for - the range or base branch instead of guessing. +- If you still cannot determine a safe comparison point, stop and ask for the range or base branch instead of guessing. Helpful read-only commands: @@ -78,9 +52,7 @@ git merge-base HEAD master ### Step 2: Inspect the actual changes -Do not summarize from commit subjects alone when the range is noisy or -long. Inspect both history and net effect so the final message reflects -what actually changed. +Do not summarize from commit subjects alone when the range is noisy or long. Inspect both history and net effect so the final message reflects what actually changed. Helpful read-only commands: @@ -93,21 +65,16 @@ git diff <base>..HEAD ### Step 3: Collapse to semantic intent -Before drafting the summary, reduce the range into the smallest truthful -set of retained groups: +Before drafting the summary, reduce the range into the smallest truthful set of retained groups: - Collapse repeated fixups into the group they support. - Merge overlapping commits into the clearest final intent. - Prefer the net effect over the path taken to get there. -- Drop typo-only, whitespace-only, and other low-signal cleanup unless it - materially changes a retained group. -- Keep documentation-only work separate in your reasoning, but include it - only when it represents a meaningful unique change. -- Highlight distinct meaningful efforts instead of forcing one dominant - umbrella theme. +- Drop typo-only, whitespace-only, and other low-signal cleanup unless it materially changes a retained group. +- Keep documentation-only work separate in your reasoning, but include it only when it represents a meaningful unique change. +- Highlight distinct meaningful efforts instead of forcing one dominant umbrella theme. -Ask yourself: "If I had to explain the real work in 2-5 compact lines, -what are the distinct changes that mattered?" +Ask yourself: "If I had to explain the real work in 2-5 compact lines, what are the distinct changes that mattered?" ### Step 4: Draft the grouped summary @@ -124,20 +91,15 @@ Formatting rules: - Return grouped lines only. Do not prepend a title. - Use one line per retained high-signal group. - Keep every line at or below 72 characters. -- Use the shared prefix and emoji guidance in - `references/commit-language.md`. -- Do not add bullets, numbering, a body, rationale paragraph, or chronology - recap. -- Do not append weak glue like "with", "plus", or "and" just to force - several top-level intents into one line. +- Use the shared prefix and emoji guidance in `references/commit-language.md`. +- Do not add bullets, numbering, a body, rationale paragraph, or chronology recap. +- Do not append weak glue like "with", "plus", or "and" just to force several top-level intents into one line. - Favor clean lines that scan well in GitHub and terminal views. -- Condense to the real grouped effort without dropping important - identifiers. +- Condense to the real grouped effort without dropping important identifiers. ### Step 5: Return the grouped lines only -Output the finished grouped summary lines and stop. Do not run -`git commit`, `git bot commit`, `git add`, or any other mutating command. +Output the finished grouped summary lines and stop. Do not run `git commit`, `git bot commit`, `git add`, or any other mutating command. ## Good Output Characteristics diff --git a/skills/git-visual-squash-summary/references/commit-language.md b/skills/git-visual-squash-summary/references/commit-language.md index b5b7afd..b5248f1 100644 --- a/skills/git-visual-squash-summary/references/commit-language.md +++ b/skills/git-visual-squash-summary/references/commit-language.md @@ -1,9 +1,6 @@ ### Allowed Prefixes -Prefixes are **optional** — only include one when it adds clarity beyond -what the emoji already conveys. Many commits need no prefix at all (e.g. -`🚚 rename auth module to identity`, `➕ add validation library`). When you -do use a prefix, pick from this list: +Prefixes are **optional** — only include one when it adds clarity beyond what the emoji already conveys. Many commits need no prefix at all (e.g. `🚚 rename auth module to identity`, `➕ add validation library`). When you do use a prefix, pick from this list: | Prefix | Use When | |--------|----------| @@ -16,9 +13,7 @@ do use a prefix, pick from this list: ### Emoji Selection — Gitmoji First, Fallback Second -**Always prefer an official [gitmoji](https://gitmoji.dev) emoji** when -the semantic meaning is a good fit. Only use a non-gitmoji emoji when no -official entry matches well enough. +**Always prefer an official [gitmoji](https://gitmoji.dev) emoji** when the semantic meaning is a good fit. Only use a non-gitmoji emoji when no official entry matches well enough. #### Primary: Gitmoji @@ -90,10 +85,7 @@ official entry matches well enough. #### Fallback: Extended Emoji Reference -When no gitmoji entry fits, consult **[this curated extended -reference](https://gist.github.com/marcellodesales/aba1152a91d69f9b39745a08fd73a6f9)** -— a multi-source collection covering languages, platforms, cloud infra, -and programming strategies that gitmoji doesn't address. +When no gitmoji entry fits, consult **[this curated extended reference](https://gist.github.com/marcellodesales/aba1152a91d69f9b39745a08fd73a6f9)** — a multi-source collection covering languages, platforms, cloud infra, and programming strategies that gitmoji doesn't address. Key entries from that reference, by category: diff --git a/skills/skill-creator-agnostic/SKILL.md b/skills/skill-creator-agnostic/SKILL.md new file mode 100644 index 0000000..0e645e7 --- /dev/null +++ b/skills/skill-creator-agnostic/SKILL.md @@ -0,0 +1,179 @@ +--- +name: skill-creator-agnostic +description: > + Adds runner-agnostic guardrails on top of Anthropic's skill-creator for creating, modifying, and benchmarking skills across Codex, GitHub Copilot, Opus, and similar agents. Use whenever skill work must follow temp-workspace isolation, valid `iteration-N/eval-name/{config}/run-N/` benchmark layout, honest measured-vs-simulated labeling, UTF-8-safe artifact generation, and repo-managed skill sync/README update rules. Treat requests like "turn this workflow into a skill", "benchmark this skill", "compare with_skill and without_skill", "why is aggregate_benchmark.py showing zeros", or "make this skill robust across agents" as automatic triggers. +--- + +# Skill Creator Agnostic + +This skill is a thin overlay on Anthropic's `skill-creator`. It does not replace the upstream workflow; it adds cross-runner and repo-level guardrails so skill work stays reliable across Codex, Copilot, Opus, and similar agents. + +Before benchmarking, read `references/benchmark-contract.md`. + +On Windows or when running from PowerShell, also read `references/windows-powershell-benchmarking.md`. + +## Critical + +- Start from Anthropic's `skill-creator` workflow. Use this skill to add environment and repo guardrails, not to fork or replace the upstream skill. +- Do not edit third-party skills such as Anthropic's `skill-creator` to encode repo-specific behavior. Keep those rules in repo-managed files and companion skills instead. +- Do not assume any specific runner CLI exists. Choose the benchmark runner from what is actually available in the current environment. +- Keep all eval workspaces under a temp root such as `$env:TEMP/<skill-name>-workspace/`, never inside the source repo. +- For repo-managed skills, keep `skills/<name>/`, `~/.claude/skills/<name>/`, and `~/.agents/skills/<name>/` in sync before calling the work done. +- Every repo-managed skill must keep a per-skill `evals/evals.json`. +- Benchmark directories must follow `iteration-N/eval-name/{config}/run-N/` exactly; do not flatten files directly under `with_skill/` or `without_skill/`. +- `grading.json` must include both `expectations` and a populated `summary` object with `passed`, `failed`, `total`, and `pass_rate`. +- Generate `benchmark.json` through `skill-creator/scripts/aggregate_benchmark.py`; never hand-author it. +- Generate the human review artifact through `skill-creator/eval-viewer/generate_review.py`; do not build custom HTML when the upstream viewer already fits. +- Write JSON as UTF-8 without BOM so Python tooling can load it reliably. +- Distinguish benchmark modes explicitly: `MEASURED` for real model executions, `SIMULATED` for hand-authored or scripted expected outputs. Never present simulated outputs as measured. + +## Workflow + +### Step 1: Classify the skill task + +Decide which of these modes the user is asking for: + +- new skill creation +- existing skill modification +- skill benchmark repair/debugging +- benchmark interpretation or review + +Load Anthropic's `skill-creator` for the base workflow, then apply this overlay for cross-runner and repo-specific execution discipline. + +### Step 2: Inspect the local environment before choosing the runner + +Choose the benchmark execution path from actual available capabilities, not from memory or assumptions. + +- Check whether a callable agent runner is available. +- If one exists, prefer a real `MEASURED` benchmark. +- If no callable runner exists, you may still validate the pipeline with a `SIMULATED` benchmark, but label it clearly as such. +- Explain the chosen mode up front whenever the distinction matters to the user. + +Do not frame the workflow around one vendor-specific CLI unless that CLI is actually present. + +### Step 3: Set up the benchmark workspace + +Create the workspace under temp and keep it isolated from the real repo. + +- Use a short path such as `$env:TEMP/<skill-name>-workspace/`. +- Put fixture repos, test branches, transcripts, and benchmark outputs there. +- Never commit workspace artifacts back into the source repository unless the user explicitly asked for checked-in examples or harnesses. + +### Step 4: Build the eval contract before running anything + +Read or create the per-skill `evals/evals.json`, then ensure each eval has a corresponding workspace shape: + +```text +iteration-N/ + eval-1-name/ + eval_metadata.json + with_skill/ + run-1/ + grading.json + timing.json + outputs/ + without_skill/ + run-1/ + grading.json + timing.json + outputs/ +``` + +Keep `eval_metadata.json` at the eval-directory level. Put run artifacts under `run-N/` so `aggregate_benchmark.py` can discover them. + +### Step 5: Run paired benchmarks + +Run each eval in paired configurations: + +- `with_skill`: the skill under test is active +- `without_skill`: baseline with no skill for new skills, or a previous/ original version for existing skills + +For `MEASURED` runs: + +- save the real outputs +- save transcripts or command logs when available +- keep timings and token counts tied to the actual run + +For `SIMULATED` runs: + +- write clearly labeled expected outputs +- use them only to validate layout, grading, aggregation, and viewer integration +- never claim the result measures model quality + +### Step 6: Grade each run deterministically when possible + +Prefer scripts or direct file/diff checks over impressionistic grading. + +Each `grading.json` must minimally look like this: + +```json +{ + "expectations": [ + { + "text": "Uses iteration-N/eval-name/{config}/run-N/ layout", + "passed": true, + "evidence": "Found run-1/grading.json and run-1/timing.json" + } + ], + "summary": { + "passed": 1, + "failed": 0, + "total": 1, + "pass_rate": 1.0 + } +} +``` + +If `summary` is missing or empty, the aggregation output is not trustworthy. + +### Step 7: Aggregate and generate the review artifacts + +After the paired runs are graded: + +1. Resolve the installed Anthropic `skill-creator` root first, usually under `~/.agents/skills/skill-creator/` or `~/.claude/skills/skill-creator/`. +2. Run `scripts/aggregate_benchmark.py` from that resolved `skill-creator` root. +3. Verify that the generated `benchmark.json` contains discovered runs and a non-empty `run_summary`. +4. Run `eval-viewer/generate_review.py` from that same resolved `skill-creator` root to create the human review artifact. + +If the viewer shows outputs but the benchmark metrics are zero, suspect run layout or `grading.json.summary` before blaming the viewer. + +### Step 8: Interpret results honestly + +Summarize benchmark outcomes with plain language: + +- pass-rate delta +- time and token tradeoffs +- whether the benchmark is `MEASURED` or `SIMULATED` +- which assertions are discriminating versus weak/non-discriminating + +Call out benchmark limitations directly. For example: + +- fixture gaps that leave an assertion only partially tested +- synthetic outputs used for pipeline validation +- missing transcripts or token counts in a measured run + +### Step 9: Finish repo-managed skill work cleanly + +For repo-managed skills: + +- sync changed skill files across the repo copy, `~/.claude`, and `~/.agents` +- update `README.md` +- run `scripts/validate-skill-templates.ps1` +- keep benchmark artifacts in temp unless the user explicitly wants them checked in + +## Good Output Characteristics + +- Treats Anthropic's `skill-creator` as the base workflow and this skill as the overlay. +- Talks about available runner capability instead of assuming one product-specific CLI. +- Resolves the installed `skill-creator` path before calling benchmark scripts or the review viewer. +- Produces valid benchmark artifacts that `aggregate_benchmark.py` and `generate_review.py` consume without repair work. +- Labels synthetic benchmarks as `SIMULATED` and live executions as `MEASURED`. +- Explains why a benchmark failed in terms of layout, grading schema, encoding, or environment reality instead of hand-waving. + +## Bad Output Characteristics + +- Presenting hand-authored outputs as if they were independent model runs. +- Hand-writing `benchmark.json` instead of generating it. +- Flattening files directly under `with_skill/` or `without_skill/`. +- Saying "use the Claude CLI" or any other vendor tool when the environment has not shown that capability. +- Treating a viewer with qualitative outputs as proof that the numeric benchmark is valid. diff --git a/skills/skill-creator-agnostic/evals/evals.json b/skills/skill-creator-agnostic/evals/evals.json new file mode 100644 index 0000000..6138005 --- /dev/null +++ b/skills/skill-creator-agnostic/evals/evals.json @@ -0,0 +1,62 @@ +{ + "skill_name": "skill-creator-agnostic", + "evals": [ + { + "id": 1, + "prompt": "We are adding a new repo-managed skill. Give me the benchmark plan and artifact contract so I can compare with_skill and without_skill from a temp workspace.", + "expected_output": "The response keeps the benchmark in temp, preserves Anthropic skill-creator as the base workflow, and requires aggregate_benchmark.py plus generate_review.py artifacts.", + "expectations": [ + "Treats Anthropic skill-creator as the base workflow rather than replacing it", + "Requires a temp workspace outside the source repo", + "Uses paired with_skill and without_skill configurations", + "Requires benchmark.json to be generated by aggregate_benchmark.py", + "Requires the review artifact to come from generate_review.py" + ] + }, + { + "id": 2, + "prompt": "aggregate_benchmark.py keeps showing zero runs even though review.html has outputs. Diagnose the likely benchmark mistake.", + "expected_output": "The response identifies the run-N workspace layout and grading summary contract as the first things to inspect.", + "expectations": [ + "Identifies eval-N/<config>/run-N/ as the required layout instead of flattening files under the config directory", + "Identifies grading.json summary as required for meaningful aggregation", + "Distinguishes a viewer showing outputs from a valid numeric benchmark", + "Avoids blaming the viewer before checking workspace layout and grading data" + ] + }, + { + "id": 3, + "prompt": "We are on Windows PowerShell and Python keeps rejecting the JSON benchmark files. Tell me the likely artifact problem and how to prevent it.", + "expected_output": "The response points to UTF-8 without BOM and other PowerShell-specific benchmark hygiene issues.", + "expectations": [ + "Calls out UTF-8 without BOM as the safe JSON encoding", + "Avoids relying on Set-Content or shell defaults without qualification", + "Mentions at least one other PowerShell-specific benchmark pitfall such as provider path resolution or stable .Count handling", + "Keeps the advice grounded in benchmark artifact generation rather than general shell trivia" + ] + }, + { + "id": 4, + "prompt": "There is no dedicated Anthropic CLI in this environment. Keep the skill benchmark runner-agnostic and tell me what counts as measured versus simulated.", + "expected_output": "The response does not require a vendor-specific CLI, prefers measured runs when a callable runner exists, and labels simulated runs honestly.", + "expectations": [ + "Does not require a specific vendor CLI as a precondition", + "Chooses the runner from actual available environment capability", + "Prefers measured runs when a callable runner exists", + "Allows simulated runs only when labeled honestly", + "Never presents simulated outputs as measured" + ] + }, + { + "id": 5, + "prompt": "We already have Anthropic skill-creator. Should we replace it, edit it, or layer our own repo rules on top?", + "expected_output": "The response recommends layering repo-managed guardrails on top of Anthropic skill-creator rather than forking or editing the third-party skill.", + "expectations": [ + "Recommends a thin overlay instead of replacing Anthropic skill-creator", + "Avoids editing third-party skill files for repo-specific behavior", + "Keeps repo-managed sync and README update expectations in scope for first-party skills", + "Frames the new skill as cross-runner guidance rather than a single-runner fork" + ] + } + ] +} diff --git a/skills/skill-creator-agnostic/references/benchmark-contract.md b/skills/skill-creator-agnostic/references/benchmark-contract.md new file mode 100644 index 0000000..9d05c05 --- /dev/null +++ b/skills/skill-creator-agnostic/references/benchmark-contract.md @@ -0,0 +1,152 @@ +# Benchmark Contract + +Use this reference whenever a skill benchmark must be reproducible across different agents or runtimes. + +## Required Workspace Layout + +```text +iteration-N/ + eval-1-name/ + eval_metadata.json + with_skill/ + run-1/ + grading.json + timing.json + outputs/ + without_skill/ + run-1/ + grading.json + timing.json + outputs/ +``` + +Key rules: + +- `aggregate_benchmark.py` walks `run-*` directories. If files live directly under `with_skill/` or `without_skill/`, the benchmark will discover zero runs. +- `eval_metadata.json` belongs at the `eval-*` directory level, not inside each run directory. +- `outputs/` may contain files, diffs, transcripts, or other evidence the reviewer should inspect. + +## Required Files + +### eval_metadata.json + +Minimum contract: + +```json +{ + "eval_id": 1, + "eval_name": "descriptive-name", + "prompt": "User-style prompt under test", + "assertions": [ + "Expectation one", + "Expectation two" + ] +} +``` + +### grading.json + +Minimum contract: + +```json +{ + "expectations": [ + { + "text": "Expectation one", + "passed": true, + "evidence": "Why it passed" + } + ], + "summary": { + "passed": 1, + "failed": 0, + "total": 1, + "pass_rate": 1.0 + } +} +``` + +Important: + +- `expectations[].text`, `expectations[].passed`, and `expectations[].evidence` should be present for every assertion. +- `summary` is required for meaningful aggregation. Without it, `aggregate_benchmark.py` falls back to zeros even if qualitative output exists. + +### timing.json + +Minimum contract: + +```json +{ + "total_duration_seconds": 12.3, + "total_tokens": 4567, + "duration_ms": 12300 +} +``` + +Use real numbers for `MEASURED` runs. For `SIMULATED` runs, either omit unsupported fields or provide clearly synthetic values and document that they are synthetic. + +## Generated Files + +These must be produced by the Anthropic tooling, not authored manually: + +- `benchmark.json` from `scripts/aggregate_benchmark.py` +- `benchmark.md` from `scripts/aggregate_benchmark.py` +- review HTML or served viewer output from `eval-viewer/generate_review.py` + +If `benchmark.json` was hand-written, the benchmark is not trustworthy as an aggregation result. + +## Benchmark Modes + +### MEASURED + +Use `MEASURED` when a callable runner can actually execute paired `with_skill` and `without_skill` runs. + +Expected properties: + +- real outputs +- real timings +- real token counts when available +- real transcripts or command logs when available + +This is the preferred benchmark mode when the environment supports it. + +### SIMULATED + +Use `SIMULATED` only when the environment cannot perform real paired agent executions or when you are validating the benchmark pipeline itself. + +Expected properties: + +- hand-authored or scripted expected outputs +- explicit `SIMULATED` labeling in logs and summary +- clear statement that the result validates pipeline correctness, not model superiority + +Never present `SIMULATED` outputs as if they were independently generated model runs. + +## Aggregation and Review Commands + +Typical flow: + +```powershell +$skillCreatorRoot = @( + (Join-Path $HOME ".agents/skills/skill-creator"), + (Join-Path $HOME ".claude/skills/skill-creator") +) | Where-Object { Test-Path $_ } | Select-Object -First 1 + +if (-not $skillCreatorRoot) { + throw "Install Anthropic's skill-creator before generating benchmark artifacts." +} +``` + +```powershell +python (Join-Path $skillCreatorRoot "scripts/aggregate_benchmark.py") ` + "$workspace/iteration-1" --skill-name "<skill-name>" +``` + +```powershell +python (Join-Path $skillCreatorRoot "eval-viewer/generate_review.py") ` + "$workspace/iteration-1" --skill-name "<skill-name>" ` + --benchmark "$workspace/iteration-1/benchmark.json" ` + --static "$workspace/review.html" +``` + +If the viewer renders outputs but the benchmark delta is zero or the run list is empty, inspect the workspace layout and `grading.json.summary` before anything else. diff --git a/skills/skill-creator-agnostic/references/windows-powershell-benchmarking.md b/skills/skill-creator-agnostic/references/windows-powershell-benchmarking.md new file mode 100644 index 0000000..8e671e6 --- /dev/null +++ b/skills/skill-creator-agnostic/references/windows-powershell-benchmarking.md @@ -0,0 +1,57 @@ +# Windows and PowerShell Benchmarking Notes + +Use this reference when building or repairing skill benchmarks on Windows, especially from PowerShell. + +## UTF-8 Without BOM + +Python JSON loaders and the Anthropic benchmark scripts expect normal UTF-8 text. PowerShell defaults are not always safe for that. + +Prefer explicit writes such as: + +```powershell +$utf8NoBom = [System.Text.UTF8Encoding]::new($false) +[System.IO.File]::WriteAllText($path, $json, $utf8NoBom) +``` + +Do not assume `Set-Content`, redirection, or the shell default encoding will produce no-BOM UTF-8 on every machine or shell version. + +## Count Pipeline Results Safely + +When using `Where-Object` followed by `.Count`, wrap the pipeline in `@(...)` so the count is stable for zero, one, or many results. + +```powershell +$passed = @($items | Where-Object { $_.passed }).Count +``` + +## Resolve Provider Paths Before .NET File APIs + +If you feed PowerShell provider paths directly into .NET file APIs, normalize them first: + +```powershell +$resolved = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path) +``` + +That avoids surprises when the working directory or provider path is not what you think it is. + +## Treat Native stderr Carefully + +Some CLIs write warnings to stderr even when the exit code is zero. + +- Capture the actual exit code. +- Do not assume "stderr means failure". +- If needed, invoke through a wrapper that preserves stdout/stderr and exposes the real process exit code. + +## Keep Temp Paths Short + +Deep temp paths plus nested benchmark folders can hit Windows path limits. Use short workspace names such as: + +```powershell +$workspace = Join-Path $env:TEMP 'skill-creator-agnostic-workspace' +``` + +## Common Failure Symptoms + +- `aggregate_benchmark.py` shows zero runs: check `run-N/` layout first. +- `aggregate_benchmark.py` loads runs but reports zero pass rate: check `grading.json.summary`. +- Python throws JSON decode errors on otherwise normal files: suspect BOM or wrong encoding. +- The viewer shows outputs but the benchmark panel is empty: suspect aggregation inputs, not the viewer. diff --git a/skills/trunk-first-repo/SKILL.md b/skills/trunk-first-repo/SKILL.md index 35c8bf7..e6601dd 100644 --- a/skills/trunk-first-repo/SKILL.md +++ b/skills/trunk-first-repo/SKILL.md @@ -1,13 +1,7 @@ --- name: trunk-first-repo description: > - Initialize a folder as a git repository following scaled trunk-based development. - Sets up an empty main branch (seed commit only), creates a versioned feature branch, - and enforces a PR-first workflow where content only reaches main through pull requests. - Use this skill when the user wants to initialize a git repo, set up a new repository, - start a project with proper git workflow, or mentions "trunk-based", "PR workflow", - "branch protection", "git init", or wants to follow GitHub PR best practices. - ALWAYS use this skill when asked to initialize or set up a git repository. + Initialize a folder as a git repository following scaled trunk-based development. Sets up an empty main branch (seed commit only), creates a versioned feature branch, and enforces a PR-first workflow where content only reaches main through pull requests. Use this skill when the user wants to initialize a git repo, set up a new repository, start a project with proper git workflow, or mentions "trunk-based", "PR workflow", "branch protection", "git init", or wants to follow GitHub PR best practices. ALWAYS use this skill when asked to initialize or set up a git repository. --- # Trunk-First Repo @@ -54,8 +48,9 @@ git remote add origin {REMOTE_URL} git push -u origin main ``` -If skipped, remind the user they can add it later: -> When you're ready, run: `git remote add origin <url>` followed by `git push -u origin main` +If skipped, remind the user they can add it later: + +> When you're ready, run: `git remote add origin <url>` followed by `git push -u origin main` ### Step 4: Summary