From project-setup
Sets up a Refit-based API client generation workflow in a .NET solution. Use this skill whenever the user wants to add an ApiClient project to a .NET solution, auto-generate typed Refit HTTP clients from an OpenAPI spec, set up refitter for client generation, create or update a generate.sh script for NuGet packaging, configure a local NuGet feed, or wire up service-to-service HTTP communication between .NET services. Triggers on phrases like "add dotnet api client", "add ApiClient project", "generate refit client", "setup refitter", "create generate.sh", "setup dotnet client generation", "NuGet api client", or when the user wants to call one .NET service from another .NET service.
How this skill is triggered — by the user, by Claude, or both
Slash command
/project-setup:setup-dotnet-api-clientThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Creates and configures a complete Refit-based API client generation workflow:
Creates and configures a complete Refit-based API client generation workflow:
a *.ApiClient classlib project, a local refitter tool, a generate.sh script
that rebuilds and packs the client as a NuGet, and CLAUDE.md documentation.
From the solution directory, find the solution file:
find . -maxdepth 2 \( -name "*.slnx" -o -name "*.sln" \) | head -1
Extract the solution name (e.g. ServiceA.slnx → ServiceA). If none is found, ask
the user which directory to work in.
Also check:
{SolutionName}.ApiClient/ already exist?*.Api.csproj project exist somewhere under the solution root?generate.sh already exist?Use these answers to skip steps that are already done rather than re-running them.
Ask (or confirm from existing files) two things before touching anything:
| Setting | Default |
|---|---|
| OpenAPI URL | http://localhost:5000/openapi/v1.json |
| NuGet output dir | ../.nuget (sibling of the solution dir) |
If values are already set in an existing .refitter or generate.sh, show them and ask the user to confirm or override.
Skip entirely if {SolutionName}.ApiClient/ already exists.
# from the solution directory
dotnet new classlib -n {SolutionName}.ApiClient
dotnet sln {SolutionName}.slnx add {SolutionName}.ApiClient/{SolutionName}.ApiClient.csproj
# from inside the ApiClient directory
cd {SolutionName}.ApiClient
dotnet new tool-manifest # creates .config/dotnet-tools.json
dotnet tool install --local refitter --version 2.0.0
dotnet add package Refit
After scaffolding, delete the generated placeholder:
rm {SolutionName}.ApiClient/Class1.cs
And create the Generated folder placeholder:
mkdir -p {SolutionName}.ApiClient/Generated
touch {SolutionName}.ApiClient/Generated/.gitkeep
For existing projects, check each sub-step (tool manifest, refitter installed, Refit package) individually and only run the missing ones.
Write {SolutionName}.ApiClient/.refitter. If it already exists, show it and ask before overwriting.
{
"openApiPath": "{OPENAPI_URL}",
"namespace": "{SolutionName}.ApiClient",
"outputFilename": "I{SolutionName}Api.g.cs",
"addAutoGeneratedHeader": true
}
Refitter 2.0.0 places the output at
./Generated/{outputFilename}relative to the ApiClient project directory, soGenerated/must exist before the first run.
Write this script at the solution root (same level as the .slnx / .sln file) and make it executable with chmod +x generate.sh. If it already exists, show it and ask before overwriting.
#!/bin/bash
set -e
if [ -z "$1" ]; then
echo "Usage: ./generate.sh <version> (e.g. ./generate.sh 1.1.0)"
exit 1
fi
VERSION="$1"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NUGET_OUT="{NUGET_OUTPUT_DIR_RESOLVED}"
# Auto-detect the *.Api project
API_PROJECT=$(find "$SCRIPT_DIR" -maxdepth 3 -name "*.Api.csproj" -not -path "*/obj/*" | head -1)
if [ -z "$API_PROJECT" ]; then
echo "Error: Could not find a *.Api.csproj under $SCRIPT_DIR"
exit 1
fi
API_DIR="$(dirname "$API_PROJECT")"
echo "==> Starting API ($API_DIR)..."
cd "$API_DIR"
dotnet run --no-launch-profile &
API_PID=$!
echo "==> Waiting for OpenAPI endpoint..."
until curl -sf {OPENAPI_URL} > /dev/null 2>&1; do sleep 1; done
echo "==> Generating Refit client..."
cd "$SCRIPT_DIR/{SolutionName}.ApiClient"
dotnet refitter --settings-file .refitter
echo "==> Stopping API..."
kill "$API_PID"
wait "$API_PID" 2>/dev/null || true
echo "==> Packing version $VERSION..."
dotnet pack \
-p:PackageId={SolutionName}.ApiClient \
-p:Version="$VERSION" \
-o "$NUGET_OUT"
echo "==> Done. Package {SolutionName}.ApiClient.$VERSION saved to $NUGET_OUT"
Substitutions to make:
{NUGET_OUTPUT_DIR_RESOLVED} → if the user chose ../.nuget (relative), write it as "$SCRIPT_DIR/../.nuget" so it works from any working directory{OPENAPI_URL} → the URL from Step 2{SolutionName} → the detected solution nameAppend the section below to CLAUDE.md in the solution directory (create if absent). Check first — if a section mentioning generate.sh is already present, skip or ask before updating.
## API Client Generation
`{SolutionName}.ApiClient` is an auto-generated Refit client for `{SolutionName}.Api`.
**Regenerate after**: adding, removing, or changing any API endpoint.
**How to regenerate**:
\```bash
./generate.sh <version> # e.g. ./generate.sh 1.2.0
\```
The script:
1. Starts `{SolutionName}.Api` in the background
2. Polls the OpenAPI endpoint at `{OPENAPI_URL}`
3. Regenerates `{SolutionName}.ApiClient/Generated/I{SolutionName}Api.g.cs` via refitter
4. Kills the API, then packs and saves the NuGet to `{NUGET_OUTPUT_DIR}`
**Do not hand-edit** `Generated/I{SolutionName}Api.g.cs` — it is fully generated.
**Endpoint naming**: refitter uses each endpoint's `operationId` as the generated method name.
To get readable names (e.g. `GetTodoById` instead of `TodosGet2`), every endpoint in
`{SolutionName}.Api` must declare a name. In ASP.NET minimal APIs use `.WithName()`:
\```csharp
app.MapGet("/todos/{id:int}", ...)
.WithName("GetTodoById");
app.MapPost("/todos", ...)
.WithName("CreateTodo");
\```
For controller-based APIs, set `Name` on the `[HttpGet]` / `[HttpPost]` etc. attribute:
\```csharp
[HttpGet("{id}", Name = "GetTodoById")]
\```
After adding or renaming endpoints, re-run `./generate.sh <version>` to regenerate the client.
**Consuming projects** need a `nuget.config` pointing to the local feed:
\```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="local-nuget" value="{NUGET_OUTPUT_DIR}" />
</packageSources>
</configuration>
\```
End with a concise table of everything done (or skipped):
✅ Created {SolutionName}.ApiClient project + added to solution
✅ Installed refitter 2.0.0 (local tool)
✅ Added Refit package
✅ Created {SolutionName}.ApiClient/.refitter
✅ Created generate.sh
✅ Updated CLAUDE.md
Next step: run ./generate.sh 1.0.0 to produce the first NuGet package.
Use ⏭ Skipped for steps that were already in place.
Provides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.
npx claudepluginhub damian0401/dev-skills --plugin project-setup