Skip to content

Spike: Skill-driven aspire init with unified agent skill#15918

Draft
maddymontaquila wants to merge 38 commits intomainfrom
spike/skill-driven-init
Draft

Spike: Skill-driven aspire init with unified agent skill#15918
maddymontaquila wants to merge 38 commits intomainfrom
spike/skill-driven-init

Conversation

@maddymontaquila
Copy link
Copy Markdown
Contributor

Description

Spike: Skill-driven aspire init — refactors the aspire init command from a monolithic ~980-line implementation into a thin skeleton launcher that delegates the heavy lifting to an agent skill.

What changed

New: Unified aspire-init skill (.agents/skills/aspire-init/SKILL.md)

  • One-time setup skill that completes Aspire initialization after aspire init drops the skeleton AppHost
  • Covers both TypeScript and C# AppHosts (reads appHost.language from aspire.config.json)
  • Comprehensive guidance: repo scanning, dependency wiring, ServiceDefaults, OTel setup, .env migration, docker-compose parsing
  • Guiding principles: minimize user code changes, surface tradeoffs explicitly, optimize for local dev
  • 3-tier integration preference: first-party Aspire.Hosting.* → Community Toolkit → raw fallbacks
  • AppHost wiring reference: WithReference vs WithEnvironment, endpoints/ports, dev.localhost, WaitFor/WaitForCompletion, persistent containers, explicit start, volumes
  • Self-deletes after successful aspire start

Modified: InitCommand.cs — gutted from ~980 to ~260 lines. Now drops skeleton files and triggers the skill.

Modified: CLI infrastructureSkillDefinition.cs, CommonAgentApplicators.cs, .csproj, resx/Designer.cs, xlf files updated for single unified skill.

New: Eval playground apps (playground/aspirify-eval/)

  • dotnet-traditional/: .NET LOB app (slnx, Vue frontend, ASP.NET API + Blazor admin + EF Core migrations + Postgres + Redis)
  • polyglot/: Polyglot microservices (Python FastAPI + Go HTTP + C# minimal API + React frontend + Redis)
  • EVAL-RUBRIC.md: Scoring rubric for blind agent evals (kept outside app dirs)
  • Both apps represent realistic "before Aspire" states for benchmarking the skill

Eval results

Ran blind agent evals against both apps (agents get skill but NOT rubric):

  • dotnet-traditional: 34/35 (97.1%) — perfect ServiceDefaults, WaitForCompletion, dev.localhost, all secrets parameterized
  • polyglot: 31/33 (93.9%) — full OTel for Python+Go, typed Redis, all secrets migrated, proper VITE_* env injection

Fixes #15911

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

maddymontaquila and others added 14 commits April 6, 2026 16:11
These are one-time skills that complete the Aspire initialization after
`aspire init` drops the skeleton apphost and aspire.config.json. The
agent runs the appropriate skill to scan the repo, wire up projects,
configure dependencies, and validate that `aspire start` works. The
skills self-remove on success.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add AspireInitTypeScript and AspireInitCSharp skill definitions to
SkillDefinition.cs with embedded resource roots. Add resource strings,
embed skill files in the csproj, and update the evergreen aspire skill
to reference the new init skills.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Strip InitCommand from ~980 lines to ~260 lines. Remove all solution
manipulation, template installation, project reference wiring, and RPC
scaffolding. New flow: prompt for language, detect .sln, drop bare
apphost skeleton + aspire.config.json, install the appropriate init
skill, then chain to agent init.

Also add Sparkles (dizzy 💫) to KnownEmojis.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collapse aspire-init-typescript and aspire-init-csharp into one
aspire-init skill. The unified skill handles both languages with
conditional sections — the agent reads appHost.language from
aspire.config.json to determine which path to follow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add detailed docker-compose/compose.yml scanning guidance — extract
services, images, ports, env vars, volumes, depends_on, and build
contexts. Map known images to typed Aspire integrations.

Move cert trust from a required step to a troubleshooting bullet
under validation (aspire start handles it automatically).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover WithReference vs WithEnvironment, endpoint/port patterns (env:
for non-.NET), service discovery env var naming, WithExternalHttpEndpoints,
dev.localhost domains, URL labels, WaitFor/WaitForCompletion, container
lifetimes (persistent), explicit start, parent relationships, volumes,
and aspire docs search/get workflow for looking up APIs and integrations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Establish the default stance: adapt the AppHost to the app, not vice
versa. When a small code change unlocks better integration (WithReference
vs WithEnvironment, dynamic ports, OTel endpoint), present the tradeoff
with both options and let the user decide.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clarify this skill optimizes for local dev experience, not deployment.
Recommend persistent container lifetimes, data volumes, dev.localhost
URLs. Add guidance for extracting hardcoded external service URLs into
AppHost parameters so they're visible and swappable from the dashboard.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scan for .env files during repo discovery. Classify each variable as
secret (AddParameter with secret:true), plain config (WithEnvironment),
or Aspire resource (replace with AddPostgres/AddRedis + WithReference).
Goal: eliminate .env files so all config flows through the AppHost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two pre-aspirified apps that serve as eval targets for the aspire-init
skill:

dotnet-traditional/ — .NET solution with slnx, Vue/Vite frontend,
ASP.NET API + Blazor admin + EF Core migration runner, Postgres + Redis,
.env with secrets and config. Exercises: full project mode, ServiceDefaults,
env var migration, secret parameterization.

polyglot/ — Python FastAPI + Go HTTP + C# minimal API + React frontend,
Redis cache, external API keys in .env. Exercises: TS apphost single-file,
multi-language scanning, OTel wiring, port injection, .env migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both READMEs now cover: architecture diagram, dependencies, config
table (.env vars with secret classification), step-by-step multi-terminal
setup, verification endpoints, pain points that Aspire should fix, and
expected Aspire outcome after aspirification.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Strip 'Pain points' and 'Expected Aspire outcome' from the app READMEs
(agents would use them as answer keys). App READMEs now only describe
the before-state. Eval rubric lives in EVAL-RUBRIC.md in the parent
directory with detailed pass/fail checklists for both apps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'Always use latest Aspire APIs' principle: enforce aspire docs
  search before writing any builder call, never invent APIs
- Massively expand OTel section: per-language setup for Node.js, Python,
  Go, and Java with concrete code samples; surface as user option
- Add Step 8 'Dev experience enhancements': surface dev.localhost
  friendly URLs, dashboard URL labels, and OTel as opt-in suggestions
- Renumber steps 9-11 to accommodate new step

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a 3-tier hierarchy for choosing how to model resources:
1. First-party Aspire.Hosting.* packages (always prefer)
2. CommunityToolkit.Aspire.Hosting.* packages (Go, Rust, etc.)
3. Raw AddExecutable/AddDockerfile/AddContainer (last resort)

Update the 'verify before you write' principle with concrete package
tables, discovery workflow (aspire list integrations, aspire docs
search, aspire add), and examples for both first-party and toolkit.

Update Step 4 non-.NET examples to show all 3 tiers with Go as the
community toolkit example. Update 'Looking up APIs' reference section
with aspire list integrations and toolkit add commands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15918

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15918"

maddymontaquila and others added 2 commits April 6, 2026 22:28
… sln detection

- Replace all AddProject<T>/addProject references with AddCsharpApp/
  addCsharpApp throughout skill examples (AddProject may be deprecated)
- Remove fsproj scanning (not needed)
- Make .env file deletion an explicit decision point: never auto-delete,
  always ask the user since teams may need them for non-Aspire workflows
- Strengthen sln/slnx detection: explicitly note it forces full project
  mode for Visual Studio compatibility

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace npx tsc && node pattern with 'aspire run' in package.json
  scripts, matching the canonical Aspire template pattern
- Add package manager detection step: scan for pnpm-lock.yaml,
  yarn.lock, or package-lock.json and use the matching tool throughout
- Replace hardcoded 'npm install' references with generic guidance
  that respects the repo's package manager

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@IEvangelist IEvangelist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern is what does this mean for non-AI users? Can they no longer call aspire init if they don't have an AI to use here?

maddymontaquila and others added 2 commits April 6, 2026 22:39
…clean up language

- Rewrite dev.localhost to focus on cookie/session isolation (not friendly URLs)
- Replace all AddNpmApp with AddViteApp/AddJavaScriptApp (API removed)
- Update Aspire.Hosting.NodeJs → Aspire.Hosting.JavaScript
- Add aspire describe/otel/logs to validation step for verifying wiring
- Remove 'non-.NET services' phrasing throughout
- Simplify OTel prompt language

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'Prefer HTTPS over HTTP' principle with full guidance
- Update all code samples to use WithHttpsEndpoint by default
- Add WithHttpsDeveloperCertificate for JS/Python apps throughout
- Keep WithHttpEndpoint as documented fallback when HTTPS causes issues
- Update dev.localhost examples to use 'https' endpoint names
- Note experimental status (ASPIRECERTIFICATES001)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@maddymontaquila
Copy link
Copy Markdown
Contributor Author

One concern is what does this mean for non-AI users? Can they no longer call aspire init if they don't have an AI to use here?

right now init just drops the blank apphost so itll still do that. I think we get rid of the deterministic JS stuff we are doing since it's wreaking havoc lol

maddymontaquila and others added 3 commits April 6, 2026 22:47
Co-authored-by: David Pine <david.pine@microsoft.com>
GPT-5.4 review caught that the actual C# API is AddCSharpApp (not
AddCsharpApp) and the TS equivalent is addCSharpApp. Fixed all 22
occurrences.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JamesNK
Copy link
Copy Markdown
Member

JamesNK commented Apr 7, 2026

I was literally just thinking that this was the best approach to brownfield/aspireify an app.

maddymontaquila and others added 5 commits April 6, 2026 23:20
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The language selection step (GetOrPromptForProjectAsync with
saveSelection: true) writes aspire.config.json to disk before
DropAspireConfig runs. This causes DropAspireConfig to find the
file already present and skip writing the appHost.path field.

Fix: merge into existing file instead of skipping, so the path
field is always written regardless of prior file state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Key additions based on analyzing agent vs Damian's working excalidraw
apphost:

- JS resource type decision matrix (addNodeApp vs addJavaScriptApp vs
  addViteApp) with clear signals for when to use each
- withRunScript/withBuildScript documentation with examples — critical
  for aspire publish to work with TypeScript servers
- Monorepo/workspace detection guidance in Step 1 (path resolution,
  root scripts that delegate, workspace-aware installs)
- Framework-specific port binding table (Express, Vite, Next.js, CRA)
- BROWSER=none pattern to suppress auto-browser-open
- Cross-service env var wiring examples (withEnvironment + endpoint ref)
- Never call it '.NET Aspire' — just 'Aspire'
- Dashboard URL must include auth token
- Updated main TS AppHost example with all new patterns

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix init skill flow: remove early skill install, let agent init prompt
  handle it naturally; print closing message to invoke agent
- Write profiles section to aspire.config.json with random ports matching
  aspire new templates (both https and http profiles)
- Add fallback defaults for ASPNETCORE_URLS, OTLP, and resource service
  in GuestAppHostProject when no profile provides them
- Add all polyglot skeleton templates (Python, Go, Java, Rust)
- Fix markdown linter errors (MD040, MD012) in eval READMEs
- Isolate eval playground from repo CPM with Directory.Build.props/targets
  and Directory.Packages.props

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Run 'aspire start' right after scanning to catch config/profile issues
early before investing time in project wiring. Renumber all subsequent
steps accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
maddymontaquila and others added 3 commits April 7, 2026 15:36
…UrlForEndpoint

The correct way to enable dev.localhost subdomains is to update the
applicationUrl in aspire.config.json profiles, not by calling
withUrlForEndpoint in AppHost code. This matches how 'aspire new'
handles it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The language selection step writes aspire.config.json first, so
DropAspireConfig was saying 'Updated' even on fresh repos. From the
user's perspective this is all one init flow — say 'Created'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Say 'AppHost created' instead of 'skeleton created', and print
copy-pasteable commands for GitHub Copilot, Claude Code, and OpenCode
to invoke the aspire-init skill.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@maddymontaquila maddymontaquila force-pushed the spike/skill-driven-init branch from 1ca9c05 to cf4a676 Compare April 7, 2026 19:51
maddymontaquila and others added 9 commits April 7, 2026 16:02
After validation passes, the agent prints a summary with the full
dashboard URL (including auth token) and resource health status
from aspire describe.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The agent should hand the user a fully running app with the
dashboard open, not stop it during cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'Never hardcode URLs' and 'Never use withUrlForEndpoint for
  dev.localhost' to Key Rules section
- Add new 'Never hardcode URLs — use endpoint references' guiding
  principle with ✅/❌ code examples
- Update Step 9 dev.localhost guidance with ⚠️ callout and real-world
  aspire.config.json example (separate otlp/resources subdomains)
- Clarify withUrlForEndpoint is ONLY for DisplayText, never for url.Url
- Add 'NEVER DO THIS' anti-pattern to cross-service env var wiring
- Remove http-only profile from dev.localhost example (match a3 pattern)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Only print the aspire-init handoff when the user actually selects
that one-time skill during agent init.

Also switch the follow-up from the generic placeholder command to
tool-specific commands based on the selected skill locations:
- copilot -i for Copilot skill locations
- claude with an initial prompt for Claude Code
- opencode --prompt for OpenCode

Thread the selected skill/location information back from
AgentInitCommand so init can make the follow-up conditional.
Adjust NewCommand for the updated return type and add tests for the
new init messaging behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rollup: Trackingaspire init improvements and bug fixes

3 participants