Aspireify
One-time wiring skill. drops a skeleton;
turns
that skeleton into a working AppHost by scanning the repo, proposing a resource
graph, editing the AppHost, wiring
, and validating end
to end. Self-deactivates after a clean
.
🚫 Hard Refusal: Never Edit
⛔
REFUSE any request to edit, modify, change, open-for-edit, or "tweak" files
inside
of a TypeScript AppHost. This directory is
generated from
the installed Aspire integration package graph. It is regenerated by
,
, and startup when package changes require it.
If a user asks to edit something in
(e.g.,
.aspire/modules/postgres.module.ts
),
the correct response is:
- Refuse the edit with a clear "I won't edit " statement.
- Explain that is generated and any changes are clobbered.
- Redirect the requested change to the configured AppHost entry point:
current , or legacy .
- If the user wants a new integration, suggest ; if they want
to change configuration, show the equivalent edit in the AppHost entry point.
| ❌ Wrong | ✅ Right |
|---|
Open .aspire/modules/postgres.module.ts
and tweak the connection options | Edit and change addPostgres('pg', { ... })
options there |
| Modify a generated file directly | Re-run after updating |
| Comment out a line in to disable a resource | Remove or guard the resource declaration in |
This rule applies even if the user insists, even for "one-line" changes, even for
"just to test something." The TS AppHost regenerates
deterministically;
edits are unrecoverable noise.
Guiding Principles
Minimize changes to the user's code
Adapt the AppHost to fit the app, not the other way around. Prefer
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.
Surface tradeoffs; do not decide silently
When a small code change unlocks better Aspire integration, present both options:
the zero-code-change mapping and the small-change version that enables
,
health checks, service discovery, dynamic ports, or dashboard telemetry. Ask which
approach the user wants, then implement that choice without complaint.
Verify APIs before writing AppHost code
Use
aspire docs search <topic>
and
for workflow guidance.
Use
aspire docs api search <query> --language csharp|typescript
and
for API shape. Use
aspire integration list/search
to
find integrations before
. Do not invent packages, methods, overloads,
or command shapes; C# and TypeScript AppHost APIs differ.
Keep configuration visible in the AppHost
Scan
,
,
,
,
, 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
values. Never
delete
files or remove existing
entries without explicit user
approval because non-Aspire workflows may still depend on them.
Local development first
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.
Redis TLS edge case
Aspire can automatically provision TLS certificates for container resources. If Redis
health checks fail with SSL/TLS handshake errors, do not fall back to
.
Use
WithoutHttpsCertificate()
on the Redis resource when the consuming app expects
plain Redis.
Project-Local Override
If
.agents/skills/aspireify/SKILL.md
exists (installed by
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.
Prerequisites
Detection — When to Activate
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 | just ran in this session | ✅ Definitive |
| Empty AppHost stub | / / current (or legacy ) only contains | ✅ Definitive |
| without resources | Config present, AppHost has no / | 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 / projects but AppHost references none | High |
If the AppHost already has wired resources and the user wants to
start/stop
the app →
. If the user wants to
deploy →
.
Language Support
| AppHost Style | Detection | Edit Target |
|---|
| C# SDK-style | containing <Sdk Name="Aspire.AppHost.Sdk" />
| (top-level statements) |
| File-based C# | with and directives | itself |
| TypeScript | Current or legacy with generated | Configured AppHost entry point only — never edit |
See references/csharp-authoring.md and
references/typescript-authoring.md.
owns the CLI-driven migration from legacy
. After it
updates packages and migration artifacts, return to aspireify only when the user still
needs AppHost source wiring or authoring.
TypeScript AppHost package managers
Dependency and toolchain failures belong to this skill. Before recommending a command,
inspect the AppHost directory and then its immediate eligible parent. Within each directory,
the first recognized marker wins in this order:
- in (, , , or , optionally versioned)
An AppHost-local marker takes precedence over every parent marker. If neither directory has
a recognized marker, Aspire defaults to npm. Report the selected manager and marker.
Use the selected manager only to repair dependencies or diagnose the toolchain. The resolver
commands are
,
, and
; a generated brownfield pnpm
AppHost uses
pnpm install --ignore-workspace
, while other pnpm dependency installs use
. Yarn Classic (
or a v1 lockfile) is unsupported: stop and ask the
user to upgrade to Yarn 4+ or explicitly migrate to npm, pnpm, or Bun.
Do not change
or create, replace, or regenerate a lockfile merely to
influence detection or switch managers. Preserve existing files until the user explicitly
chooses an upgrade or migration. Start the AppHost with
aspire start --non-interactive
,
not a raw package-manager launcher. See
references/typescript-authoring.md for the full
command matrix and resolver details.
Workflow Phases
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:
- apphost-wiring.md — full AppHost wiring workflow, API lookup, endpoint/parameter patterns, validation, solution updates, and cleanup.
- docker-compose.md — docker-compose migration, profiles, image mapping, ports, volumes, and .
- full-solution-apphosts.md — large solution triage, mixed SDK boundaries, solution membership, ServiceDefaults placement, and legacy host migration.
- javascript-apps.md — JavaScript resource selection, workspace/monorepo package-manager handling, ports, scripts, and TS AppHost package config.
- opentelemetry.md — optional Node.js, Python, and Go OpenTelemetry wiring for non-.NET services.
1. Scan
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 | , (Postgres? Redis? Rabbit?) |
| Connection strings | grep , , for , , , , , |
| Integration packages | per project; package.json |
| Existing endpoints | hardcoded ports in , , |
Full heuristics in references/scan-and-propose.md.
2. Propose
Present a resource graph before editing. Ask clarifying questions:
- "I see Postgres in — should I model it as or use Azure Database for PostgreSQL?"
- "Your React app hardcodes — replace with Aspire service discovery ()?"
- "Your API has an endpoint — exclude it from so consumers don't see it?"
3. Edit
Apply the proposed graph. Use the right authoring style for the AppHost language.
4. Validate
bash
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.
5. Self-Deactivate
After a clean
, announce:
✅ AppHost wired and validated. Handing off to aspire-orchestration for
day-to-day start/stop/wait. Aspireify is done.
Integration Discovery Catalog
Map detected services → Aspire integrations. See
references/scan-and-propose.md for the full
catalog.
| Detected | C# | TS |
|---|
| Postgres in compose / package | AddPostgres("pg").AddDatabase("db")
| addPostgres('pg').addDatabase('db')
|
| Redis in compose / | | |
| RabbitMQ | (v7 client w/ pub-sub tracing) | |
| MongoDB | | |
| Cosmos DB | AddAzureCosmosDB("cosmos")
| addAzureCosmosDB('cosmos')
|
| Azure Service Bus | | |
| Azure Cache for Redis (Entra) | (now GA) | |
| 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')
|
Current Authoring Rules
| Rule | Why |
|---|
Use unified withEnvironment(name, value)
in TS — never the deprecated per-kind helpers (, , etc.) | Single API handles all value kinds; per-kind helpers are deprecated |
| Use / over hand-rolled Dockerfiles for JS frontends | First-class lifecycle + integration |
| Use / / for JS publish | Replaces hand-rolled Dockerfiles; SPA → static, SSR Node → NodeServer, package-script SSR → PackageScript |
| Add to frontend resources for browser console + screenshots in dashboard | 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 in TS AppHosts | Generated; edits get clobbered. Edit the configured (or legacy ) only |
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 |
Look up unfamiliar API: aspire docs api search <query> --language csharp|typescript
| Don't guess overloads or builder chains |
Use context / await ctx.services().getInteractionService()
| is obsolete, and alone returns a services accessor |
| Use for external connection strings | PublishAsConnectionString
is obsolete |
Check IInteractionService.IsAvailable
before prompting | CLI-invoked commands may be noninteractive; prefer command arguments for dashboard + CLI input |
| Treat as experimental | Suppress ; do not generate removed or TypeScript dimension options |
| Keep all Aspire SDK and packages on the same release family | Mixed release families can fail at startup |
| Migrate GitHub Models integrations to Azure AI Foundry | Aspire.Hosting.GitHub.Models
is deprecated and absent from integration discovery |
Use WithModule(RedisModules.*)
for Redis 8 modules | Prefer typed JSON, Search, Bloom Filter, and TimeSeries constants over raw module paths |
| Use Foundry for hosted executable/container agents | Current Azure AI Foundry path replaces deprecated GitHub Models |
C# vs TS Quick Reference
| 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 | | |
| Pass connection | | |
| External HTTP | .WithExternalHttpEndpoints()
| .withExternalHttpEndpoints()
|
| Endpoint expression | | api.getEndpoint('http').url
/ / |
| Build + run | | await builder.build().run();
|
ServiceDefaults Wiring
Each project should call
builder.AddServiceDefaults();
to opt into OpenTelemetry,
health checks, and service discovery. Add the
project
reference (or NuGet for non-monorepo). See
references/service-defaults.md.
Endpoint & Reference Conventions
csharp
// 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
Validation & Recovery
| Symptom | Action |
|---|
| fails with build error | Fix code, re-run |
| File-lock errors during edit | Hand off to → → retry |
| Resource missing from | Re-run aspire describe --include-hidden
; is AppHost-level |
| TS AppHost change ignored | Confirm you edited the configured (or legacy ), not |
| Mixed JSON output from | Strip non-JSON lines before parsing (#15843) |
Full flow in references/validation.md.
Handoff Rules
| Scenario | Route To |
|---|
| AppHost skeleton not yet dropped | → skill |
| Day-to-day start/stop/wait/restart | → skill |
| Publish, deploy, destroy, pipeline steps | → skill |
| Logs, traces, metrics, dashboard, browser log inspection | → skill |
| Deployed (Azure/AKS) app diagnostics | → skill (azure-skills) |
Key Rules
- Never overwrite existing files — always augment or merge.
- Ask before modifying service code, especially OpenTelemetry and ServiceDefaults injection.
- Respect existing project structure — do not reorganize the repo.
- If stuck, use to diagnose environment issues.
- Never hardcode URLs in / — pass endpoint references such as or instead of string literals.
- Never use / to set URLs — that API is only for dashboard display labels; belongs in AppHost launch/profile configuration.
References
- apphost-wiring.md — Detailed AppHost wiring workflow and API lookup patterns
- docker-compose.md — Docker Compose migration patterns
- full-solution-apphosts.md — Large/full-solution AppHost guidance
- javascript-apps.md — JavaScript/TypeScript app and workspace handling
- opentelemetry.md — Non-.NET OpenTelemetry setup
- scan-and-propose.md — Repo scan heuristics + integration catalog
- csharp-authoring.md — C# AppHost patterns
- typescript-authoring.md — TS AppHost patterns + parity APIs
- service-defaults.md — Wire OTel, health checks, service discovery
- validation.md — End-to-end validation + recovery
- aspire-13-5-breaking-changes.md — Breaking changes introduced in 13.5 and fixes for affected releases