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.
How 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.mdOne-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.npx claudepluginhub microsoft/aspire-skills --plugin aspireTop-level router for Aspire 13.4 distributed apps — detects AppHost, enforces guardrails, and dispatches to sub-skills for init, orchestration, deployment, or monitoring.
Orchestrates distributed applications using Aspire's CLI, AppHost, service discovery, and MCP server. Use for creating, running, debugging, and deploying Aspire apps.
Using .NET Aspire. AppHost orchestration, service discovery, components, dashboard, health checks.