关于 aspire-orchestration
aspire-orchestration 是面向 Aspire 项目的 Agent 技能,指导 AppHost 与资源的启动、停止、等待和检查,并设有针对文件锁、目标选择及破坏性操作的安全规则。
主要功能
- 01管理 AppHost 启停流程
- 02等待并检查资源状态
- 03支持资源级操作指导
- 04限制不安全的停止操作
- 05处理多 AppHost 目标选择
适用场景
- 01启动或停止指定 AppHost
- 02等待资源就绪后开展操作
- 03检查运行中的 AppHost 与资源
- 04在工作树中隔离启动应用
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ aspire-skills --skill aspire-orchestration安装后在 Claude Code 中输入/aspire-orchestration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/eval.yamlreferences/agent-workflows.mdapp-commands.mddetection.mdresource-management.mdsafety-guardrails.md详细介绍
Aspire 编排
强制合规 — 此技能可防止 Agent 在 Aspire 项目中伤害自身。 违反这些规则会导致文件锁定、进程孤立和用户沮丧(#15801)。
先决条件
| 要求 | 安装方式 |
|---|---|
| .NET 10.0 SDK | https://dotnet.microsoft.com/download |
| Aspire CLI(curl/PowerShell) | curl -sSL https://aspire.dev/install.sh | bash |
| Aspire CLI(npm) | npm install -g @microsoft/aspire-cli |
| Aspire CLI(NativeAOT 全局工具,.NET 10) | dotnet tool install -g Aspire.Cli |
使用适用于用户环境的安装方式。除 NativeAOT .NET 全局工具外,还支持 npm、Nix、Homebrew、WinGet、mise 和安装脚本。
检测
出现以下任意信号时激活:
| 信号 | 检测方式 | 置信度 |
|---|---|---|
| C# AppHost | .csproj 包含 Aspire.AppHost.Sdk | ✅ 确定 |
| 基于文件的 C# AppHost | 项目中存在 apphost.cs 或包含 #:sdk Aspire.AppHost.Sdk 的 .cs 文件 | ✅ 确定 |
| TypeScript AppHost | 项目中存在当前的 apphost.mts 文件或旧版 apphost.ts 文件 | ✅ 确定 |
| Aspire 配置 | 项目根目录中存在 aspire.config.json | 高 |
| Aspire 设置 | 存在 .aspire/ 目录 | 高 |
| 生成的 TS 模块 | 存在 .aspire/modules/ 目录 | 高 |
| 服务默认值 | 项目引用中包含 Aspire.ServiceDefaults | 中 |
详细指纹识别方法请参阅 detection.md。
VS Code AppHost 生命周期
当 Agent 宿主提供 aspire_apphost_start 或 aspire_apphost_stop 时,在终端中运行 aspire start 或 aspire stop 之前,应使用对应的工具;但从 git worktree 启动且该工具无法请求 --isolated 时除外。如果该工具被列为延迟加载,请先使用宿主的工具发现机制加载其契约;不要将尚未加载的延迟工具视为不可用。
将 Aspire 检测到的准确 appHostPath 传递给编辑器生命周期工具。在多根工作区中,该工具契约可能要求使用如下选择器:repo-a~1/MyApp.AppHost/MyApp.AppHost.csproj。
CLI 的 --apphost 标志无法识别该选择器命名空间。在使用 CLI 作为启动/停止的后备方案之前,先将选定的 AppHost 解析为其实际文件系统项目路径,并将该路径传递给 --apphost;切勿原样复制多根选择器。该 CLI 项目路径可以是相对于工作区的路径(MyApp.AppHost/MyApp.AppHost.csproj),也可以是绝对路径(/workspaces/repo-a/MyApp.AppHost/MyApp.AppHost.csproj 或 C:\workspaces\repo-a\MyApp.AppHost\MyApp.AppHost.csproj);请使用当前平台的原生路径语法。如果检测到多个 AppHost,且无法确定用户的目标,应询问用户要使用哪一个,不要猜测、对每个 AppHost 都调用工具,也不要执行未限定范围的 CLI 命令。
如果选定的 appHostPath 已经是普通的相对于工作区的项目路径,例如 MyApp.AppHost/MyApp.AppHost.csproj,CLI 后备调用时应原样复用;不要仅为 CLI 将其转换为绝对路径。
目标不明确时必须停止。 提出一个澄清问题,并等待用户指定 AppHost。在目标确定之前,不要调用生命周期工具或终端命令,也不要提供绕过此门槛的命令。仅当用户明确要求启动/停止所有 AppHost 时,才对多个 AppHost 执行操作。
启动时,除非用户明确要求附加调试器,否则应使用模式 run 和准确的选定 appHostPath 调用 aspire_apphost_start。在 git worktree 中,编辑器工具目前不会请求 Aspire 的隔离状态。请将选定的 AppHost 解析为其文件系统路径,并改用 aspire start --non-interactive --isolated --apphost <filesystem-path>。
run 模式不会附加调试器,但仍会创建由编辑器管理、可通过 aspire_apphost_stop 停止的 Aspire 会话。调用停止工具后,请严格遵循以下结果矩阵:
| 工具结果 | 后续操作 | 是否允许停止 CLI? |
|---|---|---|
stopped 或 notRunning | 报告结果;不再执行停止操作 | 否 |
alreadyStopping,控制器为 editor | 报告编辑器中的停止操作已在进行;不再执行停止操作 | 否 |
alreadyStarting,控制器为 editor | 重试一次 aspire_apphost_stop;若再次出现此结果,报告启动仍在进行,且不再执行停止操作 | 否 |
notEditorOwned,控制器为 external | 如果用户要求停止该确切的 AppHost,将其解析为文件系统路径,并运行 aspire stop --non-interactive --apphost <filesystem-path> | 是 |
failed,控制器为 unknown | 重试一次 aspire_apphost_stop;若再次出现相同结果,则使用上述针对确切目标的 CLI 命令 | 仅在重试后 |
ambiguousSession | 不停止任何内容,让用户在编辑器中消除歧义 | 绝不允许 |
| 任何其他拒绝或失败 | 解析或报告该结果;不要更换操作方式 | 否 |
这些行互斥。只根据当前结果采取操作;不要把其他行中的命令作为推测性的后备方案提供。只有在返回新的工具结果后,才重新评估。
ambiguousSession 是终止性的安全拒绝。 不要运行或提供 CLI 后备方案,也不要询问用户是否需要。用户确认无法让通过 CLI 终止有歧义的编辑器会话变得安全。
只有在对应的编辑器工具不可用、针对隔离工作树启动,或停止结果明确标记为允许时,才直接使用 Aspire CLI 生命周期命令。 允许使用 CLI 后备方案时,先将选定的 AppHost 解析为文件系统路径,以确保目标明确。
安全防护规则
| 情况 | ✅ 始终执行 | ❌ 绝不执行 |
|---|---|---|
| 启动 Aspire 应用 | 在可用时,使用 aspire_apphost_start,模式设为 run,并指定确切的 appHostPath;在 git 工作树中,即使 aspire_apphost_start 可用,也要使用 aspire start --non-interactive --isolated --apphost <filesystem-path> | 对 AppHost 运行 dotnet run |
| 等待资源就绪 | aspire wait <resource> | curl / HTTP 轮询循环 |
| 资源中的代码已更改 | 优先使用资源命令、运行时监视/HMR、仪表板操作或 IDE 管理的调试 | 对锁定文件运行 dotnet build |
| 任务完成 | 在可用时,使用 aspire_apphost_stop 并指定确切的 appHostPath;遵循其结果判定表 | 使用未经批准的 CLI 后备方案 |
| 检查正在运行的 AppHost | aspire ps | 手动检查进程 |
| 检查资源状态 | aspire describe | aspire ps --resources(已在 13.5 中移除) |
| 移除持久化资源 | 确认数据丢失风险和确切的 AppHost,再运行 aspire stop --force --apphost <filesystem-path> | 将 --force 与 --all 组合使用,或将其用于普通停止 |
| 在 git 工作树中操作 | aspire start --non-interactive --isolated --apphost <filesystem-path> | 在无法请求隔离时使用 aspire_apphost_start |
| 从 AI Agent 运行 | 先加载可用的生命周期工具;将 CLI --apphost 后备方案解析为 <filesystem-path>;添加 --non-interactive | 假设存在交互式终端 |
| 编辑不熟悉的 API | 先运行 aspire docs search <topic>,然后运行 aspire docs api search <query> 查找 API 参考 | 猜测 API 形式 |
| 检查 C# AppHost API | 使用 dotnet-inspect 技能(如可用)检查本地符号 | 猜测重载或构建器链 |
| 添加自定义仪表板/资源命令 | 先运行 aspire docs search "custom resource commands" | 未查阅文档就编造 WithCommand 模式 |
| 安装 Aspire 支持 | 使用 aspire add 或 aspire init | dotnet workload install aspire |
详细规则和恢复模式请参阅 safety-guardrails.md。
默认工作流
- 确认工作区是 Aspire — 找出 AppHost
- 如果工作区是 git worktree,将选定的 AppHost 解析为文件系统项目路径,并使用
aspire start --non-interactive --isolated --apphost <filesystem-path>,即使aspire_apphost_start可用也如此,因为编辑器工具无法请求隔离模式。否则,如果aspire_apphost_start可用,则使用run模式启动,并在可用时传入准确选定的appHostPath;如果该工具不可用,则将选定的 AppHost 解析为文件系统项目路径,并使用aspire start --non-interactive --apphost <filesystem-path> - 与任何资源交互前,先运行
aspire wait <resource> - 使用
aspire describe检查状态,然后开展工作 - 如果 AppHost 代码发生更改,则通过相同的生命周期路由重启;如果只更改了一个资源,则优先使用该资源的命令、监视、HMR 或调试工作流
- 使用
aspire_apphost_stop停止,并在可用时传入准确选定的appHostPath;仅在文档说明的回退情况下使用aspire stop --non-interactive --apphost <filesystem-path>
快速参考
| 任务 | 命令 |
|---|---|
| 启动应用(Agent) | Git worktree:使用 aspire start --non-interactive --isolated --apphost <filesystem-path>,即使 aspire_apphost_start 可用也如此,因为该工具无法请求隔离模式。否则:使用 aspire_apphost_start(run 模式,传入准确选定的 appHostPath);如果该工具不可用,则回退到 CLI:aspire start --non-interactive --apphost <filesystem-path> |
| 启动应用(人工) | aspire run(前台运行,打开仪表板) |
| 停止应用 | aspire_apphost_stop(传入准确选定的 appHostPath);结果矩阵回退:aspire stop --non-interactive --apphost <filesystem-path> |
| 等待资源 | aspire wait <resource> |
| 列出正在运行的 AppHost | aspire ps |
| 检查资源状态 | aspire describe |
| 显示隐藏资源(代理、辅助程序、迁移) | aspire describe --include-hidden |
| 资源操作 | aspire resource <resource-name> <command>,例如使用可用的 stop、start 或 rebuild |
| 发现资源命令 | aspire resource <resource-name> --help |
| 连接到实验性资源终端 | 启用 features.terminalCommandsEnabled,然后使用 aspire terminal ps / aspire terminal attach |
| 创建新项目 | aspire new aspire-starter |
| 将 Aspire 添加到现有项目 | aspire init(然后移交给 aspireify 技能进行配置) |
| 添加集成 | aspire add <package> |
| 发现集成 | aspire integration list --format Json / aspire integration search <query> --format Json |
| 升级 CLI 本身 | aspire update --self(托管安装可能会打印 npm/.NET/Nix 更新命令) |
| 更新项目包引用 | 获得批准后运行 aspire update --yes --non-interactive |
| 迁移旧版 TypeScript 入口点 | 说明包引用、配置、tsconfig、导入和入口点都会更改;获得包更新和迁移的批准后,运行 aspire update --migrate --yes --non-interactive |
| 还原生成的文件 | aspire restore |
| 环境维护 | aspire cache clear、aspire certs trust、aspire certs clean |
| 诊断环境 | aspire doctor |
| 机器可读输出 | --format Json(支持:ps、describe、start) |
| 查找 API 参考 | aspire docs api search <query> --language csharp|typescript |
| 浏览 API 条目 | aspire docs api list <scope> |
| 获取 API 详情 | aspire docs api get <id> |
错误处理
| 症状 | 原因 | 操作 |
|---|---|---|
构建期间出现文件锁错误(MSB3491、CS2012) | Aspire 正在运行,并锁定了 bin/、obj/ 和程序集。 | 通过上述生命周期路由停止 AppHost,然后重新构建或重启。不要因此认定项目存在永久性构建故障。 |
| “端口已被占用” | 上一个实例仍在运行 | 停止,然后通过上述生命周期路由重启 |
| 找不到资源 | App 尚未启动或名称错误 | 使用 aspire ps 查找 AppHost,然后使用 aspire describe 检查资源 |
| 资源中的构建错误 | 代码错误,而非 Aspire 问题 | 修复代码,然后使用资源命令/监视/HMR/调试工作流;如果 AppHost 代码已更改,则通过生命周期路由重启 |
| 环境问题 | 缺少 SDK 或工具 | 使用 aspire doctor 进行诊断 |
aspire start 的 JSON 解析失败 | 混杂了人类可读输出和 JSON 输出(#15843) | 解析前剔除非 JSON 行 |
aspire ps 卡住 | AppHost 停在断点处(#15576) | 使用超时,检查 AppHost 进程 |
aspire agent init 失败 | 终端为非交互模式(#16264) | 在标准终端中运行 |
| Docker 守护进程不可用 | 容器支持的资源无法启动 | 启动 Docker Desktop,然后通过上述生命周期路由重启 |
| 检测到多个 AppHost | 目标 AppHost 错误 | 使用 --apphost <filesystem-path> 显式指定 |
🔒 文件锁恢复(MSB3491 / CS2012)——务必先停止 AppHost
当构建因 error MSB3491: Could not write to output file ... 或
error CS2012: Cannot open ... for writing 而失败时,项目本身没有问题——
Aspire 正在运行,并锁定资源的输出程序集。
恢复方法始终相同:
如果可用,先解析出确切的 AppHost 并调用 aspire_apphost_stop。如果允许使用 CLI
回退方案,先将选定的 AppHost 解析为其文件系统路径,再使用
以下命令;ambiguousSession 和所有其他无回退结果都会终止恢复尝试。
# ✅ CLI stop only after the result matrix permits fallback
aspire stop --non-interactive --apphost <filesystem-path> # 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 through aspire_apphost_start. If unavailable:
aspire start --non-interactive --apphost <filesystem-path>
# In a git worktree:
aspire start --non-interactive --isolated --apphost <filesystem-path>
| ❌ 切勿这样做 | ✅ 务必这样做 |
|---|---|
| 告诉用户项目存在永久性构建故障 | 识别出是 Aspire 锁定了输出文件,并通过生命周期路由停止 AppHost |
在文件仍被锁定时再次运行 dotnet build | 先停止 AppHost,再运行 dotnet build(或优先使用资源命令/监视/HMR/调试工作流) |
删除 bin/ / obj/ 来“修复”锁定问题 | 停止 AppHost;删除操作可能成功,但下次构建时仍会再次锁定 |
使用 pkill dotnet 或 kill <PID> 释放锁 | 使用编辑器的停止工具,或使用精确目标的 CLI 回退方案,以正常关闭 |
| 告诉用户“重启”或“重启电脑” | 通过生命周期路由停止 AppHost |
同一规则也适用于构建 Aspire 管理的资源时出现的任何“文件正在使用”“无法访问文件”或 “另一个进程正在使用”错误。
移交规则
| 场景 | 移交至 |
|---|---|
aspire init 之后配置 AppHost(扫描代码仓库、添加资源、配置 ServiceDefaults/OTel) | → aspireify 技能(aspireify/SKILL.md)或项目本地的 .agents/skills/aspireify/SKILL.md |
浏览器日志(Aspire.Hosting.Browsers / WithBrowserLogs())和仪表板编写 | → aspireify 技能(代码编辑)和 aspire-monitoring(发现) |
自定义资源命令、参数、交互或终端(WithCommand、CommandOptions.Arguments、IInteractionService、WithTerminal) | → aspireify 技能 |
生命周期钩子(SubscribeBeforeStart、SubscribeAfterResourcesCreated、BeforeStart 管道阶段) | → aspireify 技能 |
端点编写(更新 WithEndpoint、ExcludeReferenceEndpoint 标志) | → aspireify 技能 |
部署、发布、管道步骤、aspire destroy | → aspire-deployment 技能 |
日志、跟踪、指标、仪表板、aspire dashboard run | → aspire-monitoring 技能 |
| 已部署应用的诊断 | → azure-diagnostics 技能(azure-skills) |
运行时设置与环境
| 变量 | 默认值 | 用途 |
|---|---|---|
ASPIRE_ENABLE_CONTAINER_TUNNEL | true | 容器隧道可在 Docker Desktop、Docker Engine 和 Podman 之间提供统一的主机连接。设为 false 可选择退出。 |
ASPIRE_ENVIRONMENT | 未设置 | 选择特定于环境的配置文件——控制加载哪个 appsettings.{environment}.json,以及在仪表板遥测中报告哪个环境。 |
ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE | true | DCP 在 Windows 上使用 Aspire 受信任的开发人员证书。设为 false 可选择退出。 |
features.defaultWatchEnabled | 除非配置,否则为 false | 为受支持的 C# 和 TypeScript AppHost 启用 Aspire 默认监视。不要将其视为针对资源源代码更改的逐资源重新生成、重启或热重载功能。 |
TypeScript AppHost 说明
检测涵盖当前的 apphost.mts 和旧版 apphost.ts,但所有 TS AppHost 编写工作都交由 aspireify 处理。由 CLI 驱动的旧版迁移属于此编排技能负责的项目维护工作,而非编写工作。请说明迁移也会更新 Aspire 包、配置、tsconfig 和导入;只有在获得完整变更的批准后,才提供 aspire update --migrate --yes --non-interactive,之后仅当仍需编写源代码时才移交给 aspireify。
移交时应遵循以下现行规则:
| 规则 | 原因 |
|---|---|
优先使用统一的 withEnvironment(name, value),而非已弃用的按类型区分的辅助方法(withEnvironmentEndpoint、withEnvironmentParameter、withEnvironmentConnectionString、withEnvironmentExpression、withEnvironmentFromOutput、withEnvironmentFromKeyVaultSecret) | 按类型区分的辅助方法已弃用——现在单一 API 可处理所有值类型 |
切勿直接编辑 .aspire/modules/ | 该目录由生成工具生成;使用 aspire add <package> 重新生成,并使用 aspire restore 恢复缺失文件 |
使用 aspire docs api search <query> --language typescript 查找 API | TS 接口与 C# 不同 |
技能路由——插件内的同级技能
aspire init 创建骨架 AppHost 和 aspire.config.json 后,将 AppHost 配置工作
(扫描代码仓库 → 提议资源图 → 编辑 AppHost → 配置 Aspire.ServiceDefaults / OTel →
通过 aspire start 验证)移交给插件内的 aspireify 技能:aspireify/SKILL.md。
对于只需创建骨架的首次运行流程,请参阅插件内的 aspire-init 技能:
aspire-init/SKILL.md。此编排技能专注于生命周期
(启动/停止/等待/重启),绝不自行编辑 AppHost 代码。
项目本地技能优先级
如果 .agents/skills/aspire/SKILL.md 存在(由 aspire agent init 创建),则在以下事项中优先遵循该文件:
编辑 C# AppHost、编辑 TS AppHost、Playwright 交接、调查工作流。
本插件的安全防护规则始终适用。
如果项目本地存在 .agents/skills/aspireify/SKILL.md(由当前版本的 Aspire 中的 aspire init 安装),请提醒用户项目本地存在 aspireify 技能,并在配置 AppHost 时优先遵循该技能,而不是本插件中的同级技能。优先级规则与上述项目本地的 aspire 技能相同:项目本地技能优先,但本插件的安全防护规则仍适用。
参考资料
- safety-guardrails.md — 详细规则和恢复模式
- detection.md — 项目指纹识别
- app-commands.md — 应用生命周期和引导命令
- resource-management.md — 资源等待、重启和操作
- agent-workflows.md — 常见的 Agent 调查、集成、TypeScript 和交接工作流