
Aspire Orchestration
- 121 installs
- 74 repo stars
- Updated July 27, 2026
- microsoft/aspire-skills
aspire-orchestration is an agent skill that manages Aspire AppHost start, stop, wait, and recovery from file locks and port conflicts.
About
The aspire-orchestration skill manages Aspire AppHost lifecycle and recovers from file locks, port conflicts, and orphaned processes using mandatory safety guardrails. Detection fingerprints C# AppHost csproj with Aspire.AppHost.Sdk, file-based apphost.cs, TypeScript apphost.ts, aspire.config.json, and .aspire directories. Default workflow confirms the workspace is Aspire, runs aspire start or aspire start --isolated in git worktrees, waits with aspire wait using displayName from JSON output, inspects via aspire describe, and runs aspire stop to release locks when done. Safety rules forbid dotnet run on AppHost, curl polling instead of aspire wait, and dotnet build against locked files. File-lock errors MSB3491 and CS2012 always resolve with aspire stop before rebuild because Aspire holds bin and obj locks while running. Commands cover aspire ps, resource stop start rebuild, integration list and search, aspire update, aspire doctor, and --format Json for agents. Handoffs route AppHost wiring to aspireify, deployment to aspire-deployment, and logs traces to aspire-monitoring. Agents add --non-interactive and prefer resource commands for single-resource code changes.
- Mandatory guardrails prevent file locks and orphaned Aspire processes.
- Default workflow uses aspire start, wait, describe, and aspire stop cleanup.
- MSB3491 and CS2012 recovery always begins with aspire stop.
- Detects C#, file-based, and TypeScript AppHost project fingerprints.
- Handoffs AppHost edits to aspireify and telemetry to aspire-monitoring.
Aspire Orchestration by the numbers
- 121 all-time installs (skills.sh)
- Ranked #508 of 1,453 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
aspire-orchestration capabilities & compatibility
- Capabilities
- aspire project detection and fingerprinting · start stop wait describe resource lifecycle comm · file lock msb3491 cs2012 recovery via aspire sto · safety guardrails against dotnet run and pkill o · integration discovery and non interactive agent
- Works with
- docker · kubernetes
- Use cases
- devops · orchestration
What aspire-orchestration says it does
This skill prevents agent self-harm in Aspire projects.
npx skills add https://github.com/microsoft/aspire-skills --skill aspire-orchestrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 121 |
|---|---|
| repo stars | ★ 74 |
| Last updated | July 27, 2026 |
| Repository | microsoft/aspire-skills ↗ |
How do I safely start, wait for, and stop an Aspire app without file lock errors or orphaned processes?
Manage Aspire AppHost lifecycle with start, stop, wait, and recovery from file locks, port conflicts, and orphaned processes.
Who is it for?
Developers and agents managing Aspire AppHost lifecycle who need guardrails against lock and orphan failures.
Skip if: Skip for AppHost code wiring, deployment publishing, or telemetry inspection workflows.
When should I use this skill?
User asks to start my Aspire app, aspire stop, fix file lock MSB3491, or restart an API service resource.
What you get
A running Aspire app with resources ready via aspire wait and clean shutdown via aspire stop releasing locks.
Files
Aspire Orchestration
MANDATORY COMPLIANCE — This skill prevents agent self-harm in Aspire projects.
Violating these rules causes file locks, orphaned processes, and user frustration (#15801).
Prerequisites
| Requirement | Install |
|---|---|
| .NET 10.0 SDK | https://dotnet.microsoft.com/download |
| Aspire CLI (curl/PowerShell) | `curl -sSL https://aspire.dev/install.sh \ |
| Aspire CLI (NativeAOT global tool, .NET 10) | dotnet tool install -g Aspire.Cli |
Either install method works. The dotnet tool install path produces a NativeAOT binary (instant startup, no JIT warmup) and is the recommended option when .NET 10 is already present.
Detection
Activate when ANY signal is present:
| Signal | How to Detect | Confidence |
|---|---|---|
| C# AppHost | .csproj containing Aspire.AppHost.Sdk | ✅ Definitive |
| File-based C# AppHost | apphost.cs or .cs file with #:sdk Aspire.AppHost.Sdk | ✅ Definitive |
| TypeScript AppHost | apphost.ts file in project | ✅ Definitive |
| Aspire config | aspire.config.json in project root | High |
| Aspire settings | .aspire/ directory present | High |
| Generated TS modules | .aspire/modules/ directory present | High |
| Service defaults | Aspire.ServiceDefaults in project references | Medium |
See detection.md for detailed fingerprinting.
Safety Guardrails
| Situation | ✅ ALWAYS Do | ❌ NEVER Do |
|---|---|---|
| Start an Aspire app | aspire start | dotnet run on AppHost |
| Wait for resource ready | aspire wait <resource> | curl / HTTP polling loops |
| Code changed in a resource | Prefer resource commands, runtime watch/HMR, dashboard actions, or IDE-managed debugging | dotnet build against locked files |
| Task complete | aspire stop | Leave processes running |
| Check resource status | aspire describe / aspire ps | Manual process inspection |
| Working in git worktree | aspire start --isolated | aspire start without isolation |
| Running from AI agent | Add --non-interactive to all commands | Assuming interactive terminal |
| Editing unfamiliar API | aspire docs search <topic> then aspire docs api search <query> for API reference | Guessing API shape |
| C# AppHost API inspection | Use dotnet-inspect skill (if available) for local symbols | Guessing overloads or builder chains |
| Adding custom dashboard/resource commands | aspire docs search "custom resource commands" first | Inventing WithCommand patterns without docs |
| Installing Aspire support | Use aspire add or aspire init | ~~dotnet workload install aspire~~ (obsolete) |
See safety-guardrails.md for detailed rules and recovery patterns.
Default Workflow
1. Confirm workspace is Aspire — identify the AppHost 2. aspire start (or aspire start --isolated in worktrees) 3. aspire wait <resource> before interacting with any resource 4. aspire describe to inspect state, then work 5. If AppHost code changed, rerun aspire start; if only one resource changed, prefer the resource's commands/watch/HMR/debug workflow 6. aspire stop when cleanup is explicitly requested or needed to release locks/ports
Quick Reference
| Task | Command |
|---|---|
| Start app (agents) | aspire start (background, preferred) |
| Start app (human) | aspire run (foreground, dashboard) |
| Stop app | aspire stop |
| Wait for resource | aspire wait <resource> |
| Check status | aspire ps or aspire describe |
| Show hidden resources (proxies, helpers, migrations) | aspire ps --include-hidden / aspire describe --include-hidden |
| Resource operation | aspire resource <resource-name> <command> such as stop, start, or rebuild when exposed |
| Create new project | aspire new aspire-starter |
| Add Aspire to existing | aspire init (then hand off to aspireify skill for wiring) |
| Add integration | aspire add <package> |
| Discover integrations | aspire integration list --format Json / aspire integration search <query> --format Json |
| Upgrade the CLI itself | aspire update --self |
| Update project package refs | aspire update (modifies project files — get user approval) |
| Restore generated files | aspire restore |
| Environment maintenance | aspire cache clear, aspire certs trust, aspire certs clean |
| Diagnose environment | aspire doctor |
| Machine-readable output | --format Json (supported: ps, describe, start) |
| Look up API reference | `aspire docs api search <query> --language csharp\ |
| Browse API entries | aspire docs api list <scope> |
| Get API detail | aspire docs api get <id> |
Error Handling
| Symptom | Cause | Action |
|---|---|---|
| File lock errors during build (`MSB3491`, `CS2012`) | Aspire is running and holds locks on `bin/`, `obj/`, and assemblies. | Run `aspire stop` first, then rebuild or aspire start. Do NOT conclude the project has a permanent build failure. |
| "Port already in use" | Previous instance running | aspire stop, then aspire start |
| Resource not found | App not started or name wrong | aspire ps to check |
| Build errors in resource | Code error, not Aspire issue | Fix code, then use resource commands/watch/HMR/debug workflow or rerun aspire start if AppHost code changed |
| Environment issues | Missing SDK or tools | aspire doctor to diagnose |
JSON parse failure from aspire start | Mixed human/JSON output (#15843) | Strip non-JSON lines before parsing |
aspire wait rejects name | Use displayName not name (#15842) | Use displayName from aspire ps --format Json |
aspire ps hangs | AppHost on breakpoint (#15576) | Use timeout, check AppHost process |
aspire agent init fails | Non-interactive terminal (#16264) | Run from standard terminal |
| Docker daemon unavailable | Container-backed resources fail to start | Start Docker Desktop, then aspire start |
| Multiple AppHosts detected | Wrong AppHost targeted | Use --apphost <path> to specify explicitly |
🔒 File-Lock Recovery (MSB3491 / CS2012) — Always aspire stop First
When a build fails with error MSB3491: Could not write to output file ... or error CS2012: Cannot open ... for writing, the project itself is healthy — Aspire is running and holding file locks on the resource's output assemblies. The recovery is always the same:
# ✅ Correct recovery sequence
aspire stop # release the locks
# ... then either rebuild / restart one resource if the resource exposes commands ...
aspire resource <name> rebuild # example: C# project resource with rebuild command
# ... or restart the whole AppHost ...
aspire start # if AppHost code changed or Aspire was already stopped| ❌ NEVER do | ✅ ALWAYS do |
|---|---|
| Tell the user the project has a permanent build failure | Recognize the lock as Aspire holding outputs and run aspire stop |
dotnet build again with locks held | aspire stop first, then dotnet build (or prefer resource commands/watch/HMR/debug workflow) |
Delete bin/ / obj/ to "fix" the lock | aspire stop — deletion may succeed but the next build relocks |
pkill dotnet or kill <PID> to free locks | aspire stop — clean shutdown via the CLI, no orphans |
| Tell the user to "reboot" or "restart your machine" | aspire stop — single command, instant fix |
The same rule applies to any "file in use", "cannot access the file", or "another process is using" error during a build of an Aspire-managed resource.
Handoff Rules
| Scenario | Route To |
|---|---|
AppHost wiring after aspire init (scan repo, add resources, ServiceDefaults/OTel) | → aspireify skill (`aspireify/SKILL.md`) or project-local .agents/skills/aspireify/SKILL.md |
Browser logs (Aspire.Hosting.Browsers / WithBrowserLogs()) and dashboard authoring | → aspireify skill (code edits) and aspire-monitoring (discovery) |
Custom resource commands (WithCommand, ExecuteCommandResult, HttpCommandResultMode) | → aspireify skill |
Lifecycle hooks (SubscribeBeforeStart, SubscribeAfterResourcesCreated, BeforeStart pipeline phase) | → aspireify skill |
Endpoint authoring (WithEndpoint updates, ExcludeReferenceEndpoint flag) | → aspireify skill |
Deploy, publish, pipeline steps, aspire destroy | → aspire-deployment skill |
Logs, traces, metrics, dashboard, aspire dashboard run | → aspire-monitoring skill |
| Deployed app diagnostics | → azure-diagnostics skill (azure-skills) |
Runtime Settings And Environment
| Variable | Default | Purpose |
|---|---|---|
ASPIRE_ENABLE_CONTAINER_TUNNEL | true | Container tunnel provides uniform host connectivity across Docker Desktop, Docker Engine, and Podman. Set to false to opt out. |
ASPIRE_ENVIRONMENT | unset | Selects the environment-specific config profile — controls which appsettings.{environment}.json is loaded and which environment is reported in dashboard telemetry. |
ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE | true | The Aspire trusted developer certificate is used by DCP on Windows. Set to false to opt out. |
features.defaultWatchEnabled | false unless configured | Enables Aspire default watch for supported C# and TypeScript AppHosts. Do not treat this as per-resource rebuild, restart, or hot reload for resource source changes. |
TypeScript AppHost Note
Detection covers TS AppHosts (apphost.ts), but all TS AppHost authoring is delegated to `aspireify`. Current rules to apply when handing off:
| Rule | Why |
|---|---|
Prefer unified withEnvironment(name, value) over deprecated per-kind helpers (withEnvironmentEndpoint, withEnvironmentParameter, withEnvironmentConnectionString, withEnvironmentExpression, withEnvironmentFromOutput, withEnvironmentFromKeyVaultSecret) | Per-kind helpers are deprecated — single API now handles all value types |
Never edit .aspire/modules/ directly | Generated; use aspire add <package> to regenerate and aspire restore to recover missing files |
Use aspire docs api search <query> --language typescript for API lookup | TS surface differs from C# |
Skill Routing — In-Plugin Sibling Skills
After aspire init drops a skeleton AppHost + aspire.config.json, route AppHost wiring (scan repo → propose resource graph → edit AppHost → wire Aspire.ServiceDefaults / OTel → validate via aspire start) to the in-plugin aspireify skill: `aspireify/SKILL.md`. For first-run flows that only need the skeleton drop, see the in-plugin aspire-init skill: `aspire-init/SKILL.md`. This orchestration skill stays focused on lifecycle (start/stop/wait/restart) and never edits AppHost code itself.
Project-Local Skill Precedence
If .agents/skills/aspire/SKILL.md exists (from aspire agent init), defer to it for: C# AppHost editing, TS AppHost editing, Playwright handoff, investigation workflows. Safety guardrails from this plugin ALWAYS apply.
If .agents/skills/aspireify/SKILL.md exists project-locally (installed by aspire init in current Aspire), warn the user that a project-local aspireify skill is present and defer to it for AppHost wiring instead of the in-plugin sibling. Same precedence rule as the project-local aspire skill above: project-local wins, plugin guardrails still apply.
References
- safety-guardrails.md — Detailed rules and recovery patterns
- detection.md — Project fingerprinting
- app-commands.md — App lifecycle and bootstrap commands
- resource-management.md — Resource wait, restart, and operations
- agent-workflows.md — Common agent investigation, integration, TypeScript, and handoff workflows
name: aspire-orchestration-eval
description: Evaluates the aspire-orchestration skill against the 5 core complaints from
microsoft/aspire#15801 plus detection, worktree, and agent-mode scenarios.
version: "1.0"
type: capability
tags:
skill: aspire-orchestration
defaults:
runs: 3
timeout: 120s
executor: copilot-sdk
model: gpt-5-mini
stimuli:
- name: orch-update-self-001
prompt: How do I upgrade my Aspire CLI to the latest 13.3?
tags:
priority: p1
area:
- aspire-13-3
- update
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_update_self
config:
prompt: Does the assistant's response recommend `aspire update --self` to upgrade the Aspire CLI
itself? This is the safe, no-side-effect upgrade path that an agent can run unattended.
- type: prompt
name: distinguishes_project_update
config:
prompt: Does the assistant's response distinguish `aspire update --self` (CLI upgrade) from bare
`aspire update` (which modifies project package references and `aspire.config.json`)? It
should warn that bare `aspire update` edits project files and therefore should be run
with user approval rather than unattended.
- type: output-not-contains
config:
substring: automatically run aspire update
name: never_runs_project_update_unattended
- type: output-not-contains
config:
substring: run aspire update without confirmation
- type: output-contains
config:
substring: aspire update --self
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-aspireify-001
prompt: I just ran `aspire init` in my existing Node.js + .NET repo and it created an apphost.cs and
aspire.config.json. What's next? Wire up my services.
tags:
priority: p0
area:
- init-workflow
- aspireify-handoff
environment:
files:
- src: ../../../evals/non-aspire/MyApp/MyApp.csproj
dest: non-aspire/MyApp/MyApp.csproj
- src: ../../../evals/non-aspire/MyApp/Program.cs
dest: non-aspire/MyApp/Program.cs
graders:
- type: prompt
name: hands_off_to_aspireify
config:
prompt: Does the assistant's response explicitly hand the AppHost wiring step off to the `aspireify`
skill (in-plugin sibling at `../aspireify/SKILL.md`, OR the project-local
`.agents/skills/aspireify/SKILL.md` if installed by `aspire init`)? The orchestration
skill itself should defer scanning the repo, choosing resources, and editing the AppHost
to aspireify. Answer based on intent.
- type: prompt
name: mentions_project_local_precedence
config:
prompt: Does the assistant's response acknowledge that if a project-local
`.agents/skills/aspireify/SKILL.md` exists, the agent should defer to it (with a warning
to the user) instead of using the in-plugin sibling?
- type: output-not-contains
config:
substring: I'll write the AppHost
name: never_handauthors_apphost
- type: output-not-contains
config:
substring: Let me edit apphost.cs
- type: output-not-contains
config:
substring: I'll add AddProject
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-cleanup-001
prompt: I'm done working on this feature, what should I do to clean up?
tags:
priority: p0
area:
- safety-guardrail
- issue-15801
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_aspire_stop
config:
prompt: Does the assistant's response recommend using 'aspire stop' (or an equivalent Aspire CLI
cleanup command) to stop the running application? Answer based on the intent, not exact
string matching.
- type: prompt
name: explains_cleanup
config:
prompt: The assistant's response should recommend running 'aspire stop' and explain that leaving
Aspire running causes port conflicts, file locks, and resource waste.
- type: output-contains
config:
substring: aspire stop
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-detect-001
prompt: Help me understand this project structure
tags:
priority: p1
area: detection
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: identifies_aspire
config:
prompt: The assistant's response should identify this as an Aspire project based on the
Aspire.AppHost.Sdk reference in the csproj file. It should mention using aspire CLI
commands rather than standard dotnet commands.
- type: output-contains
config:
substring: Aspire
- type: output-contains
config:
substring: AppHost
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-detect-filebased-001
prompt: How do I run this app?
tags:
priority: p0
area: detection
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
graders:
- type: prompt
name: recognizes_aspire
config:
prompt: Does the assistant's response recognize this as an Aspire project and recommend using
'aspire start' or the Aspire CLI to run it, rather than 'dotnet run' or 'dotnet
apphost.cs'?
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet apphost.cs
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run_2
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-filelock-001
prompt: |-
I'm getting this error when trying to build:
error MSB3491: Could not write to output file 'bin/Debug/net10.0/MyService.dll'
error CS2012: Cannot open 'obj/Debug/net10.0/MyService.dll' for writing
tags:
priority: p0
area:
- error-recovery
- issue-15801
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: recognizes_aspire_locks
config:
prompt: The assistant's response should recognize that Aspire is holding file locks on the running
project and recommend either 'aspire stop' followed by rebuild, or 'aspire resource
<name> restart'.
- type: prompt
name: correct_recovery
config:
prompt: Does the assistant's response recommend using 'aspire stop' (or an equivalent Aspire CLI
command to stop the running instance) to resolve file lock errors? Answer based on the
intent, not exact string matching.
- type: output-not-contains
config:
substring: unbuildable
name: not_unbuildable
- type: output-not-contains
config:
substring: cannot be built
- type: output-contains
config:
substring: aspire stop
- type: output-not-contains
config:
substring: unbuildable
- type: output-not-contains
config:
substring: cannot be built
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-include-hidden-001
prompt: I added a YARP reverse proxy in front of my API in the AppHost, but `aspire ps` doesn't list
it. Did the AppHost wire it wrong?
tags:
priority: p1
area:
- aspire-13-3
- include-hidden
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: suggests_include_hidden
config:
prompt: Does the assistant's response recommend running `aspire ps --include-hidden` (or `aspire
describe --include-hidden`) BEFORE concluding that the AppHost is misconfigured? Aspire
13.3 filters hidden resources (proxies, helper containers, migrations) by default, so a
missing-from-`aspire ps` resource may exist but be filtered, not actually missing.
- type: prompt
name: explains_default_filtering
config:
prompt: Does the assistant's response explain (or imply) that filtered output is the correct default
for normal workflows, and that `--include-hidden` is the diagnostic opt-in for debugging
proxies, sidecars, or migrations?
- type: output-contains
config:
substring: --include-hidden
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-init-001
prompt: I have an existing Express.js app and a .NET API. I want to add Aspire to orchestrate them
together.
tags:
priority: p0
area:
- init-workflow
- aspireify-handoff
environment:
files:
- src: ../../../evals/non-aspire/MyApp/MyApp.csproj
dest: non-aspire/MyApp/MyApp.csproj
- src: ../../../evals/non-aspire/MyApp/Program.cs
dest: non-aspire/MyApp/Program.cs
graders:
- type: prompt
name: uses_aspire_init
config:
prompt: Does the assistant's response recommend running `aspire init` to drop the AppHost skeleton
into the existing repository? Answer based on intent.
- type: output-not-contains
config:
substring: dotnet workload install
name: never_workload
- type: prompt
name: hands_off_to_aspireify
config:
prompt: After running `aspire init`, does the assistant's response hand the wiring step off to the
`aspireify` skill (the in-plugin sibling skill, or the project-local
`.agents/skills/aspireify/SKILL.md` installed by `aspire init` in 13.3)? The
orchestration skill should explicitly defer to `aspireify` for repo scanning, resource
selection, ServiceDefaults / OTel wiring, and validation.
- type: prompt
name: knows_workflow
config:
prompt: "Does the assistant's response describe (or reference, via aspireify) the wiring workflow:
scanning the repository, selecting services, adding resources to the AppHost using the
3-tier API preference (first-party Aspire.Hosting.* > Community Toolkit > raw
fallbacks), and validating with `aspire start`?"
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-sdk-001
prompt: My project uses .NET 8. Can I still use Aspire with it?
tags:
priority: p1
area:
- safety-guardrail
- init-workflow
graders:
- type: prompt
name: preserves_sdk
config:
prompt: Does the assistant's response confirm that Aspire works with existing .NET SDK versions and
that global.json plus existing project target frameworks should be left untouched? The
AppHost can use a newer SDK while orchestrating older services. Answer based on intent.
- type: output-not-contains
config:
substring: change global.json
name: never_modify_globaljson
- type: output-not-contains
config:
substring: update global.json
- type: output-not-contains
config:
substring: modify global.json
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-noninteractive-001
prompt: Run the Aspire app in my CI pipeline
tags:
priority: p1
area: agent-mode
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_noninteractive
config:
prompt: Does the assistant's response recommend using the '--non-interactive' flag (or an equivalent
mechanism to prevent CLI prompts from hanging) when running Aspire in a CI pipeline?
Answer based on the intent, not exact string matching.
- type: output-contains
config:
substring: --non-interactive
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-rebuild-001
prompt: I changed some code in the API service, how do I see my changes?
tags:
priority: p0
area:
- safety-guardrail
- issue-15801
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_resource_restart
config:
prompt: Does the assistant's response recommend using 'aspire resource restart' (or an equivalent
Aspire CLI hot-reload/restart command) to apply code changes while the app is running?
Answer based on the intent, not exact string matching.
- type: output-not-contains
config:
substring: dotnet build
name: never_dotnet_build
- type: prompt
name: mentions_file_locks
config:
prompt: The assistant's response should mention that 'dotnet build' would cause file lock errors
because Aspire holds locks on running projects. It should recommend using aspire
resource <name> restart instead.
- type: output-contains
config:
substring: aspire resource
- type: output-contains
config:
substring: restart
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-start-001
prompt: I want to run my Aspire application for development
tags:
priority: p0
area:
- safety-guardrail
- issue-15801
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_aspire_start
config:
prompt: Does the assistant's response recommend using 'aspire start' (or an equivalent Aspire CLI
start command) to launch the application for development? Answer based on the intent,
not exact string matching.
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: prompt
name: explains_why
config:
prompt: Does the assistant's response explain why 'aspire start' should be used instead of 'dotnet
run' for Aspire projects, mentioning that the Aspire CLI manages the full application
lifecycle including dependent resources?
- type: output-contains
config:
substring: aspire start
- type: output-not-contains
config:
substring: dotnet run
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run_2
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-tier-001
prompt: I need to add a Go HTTP service and a PostgreSQL database to my Aspire AppHost
tags:
priority: p1
area: init-workflow
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
graders:
- type: prompt
name: correct_tiers
config:
prompt: Does the assistant's response use the correct integration tiers? PostgreSQL should use Tier
1 first-party Aspire.Hosting.PostgreSQL (AddPostgres). Go should use Tier 2
CommunityToolkit (AddGolangApp) or Tier 3 fallback (AddExecutable). The agent should
prefer higher tiers when available.
- type: prompt
name: uses_aspire_docs
config:
prompt: Does the assistant's response recommend looking up the API with aspire docs search or aspire
docs api search before writing AppHost code?
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-apidocs-001
prompt: I need to add a custom WithCommand to my AppHost resource but I'm not sure of the API signature
tags:
priority: p1
area: best-practice
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
graders:
- type: prompt
name: uses_docs_api
config:
prompt: Does the assistant's response recommend using 'aspire docs search' or 'aspire docs api
search' to look up the WithCommand API before editing the AppHost code, rather than
guessing the API shape? Answer based on intent.
- type: prompt
name: uses_docs_first
config:
prompt: Does the assistant's response follow a docs-first pattern — looking up documentation or API
reference before making code changes to the AppHost?
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-wait-001
prompt: I need to call the API service but it might not be ready yet
tags:
priority: p0
area:
- safety-guardrail
- issue-15801
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_aspire_wait
config:
prompt: Does the assistant's response recommend using 'aspire wait' (or an equivalent Aspire CLI
readiness-check command) to wait for a resource to become ready, rather than manual HTTP
polling? Answer based on the intent, not exact string matching.
- type: output-not-contains
config:
substring: curl
name: no_polling
- type: output-not-contains
config:
substring: while true
- type: output-not-contains
config:
substring: time.sleep
- type: output-not-contains
config:
substring: Thread.Sleep
- type: output-contains
config:
substring: aspire wait
- type: output-not-contains
config:
substring: curl
- type: output-not-contains
config:
substring: while
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: health
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: orch-worktree-001
prompt: I'm working in a git worktree and need to start the app
tags:
priority: p1
area: best-practice
environment:
files:
- src: ../../../evals/csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
dest: csharp-apphost/MyApp.AppHost/MyApp.AppHost.csproj
- src: ../../../evals/csharp-apphost/MyApp.AppHost/Program.cs
dest: csharp-apphost/MyApp.AppHost/Program.cs
- src: ../../../evals/csharp-apphost/aspire.config.json
dest: csharp-apphost/aspire.config.json
graders:
- type: prompt
name: uses_isolated
config:
prompt: Does the assistant's response recommend using the '--isolated' flag with 'aspire start' (or
an equivalent mechanism for port isolation) when running in a git worktree? Answer based
on the intent, not exact string matching.
- type: output-contains
config:
substring: --isolated
- type: output-contains
config:
substring: aspire start
- type: output-not-contains
config:
substring: dotnet run
name: never_dotnet_run
- type: output-not-contains
config:
substring: dotnet build
- type: output-not-contains
config:
substring: while true
name: never_curl_polling
- type: output-not-contains
config:
substring: sleep
- type: output-not-contains
config:
substring: curl.*health
- name: should_trigger_01
description: "Reason: Direct aspire start invocation — orchestration"
prompt: Run aspire start on my AppHost
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_02
description: "Reason: Direct start request"
prompt: Start my Aspire app
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_03
description: "Reason: aspire stop is orchestration"
prompt: Run aspire stop to clean up
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_04
description: "Reason: Exact MSB3491 error code — file-lock recovery scenario"
prompt: I'm getting MSB3491 file lock errors building my Aspire project
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_05
description: "Reason: Exact CS2012 error code — file-lock recovery"
prompt: CS2012 — Cannot open file for writing while Aspire is running
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_06
description: "Reason: Single resource restart is orchestration"
prompt: How do I restart just the API service in Aspire?
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_07
description: "Reason: Port conflict = orphaned Aspire instance — orchestration"
prompt: Port 5000 is already in use after I ran aspire start
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_08
description: "Reason: aspire wait is orchestration"
prompt: Run aspire wait on my postgres resource
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_09
description: "Reason: aspire update --self is orchestration (CLI lifecycle)"
prompt: Upgrade my Aspire CLI with aspire update --self
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_10
description: "Reason: Hidden-resource filtering = --include-hidden guidance lives in orchestration"
prompt: I see proxies missing in aspire ps — why?
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_trigger_11
description: "Reason: File-based C# AppHost should trigger orchestration (start/run lifecycle)"
prompt: Run my apphost.cs file
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: invokes_aspire_orchestration
config:
required:
- aspire-orchestration
- name: should_not_trigger_01
description: "Reason: Deployment routes to aspire-deployment"
prompt: Deploy my Aspire app to Azure
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_02
description: "Reason: Logs route to aspire-monitoring"
prompt: Show me the application logs
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_03
description: "Reason: Traces route to aspire-monitoring"
prompt: Check the distributed traces
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_04
description: "Reason: Publish routes to aspire-deployment"
prompt: Publish deployment artifacts with aspire publish
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_05
description: "Reason: Completely unrelated"
prompt: What's the weather today?
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_06
description: "Reason: Non-Aspire project"
prompt: Build my React app
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_07
description: "Reason: Standard test workflow, not Aspire-specific"
prompt: Run my unit tests
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_08
description: "Reason: Deployed diagnostics routes to azure-diagnostics"
prompt: Check my App Insights metrics for the deployed app
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_09
description: "Reason: AppHost wiring (resource selection + AppHost edits) is owned by aspireify"
prompt: Wire up my AppHost with the API and Postgres
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_10
description: "Reason: Repo scanning + AppHost edits route to aspireify"
prompt: Scan my repo and add the right resources to apphost.cs
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_11
description: "Reason: ServiceDefaults / OTel wiring routes to aspireify"
prompt: Configure ServiceDefaults and OTel for my services
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_12
description: "Reason: aspire destroy routes to aspire-deployment"
prompt: Tear down my Aspire deployment in Azure
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
- name: should_not_trigger_13
description: "Reason: aspire dashboard run routes to aspire-monitoring"
prompt: Run aspire dashboard run standalone
tags:
priority: p1
area: routing
graders:
- type: skill-invocation
name: does_not_invoke_aspire_orchestration
config:
disallowed:
- aspire-orchestration
Aspire Agent Workflows
Use these patterns when a task needs investigation or orchestration rather than a one-off command lookup.
Scenario: I Am In A Worktree And Need A Safe Background Run
Start the AppHost with aspire start so the CLI manages background execution. In git worktrees, use --isolated to avoid port conflicts and shared local state:
aspire start --isolatedIf the next step depends on one resource, wait for it explicitly:
aspire start --isolated
aspire wait myapiKeep these points in mind:
- In a git worktree, rerun
aspire start --isolatedwhenever AppHost changes need to be picked up. - Outside worktrees, rerun
aspire start. - Avoid
aspire runin normal agent workflows because it blocks the terminal.
Scenario: I Changed Code While The AppHost Is Running
Classify the change before restarting anything:
1. If the AppHost model, AppHost code, integrations, resource definitions, or AppHost-level configuration changed, rerun the same AppHost start command. In a git worktree, use aspire start --isolated. 2. If one resource's implementation changed, keep the AppHost running and use a resource-specific workflow. 3. If an IDE is managing debugging or hot reload, defer to the IDE and avoid overlapping Aspire CLI restart, rebuild, or watch behavior.
Use resource commands when the running AppHost already knows about the resource and only that resource needs to be operated on. Choose the resource command path that matches the resource.
For a C# project resource that exposes rebuild:
aspire resource api rebuild
aspire wait apiFor a resource that needs a process restart and does not have a better resource-specific command:
aspire resource api stop
aspire resource api start
aspire wait apiKeep these points in mind:
- Use
aspire resource <resource-name> <command>as the command shape. - Use
aspire resource <resource-name> rebuildwhen a C# project resource exposes rebuild and you need the resource to pick up compiled changes. - Use runtime or framework-native hot reload/watch for resource implementation loops when that workflow is available.
- For frontend resources, remember that frameworks such as Vite, Next.js, and similar client-side JavaScript stacks often enable hot module replacement (HMR) by default. If HMR is already applying the change through the resource's dev server, do not force a resource or AppHost restart.
- Do not restart the whole AppHost just because one resource changed or one resource needs to be rebuilt.
- Aspire default watch is controlled by
features.defaultWatchEnabled; use it for AppHost-centered CLI watch behavior, not as a replacement for resource-specific or IDE hot reload workflows.
Scenario: Something Is Wrong, But Do Not Edit Code Yet
Inspect the live app before editing code:
1. aspire describe to check resource state. 2. aspire otel logs <resource> to inspect structured logs. Add --search "<term>" to filter by keyword. 3. aspire logs <resource> to inspect console output. Add --search "<term>" to filter by keyword. 4. aspire otel traces <resource> to follow cross-service activity. Add --search "<term>" to narrow results. 5. aspire export when you need a zipped telemetry snapshot for deeper analysis or handoff.
Scenario: I Need To Add An Integration, Understand An API, Or Add A Custom Command Safely
Use integration search to find the package when needed, then use the docs commands for the workflow and the API reference commands if you need the concrete API entry:
aspire integration search postgres
aspire docs search postgres
aspire docs get <slug>
aspire docs api search postgres --language csharp
aspire docs api get <id>
aspire add <package>For dashboard or custom resource commands, use docs for the pattern and API docs for the specific entry:
aspire docs search "custom resource commands"
aspire docs get custom-resource-commands
aspire docs api search WithCommand --language csharpKeep these points in mind:
- Read the docs before editing the AppHost so the implementation follows a documented Aspire pattern instead of guessing the workflow.
- Use
aspire integration listwhen the user asks to discover available integrations before changing the AppHost, oraspire integration search <query>when the package ID is unknown. - Use
aspire docs apiwhen you need the C# or TypeScript reference entry for the exact API you are about to call. - If the AppHost is C# and you need to understand local overloads or builder chains, use the
dotnet-inspectskill if it is available after checking the Aspire API reference. - After adding an integration, restart with
aspire startso the updated AppHost takes effect.
Scenario: The AppHost Is TypeScript And Generated APIs Matter
If the AppHost is apphost.ts, the .aspire/modules/ directory contains generated TypeScript modules that expose Aspire APIs.
- Do not edit
.aspire/modules/directly. - Use
aspire add <package>to regenerate the available APIs when adding integrations. - Use
aspire restoreif.aspire/modules/disappeared after a pull, clean, or branch switch. - Inspect
.aspire/modules/aspire.tsafter regeneration or restore to see the newly available APIs.
Scenario: I Need Secrets, Deployment, Or A Playwright Handoff
Use aspire secret for AppHost user secrets, especially connection strings and passwords:
aspire secret set Parameters:postgres-password MySecretValue
aspire secret listUse aspire publish and aspire deploy for full deployment work, or aspire do <step> when the user only wants one named pipeline step such as seeding data or pushing containers.
If Playwright CLI is configured in the environment, use Aspire to discover the endpoint first and let Playwright use that discovered URL afterward. When multiple frontends exist or the URL needs to be passed to another tool, prefer aspire describe --format Json before the Playwright handoff.
App Commands
Use this when the task is about app-level lifecycle, bootstrap, or AppHost-wide maintenance.
Start The App Safely In The Background
aspire start
aspire start --isolated
aspire stop- Use
aspire startfor normal background AppHost execution. - In git worktrees or when another local instance may already be running, use
aspire start --isolated. - To restart after AppHost changes, rerun the same start command.
- Use
aspire stopwhen cleanup is explicitly requested, ports/locks need to be released, or you are finished with a started instance that the user did not ask to keep running. - Avoid
aspire runin agent workflows — it blocks the terminal.
aspire run vs aspire start
| Command | Mode | Use Case |
|---|---|---|
aspire run | Foreground (interactive) | Human developer at terminal |
aspire start | Background (detached) | AI agents — always prefer |
aspire run --detach | Background | Alternative to aspire start |
Create A New Aspire App Or Add Aspire To An Existing App
aspire new
aspire init
aspire init --language typescript- Use
aspire newwhen creating a brand-new Aspire app from scratch. - Use
aspire initwhen adding Aspire to an existing application.
After aspire init — Hand Off to aspireify
aspire init drops a minimal AppHost skeleton + AppHost configuration into the repo and installs the `aspireify` agent skill alongside it. aspire init itself does not wire resources, projects, or integrations. Hand off the wiring step to:
1. The in-plugin sibling skill: `../../aspireify/SKILL.md`, or 2. The project-local .agents/skills/aspireify/SKILL.md if aspire init installed it (project-local wins — defer to it and warn the user).
The aspireify workflow:
1. Scan the repository — discover .NET projects, Node.js apps, Python/Go services, docker-compose files 2. Present findings — confirm with user which services to include 3. Wire the AppHost — add resources using 3-tier API preference:
- Tier 1: First-party
Aspire.Hosting.*(e.g.,AddPostgres,AddRedis,AddViteApp,AddNextJsApp) - Tier 2: Community Toolkit
CommunityToolkit.Aspire.Hosting.*(e.g.,AddGolangApp) - Tier 3: Raw fallbacks (
AddExecutable,AddDockerfile,AddContainer)
4. Configure dependencies — ServiceDefaults for .NET, OTel for non-.NET 5. Validate — aspire start until all resources are healthy
Key Init Rules
- Never install the obsolete Aspire workload (
dotnet workload install aspire) - Never change the repo's .NET SDK version (don't modify root
global.json) - Never change existing project target frameworks (older TFMs work with newer AppHost)
- Always use `aspire docs search` before writing AppHost code — don't guess APIs
- Never hardcode URLs — use endpoint references (
WithReference,WithEnvironmentwith expressions) - Never overwrite existing files — augment and merge
- Adapt the AppHost to the app, not the other way around
Init Config: aspire.config.json
Read aspire.config.json at repo root for init context:
| Field | Values | Meaning |
|---|---|---|
appHost.language | "typescript/nodejs" or "csharp" | AppHost syntax to use |
appHost.path | Path to AppHost file/dir | Where to edit |
C# has two sub-modes:
- Single-file:
appHost.path→apphost.cs(uses#:sdkdirective) - Full project:
appHost.path→ directory with.csproj+Program.cs
Find The Right AppHost Or Refresh AppHost-Wide Support
aspire ps
aspire integration list --format Json
aspire integration search <query> --format Json
aspire add <package>
aspire update --self # upgrades the Aspire CLI itself (NativeAOT global tool or curl install)
aspire update # updates project package references / aspire.config.json
aspire restore- Use
aspire psfirst to discover which AppHost is already running. - Use
aspire integration list --format Jsonandaspire integration search <query> --format Jsonfor read-only integration discovery. - Use
aspire add <package>to add integrations and regenerate AppHost APIs when you are ready to mutate the AppHost. - Use `aspire update --self` to upgrade the Aspire CLI itself — the safe, no-side-effect upgrade path agents can run unattended.
- Use `aspire update` (no `--self`) to refresh AppHost package references and bump pinned versions in
aspire.config.json. This modifies project files — get user approval before running unattended (CI / agent flows). - Use
aspire restoreafter pulls, cleans, or missing generated files. - Use
--apphost <path>when the workspace has multiple AppHosts. The CLI's global config validates configured AppHost paths to catch typos early.
Key Rules
- Never install the obsolete Aspire workload (
dotnet workload install aspire). Useaspire add,aspire init, oraspire newinstead. - Never edit `.aspire/modules/` directly in TypeScript AppHosts. Use
aspire add <package>to regenerate APIs,aspire restoreif files are missing. - For unfamiliar C# AppHost APIs, use
aspire docs searchas primary reference. If thedotnet-inspectskill is available, use it to inspect local symbols and overloads — but keep docs as the source of truth. - For custom dashboard or resource commands (
WithCommand), always runaspire docs search "custom resource commands"before implementing.
Look Up API Reference Before Editing AppHost Code
aspire docs search <query>
aspire docs get <slug>
aspire docs api search <query> --language csharp
aspire docs api search <query> --language typescript
aspire docs api list <scope>
aspire docs api get <id>- Use
aspire docs searchandaspire docs getfor workflow guidance and documented patterns. - Use
aspire docs api searchwhen you need the C# or TypeScript API reference entry for a resource builder, extension method, or member. - Use
aspire docs api list <scope>to browse children under a language, package, module, type, or symbol. - Always specify
--language csharpor--language typescriptto get the correct API surface.
Detection — Recognizing Aspire Projects
Purpose: How to identify that a project uses Aspire, and which project is the AppHost.
Detection Signals
1. C# AppHost (Definitive — Strongest Signal)
Look for .csproj files containing the Aspire AppHost SDK reference:
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="10.0.0" />
<!-- ... -->
</Project>Detection method: Search for Aspire.AppHost.Sdk in .csproj files:
grep -rl "Aspire.AppHost.Sdk" --include="*.csproj" .This is the definitive signal — if a .csproj contains this SDK reference, it is an Aspire AppHost project. All Aspire CLI commands should target this project's directory.
1b. File-Based C# AppHost (Definitive)
Single-file C# AppHosts use apphost.cs (or similar .cs files) with SDK directives instead of a .csproj:
#:sdk Aspire.AppHost.Sdk
#:property IsAspireHost=true
var builder = DistributedApplication.CreateBuilder(args);
// ...Detection method: Search for apphost.cs or .cs files containing #:sdk Aspire.AppHost.Sdk:
find . -name "apphost.cs" -not -path "*/node_modules/*"
grep -rl "#:sdk Aspire.AppHost.Sdk" --include="*.cs" .File-based AppHosts are run the same way: aspire start (never dotnet apphost.cs directly).
2. TypeScript AppHost (Definitive)
Look for an apphost.ts file in the project:
find . -name "apphost.ts" -not -path "*/node_modules/*"A TypeScript AppHost uses the @aspire/apphost package and defines resources programmatically in TypeScript instead of C#.
3. .aspire/modules/ Directory (High Confidence)
Aspire generates a .aspire/modules/ directory for TypeScript AppHost support files. Its presence strongly indicates an Aspire project:
[ -d ".aspire/modules" ] && echo "Aspire project detected"4. aspire.config.json Configuration (High Confidence)
Aspire 13.2+ uses a rooted aspire.config.json file (replaces legacy aspire.json):
[ -f "aspire.config.json" ] && echo "Aspire configuration found"
# Legacy fallback:
[ -f "aspire.json" ] && echo "Legacy Aspire config found (pre-13.2)"5. .aspire/ Directory (High Confidence)
The .aspire/ directory stores Aspire settings and secrets:
[ -d ".aspire" ] && echo "Aspire settings directory found"6. Service Defaults References (Medium Confidence)
Projects that reference Aspire.ServiceDefaults are Aspire service projects (not the AppHost, but part of an Aspire solution):
grep -rl "Aspire.ServiceDefaults" --include="*.csproj" .This indicates the project is part of an Aspire solution, but these are the service projects, not the AppHost. Look for the AppHost SDK reference separately.
---
Detection Priority
When scanning a repository, check signals in this order:
| Priority | Signal | What It Means |
|---|---|---|
| 1 | Aspire.AppHost.Sdk in .csproj | This IS the AppHost — target for aspire start |
| 1b | apphost.cs or #:sdk Aspire.AppHost.Sdk in .cs | File-based C# AppHost — target for aspire start |
| 2 | apphost.ts file | TypeScript AppHost — target for aspire start |
| 3 | .aspire/modules/ directory | Aspire project — look for the AppHost |
| 4 | aspire.config.json or .aspire/ | Aspire project — look for the AppHost |
| 5 | Aspire.ServiceDefaults references | Part of Aspire solution — AppHost is elsewhere |
Finding the AppHost Directory
The Aspire CLI commands must be run from the correct context. After detecting an Aspire project:
# Find the AppHost project directory
APPHOST_DIR=$(dirname $(grep -rl "Aspire.AppHost.Sdk" --include="*.csproj" .))
# Or for file-based C# AppHost
APPHOST_FILE=$(find . -name "apphost.cs" -not -path "*/node_modules/*" | head -1)
# Or for TypeScript
APPHOST_DIR=$(dirname $(find . -name "apphost.ts" -not -path "*/node_modules/*" | head -1))Common Project Structures
Typical C# Aspire Solution
MyApp/
├── MyApp.AppHost/ ← AppHost (has Aspire.AppHost.Sdk)
│ ├── MyApp.AppHost.csproj
│ └── Program.cs
├── MyApp.ApiService/ ← Service project
│ └── MyApp.ApiService.csproj
├── MyApp.Web/ ← Frontend project
│ └── MyApp.Web.csproj
├── MyApp.ServiceDefaults/ ← Shared defaults
│ └── MyApp.ServiceDefaults.csproj
├── .aspire/
│ └── modules/ ← Aspire-generated
├── aspire.config.json
└── MyApp.slnTypical TypeScript Aspire Project
MyApp/
├── apphost.ts ← TypeScript AppHost
├── package.json
├── src/
│ ├── api/ ← Service project
│ └── web/ ← Frontend project
├── .aspire/
│ └── modules/
└── aspire.config.jsonNon-Aspire Projects
If none of the detection signals are found, this is not an Aspire project. Do not apply Aspire-specific rules. Standard .NET commands (dotnet run, dotnet build) are appropriate for non-Aspire projects.
Resource Management
Use this when the task is scoped to one resource or depends on a specific resource becoming healthy.
Wait For One Resource Before Touching It
aspire wait <resource>
aspire wait <resource> --status up --timeout 60- Use
aspire waitbefore a dependent action when readiness is the blocker. - Add
--statusand--timeoutfor explicit readiness conditions. - Treat readiness as resource-scoped — a missing ready signal is not a reason to restart the whole AppHost.
- Use
displayNamefromaspire ps --format Json, notname(#15842).
Fix Or Operate On One Resource Without Bouncing The Whole App
aspire resource <resource> start
aspire resource <resource> stop
aspire resource <resource> <command>- Prefer resource-scoped commands when the task doesn't require an AppHost-wide restart.
- If one resource is wedged, use resource-scoped commands such as
stop,start, orrebuildwhen the resource exposes them before escalating to a full AppHost restart. - Use
aspire resource <resource> <command>when the AppHost exposes resource-specific dashboard or operational commands. - If the resource's own framework watch/HMR/debug workflow is already handling the change, do not force an Aspire resource command.
What Changed Determines the Action
| What Changed | Action | Command |
|---|---|---|
| AppHost project (Program.cs, .csproj) | Full restart | aspire stop → edit → aspire start |
| .NET service project (.cs files) | Rebuild/refresh resource if exposed | aspire resource <name> rebuild or the resource's IDE/watch workflow |
| JavaScript/Python/Go files | Usually no Aspire action | File watchers/HMR handle it automatically |
| Configuration (appsettings.json) | Check first | aspire describe then decide |
| TypeScript AppHost deps | Restore | aspire restore |
Safety Guardrails — Aspire Agent Rules
Purpose: Detailed explanation of why each guardrail exists, what goes wrong when violated, and how to recover.
Why These Rules Exist
Issue #15801 documented 5 specific failures when AI agents work in Aspire projects without guidance. Every rule below directly prevents one or more of these failures.
---
Rule 1: ALWAYS aspire start — NEVER dotnet run
Why dotnet run Is Dangerous for AppHosts
The AppHost project is an orchestrator, not a regular .NET app. Running it with dotnet run:
- Bypasses the Aspire CLI orchestration layer — resources don't get managed lifecycle
- No dashboard — the Aspire developer dashboard won't launch
- No backchannel —
aspire wait,aspire logs,aspire describewon't work - No resource management — can't operate on individual resources
- Port conflicts — resources start without coordinated port allocation
- No cleanup — orphaned processes when the host exits
Correct Pattern
# ✅ Start the Aspire app
aspire start
# ✅ Verify it's running
aspire psaspire run vs aspire start
| Command | Mode | Dashboard | Use Case |
|---|---|---|---|
aspire run | Foreground (interactive) | Yes, in terminal | Human developer at terminal |
aspire start | Background (detached) | No terminal output | AI agents — always prefer this |
aspire run --detach | Background (same as start) | Yes, separate window | Alternative to aspire start |
For AI agents, always use `aspire start` — it runs in the background and returns control to the agent.
Recovery If dotnet run Was Used
# Kill the dotnet process manually (find PID first)
# Then start correctly:
aspire start---
Rule 2: ALWAYS aspire wait — NEVER curl Polling
Why curl Polling Is Wrong
Aspire tracks resource readiness internally through health checks, dependency graphs, and startup ordering. Manual HTTP polling:
- Doesn't know the correct port — Aspire assigns ports dynamically
- Doesn't respect dependency ordering — a resource may respond to HTTP before its dependencies are ready
- Creates false negatives — health endpoint may not exist or may return 503 during startup
- Wastes time — retry loops with arbitrary delays vs. event-driven readiness
Correct Pattern
# ✅ Wait for a specific resource
aspire wait apiservice
# ✅ Wait with extended timeout for slow resources
aspire wait postgres --timeout 120
# ✅ Wait then interact
aspire wait apiservice && curl $(aspire describe apiservice --format Json | jq -r '.endpoints[0].url')Machine-Readable Output
Always use --format Json when parsing output programmatically:
# ✅ Get resource endpoints as JSON
aspire describe --format Json
# ❌ Never scrape text output
aspire describe | grep "http" # fragile, format may change---
Rule 3: Prefer Resource Commands / Watch — NEVER dotnet build With Aspire Running
Why dotnet build Causes File-Lock Errors
When Aspire is running, it holds file locks on:
- Output assemblies (
.dll,.pdb) of managed resources - Build intermediates in
obj/directories - NuGet package caches being read by running processes
Running dotnet build while Aspire holds these locks produces:
error MSB3491: Could not write to output file 'bin/Debug/net10.0/MyService.dll'
error CS2012: Cannot open 'obj/Debug/net10.0/MyService.dll' for writingThe agent then concludes the project is "un-buildable" — a false conclusion.
Recovery If dotnet build Was Used and Locks Hit
When you see MSB3491 / CS2012 / "file in use" / "another process is using":
# ✅ Single correct recovery
aspire stop # release all Aspire-held locks
# Then EITHER use a resource-scoped command if Aspire is still up + one resource changed:
aspire resource <name> rebuild
# OR:
aspire start # if AppHost code changed or Aspire was fully stopped🔒 `aspire stop` is the ONLY first step. Do not pkill dotnet, do not deletebin//obj/, do not "reboot to release the lock", and do not tell the user the
project has a permanent build failure. The cause is always the same — Aspire is
holding the output files — and the fix is always aspire stop.| ❌ NEVER (file-lock recovery) | ✅ ALWAYS |
|---|---|
Say the project has a permanent build failure when you see MSB3491/CS2012 | Recognize Aspire is holding locks and run aspire stop |
pkill dotnet / kill <PID> | aspire stop (clean shutdown via the CLI) |
rm -rf bin obj to "force" the build | aspire stop, then rebuild |
| Suggest a reboot | aspire stop (single command) |
Re-run dotnet build with Aspire still up | aspire stop first; prefer resource commands/watch/HMR/debug workflow |
What Changed Determines the Action
| What Changed | Action | Command |
|---|---|---|
| AppHost project (Program.cs, .csproj) | Full restart | aspire stop → edit → aspire start |
| .NET service project (.cs files) | Rebuild/refresh resource if exposed | aspire resource <name> rebuild or the resource's IDE/watch workflow |
| JavaScript/Python/Go files | Usually no Aspire action | File watchers/HMR handle it automatically |
| Configuration (appsettings.json) | Check first | aspire describe then decide |
---
Rule 4: Use aspire stop For Cleanup — NEVER Leave Unwanted Processes Running
Why Cleanup Matters
Aspire orchestrates multiple processes (your services, databases, message brokers, etc.). Leaving them running causes:
- Port conflicts — next
aspire startfails because ports are occupied - File locks — can't build or modify service code
- Resource consumption — databases, Redis, etc. consuming memory
- Stale state — old code running while you've made changes
- Orphaned containers — Docker containers left running
Correct Pattern
# ✅ Stop when cleanup is requested or the user did not ask to keep it running
aspire stop
# ✅ Verify everything stopped
aspire ps # should show no running resourcesRecovery from Orphaned Processes
# Check if anything is still running
aspire ps
# If aspire ps shows nothing but ports are blocked:
# The previous instance may have crashed. Start fresh:
aspire start # will clean up orphaned state---
Rule 5: ALWAYS --format Json for Machine-Readable Output
Why JSON Output Matters for Agents
Text output is formatted for humans and may change between versions. JSON output is:
- Stable — structured contract unlikely to break
- Parseable —
jq, Python, or any JSON parser works - Complete — includes fields not shown in text output
Examples
# ✅ Machine-readable resource list
aspire ps --format Json
# ✅ Get specific resource details
aspire describe apiservice --format Json
# ✅ Parse with jq
aspire describe --format Json | jq '.resources[] | select(.state == "Running")'⚠️ Known JSON Output Issues
| Issue | Workaround |
|---|---|
aspire start --format json may emit human-readable text before JSON (#15843) | Strip non-JSON lines before parsing |
aspire stop does NOT support --format json yet | Use exit code for success/failure |
aspire ps --format Json returns name and displayName fields | Use displayName for aspire wait — the name field may be rejected (#15842) |
Hidden Resources and --include-hidden
aspire ps, aspire describe, and other CLI commands filter out resources marked as hidden in the AppHost (proxies, helper containers, migration jobs, etc.). This filtering is correct for normal workflows — agents and humans see only the resources they care about, not the implementation scaffolding.
Use --include-hidden when:
| Situation | Why |
|---|---|
| Debugging a proxy or sidecar | Proxies are hidden by default; you need their state to diagnose connectivity |
| Investigating helper containers | Helper containers (e.g. wait-for-it shims, init containers) are hidden |
| Tracking down migration jobs | Migration / seed jobs are typically hidden once they finish |
Expected resources are missing from aspire ps | The resource may exist but be marked hidden — confirm with --include-hidden before assuming the AppHost is wrong |
| Parsing for completeness in agent automation | A full-graph view requires explicit opt-in |
# ✅ Normal flow — filtered (correct for most tasks)
aspire ps --format Json
# ✅ Debugging / completeness — include hidden resources
aspire ps --include-hidden --format Json
aspire describe --include-hidden --format JsonIf a user reports "I can't see my proxy / migration / helper container," reach for --include-hidden before assuming the AppHost is misconfigured.
---
Rule 6: ALWAYS --non-interactive for Agent Commands
Why It Matters
AI agents run in non-interactive terminals. Some Aspire CLI commands may prompt for confirmation or input. Always pass --non-interactive to prevent hangs:
# ✅ Agent-safe commands
aspire start --non-interactive
aspire deploy --non-interactive
aspire agent init --non-interactive⚠️ Known issue: aspire agent init --non-interactive is broken in some versions (#16264, #15071). If it fails, instruct the user to run it from a standard terminal.---
Recovery Patterns Summary
| Mistake Made | Recovery Steps |
|---|---|
Used dotnet run on AppHost | Kill the process, run aspire start |
Used dotnet build and got file locks | aspire stop, wait 2s, then dotnet build or aspire start |
Used curl polling and got false results | aspire wait <resource>, then use endpoints from aspire describe |
| Left Aspire running, now ports conflict | aspire stop, then aspire start |
| Resource won't start after code change | Fix code, then use resource commands/watch/HMR/debug workflow or restart the AppHost if the AppHost model changed |
| Nothing works, environment broken | aspire doctor to diagnose, then follow recommendations |
Related skills
FAQ
What does aspire-orchestration produce?
Managed Aspire AppHost lifecycle with started resources, wait-ready endpoints, and clean stop releasing file locks.
When should I use aspire-orchestration?
When starting, stopping, waiting on, or recovering Aspire apps from file locks and port conflicts.
Is aspire-orchestration safe to install?
Review the Security Audits panel on this page before installing in production.