Skip to content
cccskills
FreePublished on GitHub

dotnet-cli-packaging

Publishes to package managers. Homebrew, apt/deb, winget, Scoop, Chocolatey manifests.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md16.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

dotnet-cli-packaging

Multi-platform packaging for .NET CLI tools: Homebrew formula authoring (binary tap and cask), apt/deb packaging with dpkg-deb, winget manifest YAML schema and PR submission to winget-pkgs, Scoop manifest JSON, Chocolatey package creation, dotnet tool global/local packaging, and NuGet distribution.

Version assumptions: .NET 8.0+ baseline. Package manager formats are stable across .NET versions.

Scope

  • Homebrew formula authoring (binary tap and cask)
  • apt/deb packaging with dpkg-deb
  • winget manifest YAML schema and PR submission
  • Scoop manifest JSON for Windows
  • Chocolatey package creation
  • dotnet tool global/local packaging and NuGet distribution

Out of scope

  • CLI distribution strategy (AOT vs framework-dependent decision) -- see [skill:dotnet-cli-distribution]
  • Release CI/CD pipeline that automates packaging -- see [skill:dotnet-cli-release-pipeline]
  • Native AOT compilation -- see [skill:dotnet-native-aot]
  • Container-based distribution -- see [skill:dotnet-containers]
  • General CI/CD patterns -- see [skill:dotnet-gha-patterns] and [skill:dotnet-ado-patterns]

Cross-references: [skill:dotnet-cli-distribution] for distribution strategy and RID matrix, [skill:dotnet-cli-release-pipeline] for automated package publishing, [skill:dotnet-native-aot] for AOT binary production, [skill:dotnet-containers] for container-based distribution, [skill:dotnet-tool-management] for consumer-side tool installation and manifest management.


Homebrew (macOS / Linux)

Homebrew is the primary package manager for macOS and widely used on Linux. Two distribution formats exist for CLI tools.

Binary Tap (Formula)

A formula downloads pre-built binaries per platform. This is the recommended approach for Native AOT CLI tools.


# Formula/mytool.rb
class Mytool < Formula
  desc "A CLI tool for managing widgets"
  homepage "https://github.com/myorg/mytool"
  version "1.2.3"
  license "MIT"

  on_macos do
    on_arm do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-osx-arm64.tar.gz"
      sha256 "abc123..."
    end
    # Optional: remove on_intel block if not targeting Intel Macs
    on_intel do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-osx-x64.tar.gz"
      sha256 "def456..."
    end
  end

  on_linux do
    on_arm do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-linux-arm64.tar.gz"
      sha256 "ghi789..."
    end
    on_intel do
      url "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-linux-x64.tar.gz"
      sha256 "jkl012..."
    end
  end

  def install
    bin.install "mytool"
  end

  test do
    assert_match version.to_s, shell_output("#{bin}/mytool --version")
  end
end

```bash

### Hosting a Tap

A tap is a Git repository containing formulae. Create a repo named `homebrew-tap`:

```text

myorg/homebrew-tap/
  Formula/
    mytool.rb

```text

Users install with:

```bash

brew tap myorg/tap
brew install mytool

```bash

### Homebrew Cask

Casks are for GUI applications or tools with an installer. For pure CLI tools, prefer formulae over casks.

```ruby

# Casks/mytool.rb -- only if the tool has a GUI component
cask "mytool" do
  version "1.2.3"
  sha256 "abc123..."

  url "https://github.com/myorg/mytool/releases/download/v#{version}/mytool-#{version}-osx-arm64.tar.gz"
  name "MyTool"
  homepage "https://github.com/myorg/mytool"

  binary "mytool"
end

```text

---

## apt/deb (Debian/Ubuntu)

### Building a .deb Package with dpkg-deb

Create the package directory structure:

```text

mytool_1.2.3_amd64/
  DEBIAN/
    control
  usr/
    bin/
      mytool

```text

**Control file:**

```text

Package: mytool
Version: 1.2.3
Section: utils
Priority: optional
Architecture: amd64
Maintainer: My Org <dev@myorg.com>
Description: A CLI tool for managing widgets
 MyTool provides fast widget management from the command line.
 Built with .NET Native AOT for zero-dependency execution.
Homepage: https://github.com/myorg/mytool

```bash

**Build the package:**

```bash

#!/bin/bash
set -euo pipefail

VERSION="${1:?Usage: build-deb.sh <version>}"
ARCH="amd64"  # or arm64
PKG_DIR="mytool_${VERSION}_${ARCH}"

mkdir -p "$PKG_DIR/DEBIAN"
mkdir -p "$PKG_DIR/usr/bin"

# Copy the published binary
cp "artifacts/linux-x64/mytool" "$PKG_DIR/usr/bin/mytool"
chmod 755 "$PKG_DIR/usr/bin/mytool"

# Write control file
cat > "$PKG_DIR/DEBIAN/control" << EOF
Package: mytool
Version: ${VERSION}
Section: utils
Priority: optional
Architecture: ${ARCH}
Maintainer: My Org <dev@myorg.com>
Description: A CLI tool for managing widgets
Homepage: https://github.com/myorg/mytool
EOF

# Build the .deb
dpkg-deb --build --root-owner-group "$PKG_DIR"
echo "Built: ${PKG_DIR}.deb"

```text

**RID to Debian architecture mapping:**

| .NET RID      | Debian Architecture |
| ------------- | ------------------- |
| `linux-x64`   | `amd64`             |
| `linux-arm64` | `arm64`             |

### Installing the .deb

```bash

sudo dpkg -i mytool_1.2.3_amd64.deb

```bash

---

## winget (Windows Package Manager)

### Manifest YAML Schema

winget manifests consist of multiple YAML files in a versioned directory structure within the `microsoft/winget-pkgs`
repository.

**Directory structure:**

```text

manifests/
  m/
    MyOrg/
      MyTool/
        1.2.3/
          MyOrg.MyTool.yaml              # Version manifest
          MyOrg.MyTool.installer.yaml    # Installer manifest
          MyOrg.MyTool.locale.en-US.yaml # Locale manifest

```yaml

**Version manifest (MyOrg.MyTool.yaml):**

```yaml

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
DefaultLocale: en-US
ManifestType: version
ManifestVersion: 1.9.0

```text

**Installer manifest (MyOrg.MyTool.installer.yaml):**

```yaml

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
InstallerType: zip
NestedInstallerType: portable
NestedInstallerFiles:
  - RelativeFilePath: mytool.exe
    PortableCommandAlias: mytool
Installers:
  - Architecture: x64
    InstallerUrl: https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip
    InstallerSha256: ABC123...
  - Architecture: arm64
    InstallerUrl: https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-arm64.zip
    InstallerSha256: DEF456...
ManifestType: installer
ManifestVersion: 1.9.0

```text

**Locale manifest (MyOrg.MyTool.locale.en-US.yaml):**

```yaml

PackageIdentifier: MyOrg.MyTool
PackageVersion: 1.2.3
PackageLocale: en-US
PackageName: MyTool
Publisher: My Org
ShortDescription: A CLI tool for managing widgets
License: MIT
PackageUrl: https://github.com/myorg/mytool
ManifestType: defaultLocale
ManifestVersion: 1.9.0

```text

### Submitting to winget-pkgs

1. Fork `microsoft/winget-pkgs` on GitHub
2. Create the manifest files in the correct directory structure
3. Validate locally: `winget validate --manifest <path>`
4. Submit a PR -- automated checks run against the manifest
5. Microsoft team reviews and merges

See [skill:dotnet-cli-release-pipeline] for automating winget PR creation.

---

## Scoop (Windows)

Scoop is popular among Windows power users. Manifests are JSON files in a bucket repository.

### Scoop Manifest

```json

{
  "version": "1.2.3",
  "description": "A CLI tool for managing widgets",
  "homepage": "https://github.com/myorg/mytool",
  "license": "MIT",
  "architecture": {
    "64bit": {
      "url": "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip",
      "hash": "abc123..."
    },
    "arm64": {
      "url": "https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-arm64.zip",
      "hash": "def456..."
    }
  },
  "bin": "mytool.exe",
  "checkver": {
    "github": "https://github.com/myorg/mytool"
  },
  "autoupdate": {
    "architecture": {
      "64bit": {
        "url": "https://github.com/myorg/mytool/releases/download/v$version/mytool-$version-win-x64.zip"
      },
      "arm64": {
        "url": "https://github.com/myorg/mytool/releases/download/v$version/mytool-$version-win-arm64.zip"
      }
    }
  }
}

```text

### Hosting a Scoop Bucket

Create a GitHub repo named `scoop-mytool` (or `scoop-bucket`):

```text

myorg/scoop-mytool/
  bucket/
    mytool.json

```json

Users install with:

```powershell

scoop bucket add myorg https://github.com/myorg/scoop-mytool
scoop install mytool

```bash

---

## Chocolatey

Chocolatey is Windows' most established package manager for binary distribution.

### Package Structure

```text

mytool/
  mytool.nuspec
  tools/
    chocolateyInstall.ps1
    LICENSE.txt

```powershell

**mytool.nuspec:**

```xml

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.xmldata.org/2004/07/nuspec">
  <metadata>
    <id>mytool</id>
    <version>1.2.3</version>
    <title>MyTool</title>
    <authors>My Org</authors>
    <projectUrl>https://github.com/myorg/mytool</projectUrl>
    <license type="expression">MIT</license>
    <description>A CLI tool for managing widgets.</description>
    <tags>cli dotnet tools</tags>
  </metadata>
</package>

```text

**tools/chocolateyInstall.ps1:**

```powershell

$ErrorActionPreference = 'Stop'

$packageArgs = @{
  packageName    = 'mytool'
  url64bit       = 'https://github.com/myorg/mytool/releases/download/v1.2.3/mytool-1.2.3-win-x64.zip'
  checksum64     = 'ABC123...'
  checksumType64 = 'sha256'
  unzipLocation  = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
}

Install-ChocolateyZipPackage @packageArgs

```bash

### Building and Publishing

```powershell

# Pack the .nupkg
choco pack mytool.nuspec

# Test locally
choco install mytool --source="." --force

# Push to Chocolatey Community Repository
choco push mytool.1.2.3.nupkg --source https://push.chocolatey.org/ --api-key $env:CHOCO_API_KEY

```text

---

## dotnet tool (Global and Local)

`dotnet tool` is the simplest distribution for .NET developers. Tools are distributed as NuGet packages.

### Project Configuration for Tool Packaging

```xml

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>

    <!-- Tool packaging properties -->
    <PackAsTool>true</PackAsTool>
    <ToolCommandName>mytool</ToolCommandName>
    <PackageId>MyOrg.MyTool</PackageId>
    <Version>1.2.3</Version>
    <Description>A CLI tool for managing widgets</Description>
    <Authors>My Org</Authors>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/myorg/mytool</PackageProjectUrl>
    <PackageReadmeFile>README.md</PackageReadmeFile>
  </PropertyGroup>

  <ItemGroup>
    <None Include="../../README.md" Pack="true" PackagePath="/" />
  </ItemGroup>
</Project>

```markdown

### Building and Publishing

```bash

# Pack the tool
dotnet pack -c Release

# Publish to NuGet.org
dotnet nuget push bin/Release/MyOrg.MyTool.1.2.3.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY"

```json

### Installing dotnet Tools

```bash

# Global tool (available system-wide)
dotnet tool install -g MyOrg.MyTool

# Local tool (per-project, tracked in .config/dotnet-tools.json)
dotnet new tool-manifest  # first time only
dotnet tool install MyOrg.MyTool

# Update
dotnet tool update -g MyOrg.MyTool

# Run local tool
dotnet tool run mytool
# or just:
dotnet mytool

```text

### Global vs Local Tools

| Aspect             | Global Tool                 | Local Tool                         |
| ------------------ | --------------------------- | ---------------------------------- |
| Scope              | System-wide (per user)      | Per-project directory              |
| Install location   | `~/.dotnet/tools`           | `.config/dotnet-tools.json`        |
| Version management | Manual update               | Tracked in source control          |
| CI/CD              | Must install before use     | `dotnet tool restore` restores all |
| Best for           | Personal productivity tools | Project-specific build tools       |

---

## NuGet Distribution

For tools distributed as NuGet packages (either as `dotnet tool` or standalone):

### Package Metadata

```xml

<PropertyGroup>
  <PackageId>MyOrg.MyTool</PackageId>
  <Version>1.2.3</Version>
  <Description>A CLI tool for managing widgets</Description>
  <Authors>My Org</Authors>
  <PackageLicenseExpression>MIT</PackageLicenseExpression>
  <PackageProjectUrl>https://github.com/myorg/mytool</PackageProjectUrl>
  <PackageReadmeFile>README.md</PackageReadmeFile>
  <PackageTags>cli;tools;widgets</PackageTags>
  <RepositoryUrl>https://github.com/myorg/mytool</RepositoryUrl>
  <RepositoryType>git</RepositoryType>
</PropertyGroup>

```text

### Publishing to NuGet.org

```bash

# Pack
dotnet pack -c Release -o ./nupkgs

# Push (use env var for API key -- never hardcode)
dotnet nuget push ./nupkgs/MyOrg.MyTool.1.2.3.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY"

```json

### Private Feed Distribution

```bash

# Push to a private feed (Azure Artifacts, GitHub Packages, etc.)
dotnet nuget push ./nupkgs/MyOrg.MyTool.1.2.3.nupkg \
  --source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
  --api-key "$AZURE_ARTIFACTS_PAT"

```json

---

## Package Format Comparison

| Format           | Platform       | Requires .NET   | Auto-Update          | Difficulty |
| ---------------- | -------------- | --------------- | -------------------- | ---------- |
| Homebrew formula | macOS, Linux   | No (binary tap) | `brew upgrade`       | Medium     |
| apt/deb          | Debian/Ubuntu  | No (AOT binary) | Via apt repo         | Medium     |
| winget           | Windows 10+    | No (portable)   | `winget upgrade`     | Medium     |
| Scoop            | Windows        | No (portable)   | `scoop update`       | Low        |
| Chocolatey       | Windows        | No              | `choco upgrade`      | Medium     |
| dotnet tool      | Cross-platform | Yes (SDK)       | `dotnet tool update` | Low        |
| NuGet (library)  | Cross-platform | Yes (SDK)       | NuGet restore        | Low        |

---

## Agent Gotchas

1. **Do not hardcode SHA-256 hashes in package manifests.** Generate checksums from actual release artifacts, not
   placeholder values. All package managers validate checksums against downloaded files.
2. **Do not use `InstallerType: exe` for portable CLI tools in winget.** Use `InstallerType: zip` with
   `NestedInstallerType: portable` for standalone executables. The `exe` type implies an installer with silent flags.
3. **Do not forget `PackAsTool` for dotnet tool projects.** Without `<PackAsTool>true</PackAsTool>`, `dotnet pack`
   produces a library package, not an installable tool.
4. **Do not hardcode API keys in packaging scripts.** Use environment variable references (`$NUGET_API_KEY`,
   `$env:CHOCO_API_KEY`) with a comment noting CI secret configuration.
5. **Do not mix Homebrew formula and cask for the same CLI tool.** Pure CLI tools should use formulae. Casks are for GUI
   applications with macOS app bundles.
6. **Do not skip the `test` block in Homebrew formulae.** Homebrew CI runs formula tests. A missing test block causes
   review rejection. At minimum, test `--version` output.

---



## Code Navigation (Serena MCP)

**Primary approach:** Use Serena symbol operations for efficient code navigation:

1. **Find definitions**: `serena_find_symbol` instead of text search
2. **Understand structure**: `serena_get_symbols_overview` for file organization
3. **Track references**: `serena_find_referencing_symbols` for impact analysis
4. **Precise edits**: `serena_replace_symbol_body` for clean modifications

**When to use Serena vs traditional tools:**
- ✅ **Use Serena**: Navigation, refactoring, dependency analysis, precise edits
- ✅ **Use Read/Grep**: Reading full files, pattern matching, simple text operations
- ✅ **Fallback**: If Serena unavailable, traditional tools work fine

**Example workflow:**
```text
# Instead of:
Read: src/Services/OrderService.cs
Grep: "public void ProcessOrder"

# Use:
serena_find_symbol: "OrderService/ProcessOrder"
serena_get_symbols_overview: "src/Services/OrderService.cs"
```
## References

- [Homebrew Formula Cookbook](https://docs.brew.sh/Formula-Cookbook)
- [Homebrew Taps](https://docs.brew.sh/Taps)
- [dpkg-deb manual](https://man7.org/linux/man-pages/man1/dpkg-deb.1.html)
- [winget manifest schema](https://learn.microsoft.com/en-us/windows/package-manager/package/manifest)
- [winget-pkgs repository](https://github.com/microsoft/winget-pkgs)
- [Scoop Wiki](https://github.com/ScoopInstaller/Scoop/wiki)
- [Chocolatey package creation](https://docs.chocolatey.org/en-us/create/create-packages)
- [.NET tool packaging](https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools-how-to-create)
- [NuGet publishing](https://learn.microsoft.com/en-us/nuget/nuget-org/publish-a-package)

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Patterns and techniques for evaluating and improving AI agent outputs.

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

Comprehensive AI prompt engineering safety review and improvement prompt. Analyzes prompts for safety, bias, security vulnerabilities, and effectiveness while providing detailed improvement recommendations.

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

Use when user requests research requiring multiple sources, comprehensive analysis, or synthesis across topics - technical research, domain knowledge gathering, market analysis, or learning about complex subjects

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

AI-powered wiki generation for code repositories with commands, agents, and skills

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

Use when building .NET 10 or C# 14 applications; when using minimal APIs, modular monolith patterns, or feature folders; when implementing HTTP resilience, Options pattern, Channels, or validation; when seeing outdated patterns like old extension method syntax

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

Implements accessible .NET UI. SemanticProperties, ARIA, AutomationPeer, testing per platform.

The English summary is being prepared. Showing the original description.

rudironsoni/Synaxis2Updated Mar 17, 2026

See all skills by rudironsoni

Report a problem with this skill