Help us improve
Share bugs, ideas, or general feedback.
From aspire
Wires an Aspire AppHost after `aspire init` drops a skeleton: scans repo, proposes resource graph, edits AppHost (C#/TS), wires ServiceDefaults + OTel, validates with `aspire start`, then self-deactivates.
npx claudepluginhub microsoft/aspire-skills --plugin aspireHow this skill is triggered — by the user, by Claude, or both
Slash command
/aspire:aspireifyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **One-time wiring skill.** `aspire init` drops a skeleton; `aspireify` turns
evals/eval.yamlreferences/apphost-wiring.mdreferences/csharp-authoring.mdreferences/docker-compose.mdreferences/full-solution-apphosts.mdreferences/javascript-apps.mdreferences/opentelemetry.mdreferences/scan-and-propose.mdreferences/service-defaults.mdreferences/typescript-authoring.mdreferences/validation.mdTop-level router for Aspire 13.4 distributed apps — detects AppHost, enforces guardrails, and dispatches to sub-skills for init, orchestration, deployment, or monitoring.
Guides .NET Aspire setup for cloud-native orchestration: AppHost configuration, service defaults, resource wiring, service discovery, and the Aspire dashboard.
Using .NET Aspire. AppHost orchestration, service discovery, components, dashboard, health checks.
Share bugs, ideas, or general feedback.
One-time wiring skill.
aspire initdrops a skeleton;aspireifyturns that skeleton into a working AppHost by scanning the repo, proposing a resource graph, editing the AppHost, wiringAspire.ServiceDefaults, and validating end to end. Self-deactivates after a cleanaspire start. Aligned with Aspire 13.4 guidance from the current Aspire development branch.
.aspire/modules/⛔ REFUSE any request to edit, modify, change, open-for-edit, or "tweak" files inside
.aspire/modules/of a TypeScript AppHost. This directory is generated by Aspire fromapphost.tsand the integration packages — every file in it gets clobbered on the next build,aspire add, oraspire start.If a user asks to edit something in
.aspire/modules/(e.g.,.aspire/modules/postgres.module.ts), the correct response is:
- Refuse the edit with a clear "I won't edit
.aspire/modules/" statement.- Explain that
.aspire/modules/is generated and any changes are clobbered.- Redirect the requested change to
apphost.ts— the only file the user should hand-edit in a TS AppHost.- If the user wants a new integration, suggest
aspire add <package>; if they want to change configuration, show the equivalent edit inapphost.ts.
| ❌ Wrong | ✅ Right |
|---|---|
Open .aspire/modules/postgres.module.ts and tweak the connection options | Edit apphost.ts and change addPostgres('pg', { ... }) options there |
Modify a generated .aspire/modules/*.ts file directly | Re-run aspire add <package> after updating apphost.ts |
Comment out a line in .aspire/modules/ to disable a resource | Remove or guard the resource declaration in apphost.ts |
This rule applies even if the user insists, even for "one-line" changes, even for
"just to test something." The TS AppHost regenerates .aspire/modules/ deterministically;
edits are unrecoverable noise.
Adapt the AppHost to fit the app, not the other way around. Prefer WithEnvironment()
to match existing environment variable names, Aspire-managed ports over fixed ports,
and 1:1 Docker Compose mapping before optimizing. Do not restructure directories,
rename files, or change build scripts unless the user explicitly chooses that tradeoff.
When a small code change unlocks better Aspire integration, present both options:
the zero-code-change mapping and the small-change version that enables WithReference,
health checks, service discovery, dynamic ports, or dashboard telemetry. Ask which
approach the user wants, then implement that choice without complaint.
Use aspire docs search <topic> and aspire docs get <slug> for workflow guidance.
Use aspire docs api search <query> --language csharp|typescript and
aspire docs api get <id> for API shape. Use aspire integration list/search to
find integrations before aspire add. Do not invent packages, methods, overloads,
or command shapes; C# and TypeScript AppHost APIs differ.
Scan .env, .env.local, .env.development, secrets.json.example,
<UserSecretsId>, and setup scripts. Propose migrating values into AppHost parameters:
connection strings become Aspire resources, API keys/tokens become secret parameters,
and non-secret config becomes plain parameters or WithEnvironment() values. Never
delete .env files or remove existing UserSecretsId entries without explicit user
approval because non-Aspire workflows may still depend on them.
This skill optimizes local development, not production deployment. Prefer persistent container lifetimes and data volumes for databases/caches, use HTTPS endpoints by default, pass endpoint references instead of hardcoded URLs, and model external SaaS URLs/API keys as parameters so they are visible in the dashboard.
Aspire can automatically provision TLS certificates for container resources. If Redis
health checks fail with SSL/TLS handshake errors, do not fall back to AddContainer().
Use WithoutHttpsCertificate() on the Redis resource when the consuming app expects
plain Redis.
If .agents/skills/aspireify/SKILL.md exists (installed by aspire init or
aspire agent init --skills aspireify), warn the user that a project-local
copy is present and defer to it. The plugin version is the fallback.
⚠️ Project-local .agents/skills/aspireify/SKILL.md detected — deferring to it.
| Requirement | Install |
|---|---|
| .NET 10.0 SDK (C# AppHost) | https://dotnet.microsoft.com/download |
| Node.js 20+ (TS AppHost) | https://nodejs.org |
| Aspire CLI | curl -sSL https://aspire.dev/install.sh | bash or dotnet tool install -g Aspire.Cli |
| Skeleton already dropped | aspire init produced aspire.config.json + AppHost stub |
Activate when ANY signal is present AND the AppHost is unwired (no resources declared beyond the stub):
| Signal | How to Detect | Confidence |
|---|---|---|
| Skeleton just dropped | aspire init just ran in this session | ✅ Definitive |
| Empty AppHost stub | apphost.cs / Program.cs / apphost.ts only contains Build().Run() | ✅ Definitive |
aspire.config.json without resources | Config present, AppHost has no AddProject/addProject | High |
| User asks to "wire" / "scaffold resource graph" | Verb match: wire, scaffold, integrate, hook up, add Postgres/Redis/etc. | High |
| User asks "what next after aspire init" | Direct handoff request | ✅ Definitive |
| Existing repo with services + new AppHost | Repo has .csproj/package.json projects but AppHost references none | High |
If the AppHost already has wired resources and the user wants to start/stop
the app → aspire-orchestration. If the user wants to deploy → aspire-deployment.
| AppHost Style | Detection | Edit Target |
|---|---|---|
| C# SDK-style | .csproj containing <Sdk Name="Aspire.AppHost.Sdk" /> | Program.cs (top-level statements) |
| File-based C# | apphost.cs with #:sdk Aspire.AppHost.Sdk and #:package directives | apphost.cs itself |
| TypeScript | apphost.ts with generated .aspire/modules/ | apphost.ts only — never edit .aspire/modules/ |
See references/csharp-authoring.md and references/typescript-authoring.md.
1. SCAN → discover projects, services, dependencies, integration candidates
2. PROPOSE → resource graph + integration list, confirm with user
3. EDIT → wire AppHost, add ServiceDefaults + OTel + health checks
4. VALIDATE → aspire start --non-interactive → aspire wait <each resource>
5. DEACTIVATE → confirm clean start, hand off to aspire-orchestration
For the detailed, upstream-parity workflow, load these references before editing:
depends_on.Walk the repo and inventory:
| What | How |
|---|---|
| .NET projects | find . -name '*.csproj' -not -path '*/bin/*' -not -path '*/obj/*' |
| Node services | find . -name 'package.json' -not -path '*/node_modules/*' |
| Python services | find . -name 'pyproject.toml' -o -name 'requirements.txt' |
| Container deps in compose | docker-compose.yml, compose.yaml (Postgres? Redis? Rabbit?) |
| Connection strings | grep appsettings*.json, .env*, config/* for Postgres, Redis, Mongo, RabbitMQ, Cosmos, ServiceBus |
| Integration packages | dotnet list package per project; package.json dependencies |
| Existing endpoints | hardcoded ports in launchSettings.json, next.config.js, vite.config.ts |
Full heuristics in references/scan-and-propose.md.
Present a resource graph before editing. Ask clarifying questions:
docker-compose.yml — should I model it as AddPostgres('db') or use Azure Database for PostgreSQL?"http://localhost:5000 — replace with Aspire service discovery (endpoint.url)?"/admin endpoint — exclude it from WithReference() so consumers don't see it?"Apply the proposed graph. Use the right authoring style for the AppHost language.
aspire start --non-interactive --format Json
aspire wait <resource> # repeat for each declared resource
aspire describe --format Json # sanity check graph
Full validation flow + recovery in references/validation.md.
After a clean aspire start, announce:
✅ AppHost wired and validated. Handing off to aspire-orchestration for
day-to-day start/stop/wait. Aspireify is done.
Map detected services → Aspire integrations. See references/scan-and-propose.md for the full catalog.
| Detected | C# | TS |
|---|---|---|
Postgres in compose / Npgsql package | AddPostgres("pg").AddDatabase("db") | addPostgres('pg').addDatabase('db') |
Redis in compose / StackExchange.Redis | AddRedis("cache") | addRedis('cache') |
| RabbitMQ | AddRabbitMQ("mq") (v7 client w/ pub-sub tracing) | addRabbitMQ('mq') |
| MongoDB | AddMongoDB("mongo") | addMongoDB('mongo') |
| Cosmos DB | AddAzureCosmosDB("cosmos") | addAzureCosmosDB('cosmos') |
| Azure Service Bus | AddAzureServiceBus("sb") | addAzureServiceBus('sb') |
| Azure Cache for Redis (Entra) | AddAzureRedis("cache") (now GA) | addAzureRedis('cache') |
| Next.js frontend | AddNextJsApp("web", "./web") | addNextJsApp('web', '../web') |
| Vite SPA | AddViteApp("web", "./web") | addViteApp('web', '../web') |
| Plain Node app | AddNodeApp("api", "server.js") | addNodeApp('api', 'server.js') |
| Rule | Why |
|---|---|
Use unified withEnvironment(name, value) in TS — never the deprecated per-kind helpers (withEnvironmentEndpoint, withEnvironmentParameter, etc.) | Single API handles all value kinds; per-kind helpers are deprecated |
Use AddNextJsApp / AddViteApp over hand-rolled Dockerfiles for JS frontends | First-class lifecycle + PublishAs* integration |
Use PublishAsStaticWebsite / PublishAsNodeServer / PublishAsPackageScript for JS publish | Replaces hand-rolled Dockerfiles; SPA → static, SSR Node → NodeServer, package-script SSR → PackageScript |
Add WithBrowserLogs() to frontend resources for browser console + screenshots in dashboard | Aspire.Hosting.Browsers surfaces browser telemetry in the dashboard |
Bind every resource to a compute environment with WithComputeEnvironment(env) when multiple environments exist | Multi-environment deploys require explicit binding |
Never edit .aspire/modules/ in TS AppHosts | Generated; edits get clobbered. Edit only apphost.ts |
Use WithEndpoint("name", e => ...) to update endpoints | Endpoint callbacks update existing endpoints rather than throwing on duplicates |
Mark admin endpoints with ExcludeReferenceEndpoint = true | Prevents consumers from receiving admin URLs via WithReference() |
Look up unfamiliar API: aspire docs api search <query> --language csharp|typescript | Don't guess overloads or builder chains |
| Concept | C# | TypeScript |
|---|---|---|
| Builder | var builder = DistributedApplication.CreateBuilder(args); | const builder = await createBuilder(); |
| Add project | builder.AddProject<Projects.Api>("api") (SDK) or AddProject("api", "../Api/Api.csproj") | await builder.addProject('api', '../Api/Api.csproj') |
| Wire env var (any value type) | .WithEnvironment("KEY", value) | .withEnvironment('KEY', value) ← unified API |
| Wait for dependency | .WaitFor(db) | .waitFor(db) |
| Pass connection | .WithReference(db) | .withReference(db) |
| External HTTP | .WithExternalHttpEndpoints() | .withExternalHttpEndpoints() |
| Endpoint expression | api.GetEndpoint("http") | api.getEndpoint('http').url / .host / .port |
| Build + run | builder.Build().Run(); | await builder.build().run(); |
Each project should call builder.AddServiceDefaults(); to opt into OpenTelemetry,
health checks, and service discovery. Add the Aspire.ServiceDefaults project
reference (or NuGet for non-monorepo). See
references/service-defaults.md.
// Public-facing API. Mark "admin" endpoint as not-for-consumers.
var api = builder.AddProject<Projects.Api>("api")
.WithExternalHttpEndpoints()
.WithEndpoint("admin", e => e.ExcludeReferenceEndpoint = true);
// Frontend wires the API via service discovery.
builder.AddNextJsApp("web", "./web")
.WithReference(api) // injects services__api__http and __https
.WaitFor(api)
.WithBrowserLogs(); // browser console + screenshots
| Symptom | Action |
|---|---|
aspire start fails with build error | Fix code, re-run aspire start |
aspire wait rejects resource name | Use displayName from aspire ps --format Json (#15842) |
| File-lock errors during edit | Hand off to aspire-orchestration → aspire stop → retry |
Resource missing from aspire ps | May be hidden — re-run with --include-hidden |
| TS AppHost change ignored | Confirm you edited apphost.ts, not .aspire/modules/ |
Mixed JSON output from aspire start | Strip non-JSON lines before parsing (#15843) |
Full flow in references/validation.md.
| Scenario | Route To |
|---|---|
| AppHost skeleton not yet dropped | → aspire-init skill |
| Day-to-day start/stop/wait/restart | → aspire-orchestration skill |
| Publish, deploy, destroy, pipeline steps | → aspire-deployment skill |
| Logs, traces, metrics, dashboard, browser log inspection | → aspire-monitoring skill |
| Deployed (Azure/AKS) app diagnostics | → azure-diagnostics skill (azure-skills) |
aspire doctor to diagnose environment issues.WithEnvironment / withEnvironment — pass endpoint references such as api.GetEndpoint("http") or api.getEndpoint('http') instead of string literals.WithUrlForEndpoint / withUrlForEndpoint to set dev.localhost URLs — that API is only for dashboard display labels; dev.localhost belongs in AppHost launch/profile configuration.