KS
Killer-Skills

dotnet-cli-release-pipeline — Categories.community

v1.0.0
GitHub

About this Skill

Perfect for .NET Development Agents needing streamlined release pipeline management with GitHub Actions and SemVer versioning Distribution packages for dotnet-agent-harness — per-platform zip bundles and OpenCode npm plugin for comprehensive .NET development guidance

rudironsoni rudironsoni
[0]
[0]
Updated: 2/27/2026

Quality Score

Top 5%
45
Excellent
Based on code quality & docs
Installation
SYS Universal Install (Auto-Detect)
Cursor IDE Windsurf IDE VS Code IDE
> npx killer-skills add rudironsoni/dotnet-harness-plugin/dotnet-cli-release-pipeline

Agent Capability Analysis

The dotnet-cli-release-pipeline MCP Server by rudironsoni is an open-source Categories.community integration for Claude and other AI agents, enabling seamless task automation and capability expansion.

Ideal Agent Persona

Perfect for .NET Development Agents needing streamlined release pipeline management with GitHub Actions and SemVer versioning

Core Value

Empowers agents to automate .NET CLI tool releases with unified CI/CD pipelines, producing distribution formats like per-platform zip bundles and OpenCode npm plugins, while utilizing Runtime Identifier (RID) build matrices and GitHub Releases with SHA-256 checksums

Capabilities Granted for dotnet-cli-release-pipeline MCP Server

Automating .NET CLI tool releases across multiple platforms
Generating Homebrew formulas and winget manifests for seamless package distribution
Managing SemVer versioning strategies with git tags for consistent version control

! Prerequisites & Limits

  • Requires .NET 8.0+ baseline
  • Limited to GitHub Actions workflow syntax v2
  • Dependent on GitHub Releases for distribution
Project
SKILL.md
17.2 KB
.cursorrules
1.2 KB
package.json
240 B
Ready
UTF-8

# Tags

[No tags]
SKILL.md
Readonly

dotnet-cli-release-pipeline

Unified release CI/CD pipeline for .NET CLI tools: GitHub Actions workflow producing all distribution formats from a single version tag trigger, build matrix per Runtime Identifier (RID), artifact staging between jobs, GitHub Releases with SHA-256 checksums, automated Homebrew formula and winget manifest PR creation, and SemVer versioning strategy with git tags.

Version assumptions: .NET 8.0+ baseline. GitHub Actions workflow syntax v2. Patterns apply to any CI system but examples use GitHub Actions.

Scope

  • Tag-triggered GitHub Actions release workflow
  • Build matrix per Runtime Identifier (RID)
  • Artifact staging between CI jobs
  • GitHub Releases with SHA-256 checksums
  • Automated Homebrew formula and winget manifest PR creation
  • SemVer versioning with git tags

Out of scope

  • General CI/CD patterns (branch strategies, matrix testing) -- see [skill:dotnet-gha-patterns] and [skill:dotnet-ado-patterns]
  • Native AOT compilation configuration -- see [skill:dotnet-native-aot]
  • Distribution strategy decisions -- see [skill:dotnet-cli-distribution]
  • Package format details -- see [skill:dotnet-cli-packaging]
  • Container image publishing -- see [skill:dotnet-containers]

Cross-references: [skill:dotnet-cli-distribution] for RID matrix and publish strategy, [skill:dotnet-cli-packaging] for package format authoring, [skill:dotnet-native-aot] for AOT publish configuration, [skill:dotnet-containers] for container-based distribution.


Versioning Strategy

SemVer + Git Tags

Use Semantic Versioning (SemVer) with git tags as the single source of truth for release versions.

Tag format: v{major}.{minor}.{patch} (e.g., v1.2.3)

bash
1 2# Tag a release 3git tag -a v1.2.3 -m "Release v1.2.3" 4git push origin v1.2.3 5 6```bash 7 8### Version Flow 9 10```text 11 12git tag v1.2.3 131415GitHub Actions trigger (on push tags: v*) 161718Extract version from tag: GITHUB_REF_NAME → v1.2.3 → 1.2.3 192021Pass to dotnet publish /p:Version=1.2.3 222324Embed in binary (--version output) 252627Stamp in package manifests (Homebrew, winget, Scoop, NuGet) 28 29```text 30 31### Extracting Version from Tag 32 33```yaml 34 35- name: Extract version from tag 36 id: version 37 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 38 # v1.2.3 → 1.2.3 39 40```text 41 42### Pre-release Versions 43 44```bash 45 46# Pre-release tag 47git tag -a v1.3.0-rc.1 -m "Release candidate 1" 48 49# CI detects pre-release and skips package manager submissions 50# but still creates GitHub Release as pre-release 51 52```text 53 54--- 55 56## Unified GitHub Actions Workflow 57 58### Complete Workflow 59 60```yaml 61 62name: Release 63 64on: 65 push: 66 tags: 67 - 'v[0-9]+.[0-9]+.[0-9]+*' # v1.2.3, v1.2.3-rc.1 68 69permissions: 70 contents: write # Create GitHub Releases 71 72defaults: 73 run: 74 shell: bash 75 76env: 77 PROJECT: src/MyCli/MyCli.csproj 78 DOTNET_VERSION: '8.0.x' 79 80jobs: 81 build: 82 strategy: 83 matrix: 84 include: 85 - rid: linux-x64 86 os: ubuntu-latest 87 - rid: linux-arm64 88 os: ubuntu-latest 89 - rid: osx-arm64 90 os: macos-latest 91 - rid: win-x64 92 os: windows-latest 93 runs-on: ${{ matrix.os }} 94 steps: 95 - uses: actions/checkout@v4 96 97 - uses: actions/setup-dotnet@v4 98 with: 99 dotnet-version: ${{ env.DOTNET_VERSION }} 100 101 - name: Extract version 102 id: version 103 shell: bash 104 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 105 106 - name: Publish 107 run: >- 108 dotnet publish ${{ env.PROJECT }} -c Release -r ${{ matrix.rid }} -o ./publish /p:Version=${{ 109 steps.version.outputs.version }} 110 111 - name: Package (Unix) 112 if: runner.os != 'Windows' 113 run: | 114 set -euo pipefail 115 cd publish 116 tar -czf "$GITHUB_WORKSPACE/mytool-${{ steps.version.outputs.version }}-${{ matrix.rid }}.tar.gz" . 117 118 - name: Package (Windows) 119 if: runner.os == 'Windows' 120 shell: pwsh 121 run: | 122 Compress-Archive -Path "publish/*" ` 123 -DestinationPath "mytool-${{ steps.version.outputs.version }}-${{ matrix.rid }}.zip" 124 125 - name: Upload artifact 126 uses: actions/upload-artifact@v4 127 with: 128 name: release-${{ matrix.rid }} 129 path: | 130 *.tar.gz 131 *.zip 132 133 release: 134 needs: build 135 runs-on: ubuntu-latest 136 steps: 137 - name: Extract version 138 id: version 139 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 140 141 - name: Download all artifacts 142 uses: actions/download-artifact@v4 143 with: 144 path: artifacts 145 merge-multiple: true 146 147 - name: Generate checksums 148 working-directory: artifacts 149 run: | 150 set -euo pipefail 151 shasum -a 256 *.tar.gz *.zip > checksums-sha256.txt 152 cat checksums-sha256.txt 153 154 - name: Detect pre-release 155 id: prerelease 156 run: | 157 set -euo pipefail 158 if [[ "${{ steps.version.outputs.version }}" == *-* ]]; then 159 echo "is_prerelease=true" >> "$GITHUB_OUTPUT" 160 else 161 echo "is_prerelease=false" >> "$GITHUB_OUTPUT" 162 fi 163 164 # Pin third-party actions to a commit SHA in production for supply-chain security 165 - name: Create GitHub Release 166 uses: softprops/action-gh-release@v2 167 with: 168 name: v${{ steps.version.outputs.version }} 169 prerelease: ${{ steps.prerelease.outputs.is_prerelease }} 170 generate_release_notes: true 171 files: | 172 artifacts/*.tar.gz 173 artifacts/*.zip 174 artifacts/checksums-sha256.txt 175 176 publish-nuget: 177 needs: release 178 if: ${{ !contains(github.ref_name, '-') }} # Skip pre-releases 179 runs-on: ubuntu-latest 180 steps: 181 - uses: actions/checkout@v4 182 183 - uses: actions/setup-dotnet@v4 184 with: 185 dotnet-version: ${{ env.DOTNET_VERSION }} 186 187 - name: Extract version 188 id: version 189 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 190 191 - name: Pack 192 run: >- 193 dotnet pack ${{ env.PROJECT }} -c Release /p:Version=${{ steps.version.outputs.version }} -o ./nupkgs 194 195 - name: Push to NuGet 196 run: >- 197 dotnet nuget push ./nupkgs/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ 198 secrets.NUGET_API_KEY }} 199 200```json 201 202--- 203 204## Build Matrix per RID 205 206### Matrix Strategy 207 208The build matrix produces one artifact per RID. Each RID runs on the appropriate runner OS. 209 210```yaml 211 212strategy: 213 matrix: 214 include: 215 - rid: linux-x64 216 os: ubuntu-latest 217 - rid: linux-arm64 218 os: ubuntu-latest # Cross-compile ARM64 on x64 runner 219 - rid: osx-arm64 220 os: macos-latest # Native ARM64 runner 221 - rid: win-x64 222 os: windows-latest 223 224```text 225 226### Cross-Compilation Notes 227 228- **linux-arm64 on ubuntu-latest:** .NET supports cross-compilation for managed (non-AOT) builds. 229 `dotnet publish -r linux-arm64` on an x64 runner produces a valid ARM64 binary without QEMU. For Native AOT, 230 cross-compiling ARM64 on an x64 runner requires the ARM64 cross-compilation toolchain (`gcc-aarch64-linux-gnu` or 231 equivalent). See [skill:dotnet-native-aot] for cross-compile prerequisites. 232- **osx-arm64:** Use `macos-latest` (which provides ARM64 runners) for native compilation. Cross-compiling macOS ARM64 233 from Linux is not supported. 234- **win-x64 on windows-latest:** Native compilation on Windows runner. 235 236### Extended Matrix (Optional) 237 238```yaml 239 240strategy: 241 matrix: 242 include: 243 # Primary targets 244 - rid: linux-x64 245 os: ubuntu-latest 246 - rid: linux-arm64 247 os: ubuntu-latest 248 - rid: osx-arm64 249 os: macos-latest 250 - rid: win-x64 251 os: windows-latest 252 # Extended targets 253 - rid: osx-x64 254 os: macos-13 # Intel macOS runner 255 - rid: linux-musl-x64 256 os: ubuntu-latest # Alpine musl cross-compile 257 258```text 259 260--- 261 262## Artifact Staging 263 264### Upload Per-RID Artifacts 265 266Each matrix job uploads its artifact with a RID-specific name: 267 268```yaml 269 270- name: Upload artifact 271 uses: actions/upload-artifact@v4 272 with: 273 name: release-${{ matrix.rid }} 274 path: | 275 *.tar.gz 276 *.zip 277 retention-days: 1 # Short retention -- artifacts are published to GitHub Releases 278 279```text 280 281### Download in Release Job 282 283The release job downloads all artifacts from the build matrix: 284 285```yaml 286 287- name: Download all artifacts 288 uses: actions/download-artifact@v4 289 with: 290 path: artifacts 291 merge-multiple: true # Merge all release-* artifacts into one directory 292 293```text 294 295After download, `artifacts/` contains: 296 297```text 298 299artifacts/ 300 mytool-1.2.3-linux-x64.tar.gz 301 mytool-1.2.3-linux-arm64.tar.gz 302 mytool-1.2.3-osx-arm64.tar.gz 303 mytool-1.2.3-win-x64.zip 304 305```text 306 307--- 308 309## GitHub Releases with Checksums 310 311### Checksum Generation 312 313```yaml 314 315- name: Generate checksums 316 working-directory: artifacts 317 run: | 318 set -euo pipefail 319 shasum -a 256 *.tar.gz *.zip > checksums-sha256.txt 320 cat checksums-sha256.txt 321 322```text 323 324**Output format (checksums-sha256.txt):** 325 326```text 327 328abc123... mytool-1.2.3-linux-x64.tar.gz 329def456... mytool-1.2.3-linux-arm64.tar.gz 330ghi789... mytool-1.2.3-osx-arm64.tar.gz 331jkl012... mytool-1.2.3-win-x64.zip 332 333```text 334 335### Creating the Release 336 337```yaml 338 339- name: Create GitHub Release 340 uses: softprops/action-gh-release@v2 341 with: 342 name: v${{ steps.version.outputs.version }} 343 prerelease: ${{ steps.prerelease.outputs.is_prerelease }} 344 generate_release_notes: true 345 files: | 346 artifacts/*.tar.gz 347 artifacts/*.zip 348 artifacts/checksums-sha256.txt 349 350```text 351 352`generate_release_notes: true` auto-generates release notes from merged PRs and commit messages since the last tag. 353 354--- 355 356## Automated Formula/Manifest PR Creation 357 358### Homebrew Formula Update 359 360After the GitHub Release is published, update the Homebrew tap automatically: 361 362```yaml 363 364update-homebrew: 365 needs: release 366 if: ${{ !contains(github.ref_name, '-') }} 367 runs-on: ubuntu-latest 368 steps: 369 - name: Extract version 370 id: version 371 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 372 373 - uses: actions/checkout@v4 374 with: 375 repository: myorg/homebrew-tap 376 token: ${{ secrets.TAP_GITHUB_TOKEN }} 377 378 - name: Download checksums 379 run: | 380 set -euo pipefail 381 curl -sL "https://github.com/myorg/mytool/releases/download/v${{ steps.version.outputs.version }}/checksums-sha256.txt" \ 382 -o checksums.txt 383 384 - name: Update formula 385 run: | 386 set -euo pipefail 387 VERSION="${{ steps.version.outputs.version }}" 388 LINUX_X64_SHA=$(grep "linux-x64" checksums.txt | awk '{print $1}') 389 LINUX_ARM64_SHA=$(grep "linux-arm64" checksums.txt | awk '{print $1}') 390 OSX_ARM64_SHA=$(grep "osx-arm64" checksums.txt | awk '{print $1}') 391 392 # Use sed or a templating script to update Formula/mytool.rb 393 # with new version and SHA-256 values 394 python3 scripts/update-formula.py \ 395 --version "$VERSION" \ 396 --linux-x64-sha "$LINUX_X64_SHA" \ 397 --linux-arm64-sha "$LINUX_ARM64_SHA" \ 398 --osx-arm64-sha "$OSX_ARM64_SHA" 399 400 - name: Create PR 401 uses: peter-evans/create-pull-request@v6 402 with: 403 title: 'mytool ${{ steps.version.outputs.version }}' 404 commit-message: 'Update mytool to ${{ steps.version.outputs.version }}' 405 branch: 'update-mytool-${{ steps.version.outputs.version }}' 406 body: | 407 Automated update for mytool v${{ steps.version.outputs.version }} 408 Release: https://github.com/myorg/mytool/releases/tag/v${{ steps.version.outputs.version }} 409 410```text 411 412### winget Manifest Update 413 414```yaml 415 416update-winget: 417 needs: release 418 if: ${{ !contains(github.ref_name, '-') }} 419 runs-on: windows-latest 420 steps: 421 - name: Extract version 422 id: version 423 shell: bash 424 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 425 426 - name: Submit to winget-pkgs 427 uses: vedantmgoyal9/winget-releaser@main 428 with: 429 identifier: MyOrg.MyTool 430 version: ${{ steps.version.outputs.version }} 431 installers-regex: '\.zip$' 432 token: ${{ secrets.WINGET_GITHUB_TOKEN }} 433 434```text 435 436### Scoop Manifest Update 437 438```yaml 439 440update-scoop: 441 needs: release 442 if: ${{ !contains(github.ref_name, '-') }} 443 runs-on: ubuntu-latest 444 steps: 445 - name: Extract version 446 id: version 447 run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" 448 449 - uses: actions/checkout@v4 450 with: 451 repository: myorg/scoop-mytool 452 token: ${{ secrets.SCOOP_GITHUB_TOKEN }} 453 454 - name: Download checksums 455 run: | 456 set -euo pipefail 457 curl -sL "https://github.com/myorg/mytool/releases/download/v${{ steps.version.outputs.version }}/checksums-sha256.txt" \ 458 -o checksums.txt 459 460 - name: Update manifest 461 run: | 462 set -euo pipefail 463 VERSION="${{ steps.version.outputs.version }}" 464 WIN_X64_SHA=$(grep "win-x64" checksums.txt | awk '{print $1}') 465 466 # Update bucket/mytool.json with new version and hash 467 jq --arg v "$VERSION" --arg h "$WIN_X64_SHA" \ 468 '.version = $v | .architecture."64bit".hash = $h | 469 .architecture."64bit".url = "https://github.com/myorg/mytool/releases/download/v\($v)/mytool-\($v)-win-x64.zip"' \ 470 bucket/mytool.json > tmp.json && mv tmp.json bucket/mytool.json 471 472 - name: Create PR 473 uses: peter-evans/create-pull-request@v6 474 with: 475 title: 'mytool ${{ steps.version.outputs.version }}' 476 commit-message: 'Update mytool to ${{ steps.version.outputs.version }}' 477 branch: 'update-mytool-${{ steps.version.outputs.version }}' 478 479```text 480 481--- 482 483## Versioning Strategy Details 484 485### SemVer for CLI Tools 486 487| Change Type | Version Bump | Example | 488| -------------------------------- | ------------------ | -------------- | 489| Breaking CLI flag rename/removal | Major | 1.x.x -> 2.0.0 | 490| New command or option | Minor | x.1.x -> x.2.0 | 491| Bug fix, performance improvement | Patch | x.x.1 -> x.x.2 | 492| Release candidate | Pre-release suffix | x.x.x-rc.1 | 493 494### Version Embedding 495 496The version flows from the git tag through `dotnet publish` into the binary: 497 498```xml 499 500<!-- .csproj -- Version is set at publish time via /p:Version --> 501<PropertyGroup> 502 <!-- Fallback version for local development --> 503 <Version>0.0.0-dev</Version> 504</PropertyGroup> 505 506```text 507 508```bash 509 510# --version output matches the git tag 511$ mytool --version 5121.2.3 513 514```bash 515 516### Tagging Workflow 517 518```bash 519 520# 1. Update CHANGELOG.md (if applicable) 521# 2. Commit the changelog 522git commit -am "docs: update changelog for v1.2.3" 523 524# 3. Tag the release 525git tag -a v1.2.3 -m "Release v1.2.3" 526 527# 4. Push tag -- triggers the release workflow 528git push origin v1.2.3 529 530```text 531 532--- 533 534## Workflow Security 535 536### Secret Management 537 538```yaml 539 540# Required repository secrets: 541# NUGET_API_KEY - NuGet.org API key for package publishing 542# TAP_GITHUB_TOKEN - PAT with repo scope for homebrew-tap 543# WINGET_GITHUB_TOKEN - PAT with public_repo scope for winget-pkgs PRs 544# SCOOP_GITHUB_TOKEN - PAT with repo scope for scoop bucket 545# CHOCO_API_KEY - Chocolatey API key for package push 546 547```text 548 549### Permissions 550 551```yaml 552 553permissions: 554 contents: write # Minimum: create GitHub Releases and upload assets 555 556```yaml 557 558Use job-level permissions when different jobs need different scopes. Never grant `write-all`. 559 560--- 561 562## Agent Gotchas 563 5641. **Do not use `set -e` without `set -o pipefail` in GitHub Actions bash steps.** Without `pipefail`, a failing command 565 piped to `tee` or another utility exits 0, masking the failure. Always use `set -euo pipefail`. 5662. **Do not hardcode the .NET version in the publish path.** Use `dotnet publish -o ./publish` to control the output 567 directory explicitly. Hardcoding `net8.0` in artifact paths breaks when upgrading to .NET 9+. 5683. **Do not skip the pre-release detection step.** Package manager submissions (Homebrew, winget, Scoop, Chocolatey, 569 NuGet) must be gated on stable versions. Publishing a `-rc.1` to winget-pkgs or NuGet as stable causes user 570 confusion. 5714. **Do not use `actions/upload-artifact` v3 with `merge-multiple`.** The `merge-multiple` parameter requires 572 `actions/download-artifact@v4`. Using v3 silently ignores the flag and creates nested directories. 5735. **Do not forget `retention-days: 1` on intermediate build artifacts.** Release artifacts are published to GitHub 574 Releases (permanent). Workflow artifacts are temporary and should expire quickly to save storage. 5756. **Do not create GitHub Releases with `gh release create` in a matrix job.** Only the release job (after all builds 576 complete) should create the release. Matrix jobs upload artifacts; the release job assembles them. 577 578--- 579 580## References 581 582- [GitHub Actions workflow syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) 583- [softprops/action-gh-release](https://github.com/softprops/action-gh-release) 584- [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) 585- [vedantmgoyal9/winget-releaser](https://github.com/vedantmgoyal9/winget-releaser) 586- [Semantic Versioning](https://semver.org/) 587- [.NET versioning](https://learn.microsoft.com/en-us/dotnet/core/versions/) 588- [GitHub Actions artifacts](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts)

Related Skills

Looking for an alternative to dotnet-cli-release-pipeline or building a Categories.community AI Agent? Explore these related open-source MCP Servers.

View All

widget-generator

Logo of f
f

widget-generator is an open-source AI agent skill for creating widget plugins that are injected into prompt feeds on prompts.chat. It supports two rendering modes: standard prompt widgets using default PromptCard styling and custom render widgets built as full React components.

149.6k
0
Design

chat-sdk

Logo of lobehub
lobehub

chat-sdk is a unified TypeScript SDK for building chat bots across multiple platforms, providing a single interface for deploying bot logic.

73.0k
0
Communication

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication