---
name: install-local-tool
version: 1.0.0
date: 2026-01-21
description: Build and install a dotnet tool locally to global tools, handling platform-specific packaging and process cleanup.
canonical_repo: https://github.com/stoicstudio/ClaudeSkills
canonical_path: skills/install-local-tool/SKILL.md
---
# install-local-tool
Builds the current project as a dotnet tool and installs it to the global dotnet tools, replacing any existing version.
> **Canonical Source**: This skill is maintained at [stoicstudio/ClaudeSkills](https://github.com/stoicstudio/ClaudeSkills).
> Run `/update-skill install-local-tool` to update.
## Prerequisites
Before running, ensure:
1. The project is a dotnet tool (`true` in .csproj)
2. All code changes are complete
3. `dotnet test` passes (if tests exist)
4. Version number has been updated in .csproj or VersionInfo.cs
## Steps
### 1. Locate the Tool Project
Find the main .csproj file that defines the tool:
```bash
# Look for .csproj with PackAsTool in src/ directory
grep -r "true" src/**/*.csproj
```
Or use the project structure convention: `src/{ProjectName}/{ProjectName}.csproj`
### 2. Extract Tool Configuration from .csproj
Read the .csproj file and extract these properties:
| Property | Purpose | Example |
|----------|---------|---------|
| `ToolCommandName` | CLI command name | `clang-codex` |
| `PackageId` | NuGet package identifier | `clang-codex.mcp` |
| `Version` | Package version | `0.22.4` |
**Detect Platform-Specific Packaging**:
Check if PackageId is conditional on `$(TargetRid)`:
```xml
clang-codex.mcp.$(TargetRid)
clang-codex.mcp
```
If this pattern exists, the project requires platform-specific packaging.
### 3. Determine Current Platform RID
If platform-specific packaging is needed, detect the runtime identifier:
```bash
# Windows
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OS" == "Windows_NT" ]]; then
# Check architecture
if [[ "$(uname -m)" == "aarch64" || "$PROCESSOR_ARCHITECTURE" == "ARM64" ]]; then
RID="win-arm64"
else
RID="win-x64"
fi
# Linux
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
if [[ "$(uname -m)" == "aarch64" ]]; then
RID="linux-arm64"
else
RID="linux-x64"
fi
# macOS
elif [[ "$OSTYPE" == "darwin"* ]]; then
if [[ "$(uname -m)" == "arm64" ]]; then
RID="osx-arm64"
else
RID="osx-x64"
fi
fi
```
### 4. Construct Package Name
```bash
# If platform-specific
if [[ "$PLATFORM_SPECIFIC" == "true" ]]; then
PACKAGE_NAME="${BASE_PACKAGE_ID}.${RID}" # e.g., clang-codex.mcp.win-x64
else
PACKAGE_NAME="$BASE_PACKAGE_ID" # e.g., roslyn-codex.mcp
fi
```
### 5. Stop Running Processes
Kill any running instances of the tool to allow file replacement:
```bash
# Get the tool command name from .csproj
TOOL_CMD="clang-codex" # from ToolCommandName
# Windows (via taskkill)
taskkill /F /IM "${TOOL_CMD}.exe" 2>/dev/null || true
# Linux/macOS (via pkill)
pkill -f "$TOOL_CMD" 2>/dev/null || true
```
**Note**: The process name is typically `{ToolCommandName}.exe` on Windows or just `{ToolCommandName}` on Unix.
### 6. Uninstall Existing Version
```bash
dotnet tool uninstall --global "$PACKAGE_NAME" 2>/dev/null || true
```
The `|| true` ensures the command succeeds even if the tool isn't installed.
### 7. Build and Pack the Tool
```bash
# Navigate to project directory
cd src/{ProjectName}
# Clean previous artifacts
rm -rf bin/Release/*.nupkg
# Build and pack
if [[ "$PLATFORM_SPECIFIC" == "true" ]]; then
# Platform-specific: pass TargetRid to get correct PackageId
dotnet pack -c Release -p:TargetRid=$RID
else
# Standard: no RID needed
dotnet pack -c Release
fi
```
The .nupkg will be created in `bin/Release/`.
### 8. Install from Local Package
```bash
# Find the generated .nupkg
NUPKG=$(ls bin/Release/*.nupkg | head -1)
# Install globally from local package
dotnet tool install --global --add-source ./bin/Release "$PACKAGE_NAME"
```
### 9. Verify Installation
```bash
# Check installation
dotnet tool list --global | grep "$TOOL_CMD"
# Test the tool
$TOOL_CMD --version 2>/dev/null || $TOOL_CMD --help 2>/dev/null || echo "Tool installed (no --version/--help flag)"
```
### 10. Report Result
Report success with:
- Tool command name
- Package name
- Version installed
- Installation path (from `dotnet tool list --global`)
## Example Output
```
✓ Stopped 2 running instances of clang-codex
✓ Uninstalled clang-codex.mcp.win-x64 (previous version)
✓ Built and packed clang-codex.mcp.win-x64 v0.22.4
✓ Installed globally
Tool: clang-codex
Package: clang-codex.mcp.win-x64
Version: 0.22.4
Path: C:\Users\john\.dotnet\tools\clang-codex.exe
```
## Platform-Specific Projects
Projects that bundle native libraries (like ClangCodex.Mcp with libclang) require platform-specific packaging. Detection:
**Indicators in .csproj**:
- `` property
- Conditional `` based on `$(TargetRid)`
- `` listing multiple platforms
- References to `*.runtime.*` native library packages
**Why needed**: Native libraries must match the target platform. A single "any" package cannot contain all platform variants efficiently.
## Troubleshooting
| Problem | Solution |
|---------|----------|
| "Tool already installed" | Uninstall failed; manually run `dotnet tool uninstall --global {name}` |
| "Process in use" | Close IDE or apps using the tool, or use Task Manager |
| "Package not found" | Check that `dotnet pack` succeeded and .nupkg exists |
| "Version mismatch" | Ensure Version in .csproj matches expected version |
| "Wrong platform" | Verify RID detection matches your actual platform |
## See Also
- [publish-release](../publish-release/SKILL.md) - For publishing to GitHub Packages
- [update-skill](../update-skill/SKILL.md) - Update this skill from canonical repo