13.4: Load Aspire skills catalog from bundle manifest#17553
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17553Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17553" |
There was a problem hiding this comment.
Pull request overview
Updates aspire agent init to treat the Aspire skills bundle manifest (skill-manifest.json) as the source of truth for bundle-backed skills, so the interactive catalog doesn’t drift behind microsoft/aspire-skills.
Changes:
- Load skill definitions dynamically from the resolved Aspire skills bundle manifest and reuse that resolved bundle for installation.
- Adjust default-skill selection so standalone/
aspire newno longer preselectaspireify, whileaspire initstill does. - Update tests and localized help text to reflect dynamic bundle-backed skills plus CLI-defined skills.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Cli.Tests/TestServices/FakePlaywrightServices.cs | Extends the fake bundle manifest to include additional bundle-defined skills for test coverage. |
| tests/Aspire.Cli.Tests/Commands/NewCommandTests.cs | Updates assertions for new default-skill behavior and uses shared skill-name constants. |
| tests/Aspire.Cli.Tests/Commands/InitCommandTests.cs | Updates selection logic to find skills by name rather than static instances. |
| tests/Aspire.Cli.Tests/Commands/AgentInitCommandTests.cs | Adds/updates tests for manifest-driven skill catalog and revised defaults. |
| tests/Aspire.Cli.Tests/Agents/CommonAgentApplicatorsTests.cs | Updates tests to distinguish CLI-defined skills from bundle-defined skills. |
| tests/Aspire.Cli.Tests/Agents/AspireSkillsInstallerTests.cs | Aligns installer tests with manifest-sourced bundle skill definitions. |
| tests/Aspire.Cli.Tests/Agents/AspireSkillsBundleTests.cs | Adds coverage for enumerating manifest skills and updates existing bundle tests. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hant.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hans.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.tr.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ru.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pt-BR.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pl.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ko.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ja.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.it.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.fr.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.es.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.de.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/xlf/AgentCommandStrings.cs.xlf | Updates localized --skills help text to mention dynamic bundle skills. |
| src/Aspire.Cli/Resources/AgentCommandStrings.resx | Updates --skills option description text. |
| src/Aspire.Cli/Resources/AgentCommandStrings.Designer.cs | Updates generated resource accessor doc comment for the changed string. |
| src/Aspire.Cli/Commands/InitCommand.cs | Uses agent-init default mode that includes aspireify for the init flow and checks selection by name. |
| src/Aspire.Cli/Commands/AgentInitCommand.cs | Adds manifest-sourced skill loading, default-mode handling, and bundle reuse during install. |
| src/Aspire.Cli/Agents/SkillDefinition.cs | Removes hardcoded bundle skill entries; introduces bundle-skill factory, name checks, and name-based equality. |
| src/Aspire.Cli/Agents/AspireSkills/AspireSkillsBundle.cs | Exposes manifest skill definitions and validates manifest skill descriptions. |
Files not reviewed (1)
- src/Aspire.Cli/Resources/AgentCommandStrings.Designer.cs: Language not supported
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…navailable warning - Extract just the first sentence (after stripping the leading bold `**TYPE SKILL**` tag) for bundle skill descriptions shown in the agent init selection prompt so the list stays readable. - Sort the merged skill catalog deterministically by name (OrdinalIgnoreCase) so prompt ordering is stable regardless of manifest order. - When the Aspire skills bundle is unavailable (network failure, version mismatch, etc.), silently fall back to the CLI-defined skills instead of surfacing a user-visible warning. The installer already logs the underlying cause at debug, and the equivalent `LogWarning` paths on the corrupt-bundle catch blocks are demoted to `LogDebug` to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s range The embedded Aspire skills bundle ships inside the CLI binary as the trusted last-resort fallback, and the on-disk cache is populated by this installer itself. Both sources are gated by bundle version (the cache directory is version-keyed), so the bundle manifest's supports range should only gate fresh downloads from GitHub. Previously, a prerelease CLI build whose version fell outside the embedded snapshot's stamped range (e.g., a 13.5.x dogfood build paired with a snapshot supporting '>=13.4.0 <13.5.0') would reject the embedded bundle on every offline invocation, leaving the user with only the CLI-defined PlaywrightCli and DotnetInspect skills. Add a skipCompatibilityCheck parameter to AspireSkillsBundle.LoadAsync, plumb it through CacheArchiveAsync, and apply it to the embedded install and cache-load paths. The GitHub-download path keeps strict validation because we don't otherwise know what we're getting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The default-skill selection in agent init was driven by a two-value enum
(AgentInitSkillDefaultMode) whose IncludeAspireify member named a specific
skill. That locks the design into a named set: every time a caller needs a
different default-selection rule, the enum has to grow another member.
Replace the enum with an optional Func<SkillDefinition, bool>? predicate
parameter on AgentInitCommand.PromptAndChainAsync. Semantics:
- null -> trust the bundle author's SkillDefinition.IsDefault as-is
(what 'aspire init' wants so aspireify chains into the flow)
- non-null -> caller decides which skills are pre-selected
The 'aspireify is one-time wiring' decision moves to the two call sites
that need it ('aspire new' and standalone 'aspire agent init') via an
internal AgentInitCommand.ExcludeAspireifyFromDefaults helper method.
No new enum values are needed when future contexts emerge.
Drops the dead IsDefaultSkill helper and the enum type. No user-visible
behavior change beyond what the predicate expresses.
Tests:
- Rename PromptAndChainAsync_WithIncludeAspireifyDefault_SelectsAspireify
to PromptAndChainAsync_WithoutPredicateOverride_PreSelectsBundleDefaultsIncludingAspireify
to match the new contract (no override = trust bundle's IsDefault).
- Add PromptAndChainAsync_WithExcludeAspireifyPredicate_DoesNotPreSelectAspireify
to lock in the predicate-based override path.
- Add AgentInitCommand_NonInteractive_WithAllBundleSkillNames_InstallsEverySkillSurfacedByBundle
as a regression guard: passing every bundle skill name to --skills must
materialize all six SKILL.md files (aspire-init, aspire-monitoring,
aspire-orchestration were invisible before this PR).
- Add AgentInitCommand_NonInteractive_WithExplicitBundleSkillName_InstallsBundleSkill
proving bundle-only names are selectable via --skills now that the
catalog comes from the manifest.
- Extend the Hex1b cache fixture to seed all six bundle skills and add
AgentInitCommand_NonInteractive_WithAllSkills_InstallsEverySkillSurfacedByBundle
as a full-stack regression guard against the original report.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adding a skill to the bundle (or to the test fixture) no longer requires mirroring the change in test assertions: - Integration test now derives the skill list from the bundle's manifest via IAspireSkillsInstaller, so --skills and the install assertions are data-driven against whatever the fake produces. - Hex1b regression test now narrows to the bundle-only skill names (aspire-init/-monitoring/-orchestration) that the original bug hid. Future bundle additions don't widen this scope; the test stays a focused snapshot of the original regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… feature 13.4 ships with the GitHub bundle fetch path disabled; users get the embedded snapshot only. Setting features:aspireSkillsRemoteFetchEnabled to true re-enables the GitHub release acquisition and sigstore provenance verification path. The cache lookup and embedded fallback are unaffected, so cached bundles still load without network access. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #17553 Testing ReportPR Information
CLI Version Verification
Changes AnalyzedThe PR moves the installable skill catalog for Change categories
Test Scenarios ExecutedScenario 1 — Help text reflects the new
|
| Scenario | Status | Notes |
|---|---|---|
| 1. Help text | ✅ Passed | Stale list gone; all/none documented |
2. --skills all |
✅ Passed | 6 bundle + playwright-cli installed; dotnet-inspect correctly gated |
| 3. Bundle-only skills regression | ✅ Passed | All 3 previously-hidden skills installable by name |
4. --skills none |
✅ Passed | Clean no-op |
| 5. Unknown skill | Spectre markup leak in error; MCP applicator pollutes --skills catalog |
|
6. aspire new --suppress-agent-init |
✅ Passed | Project created, no .agents folder |
| 7. Feature flag default off | ✅ Passed | Flag registered with default: false; offline path works |
Overall Result
✅ PR FUNCTIONALLY VERIFIED — the primary fix (bundle-driven catalog so aspire-init, aspire-monitoring, aspire-orchestration are visible to --skills, the prompt, and aspire new) works as advertised, the new feature flag is in place and defaults to false, and the aspire new flow is unaffected.
Recommendations
- Address the
--skillsvalidation surface (Findings 5.1 + 5.2): excludeAgentEnvironmentApplicatoritems from the value set bound to--skills, and escape/strip Spectre markup before the validator prints labels. This regression is small but visible to any user who mistypes--skills, and it incidentally exposes a non-skill ("Install Aspire MCP server") as if it were a selectable skill name. - Optional follow-up: consider a unit test under
AgentInitCommandTeststhat drivesaspire agent init --skills <bogus> --non-interactiveand snapshots the rejection message — that would have caught both findings.
- Fix 1: SimplifyDescription only strips leading -/: when a **TYPE** prefix was actually trimmed; preserves descriptions like `-Quickly do X.` and `:memo notes`.
- Fix 2: ValidateSkillName adds explicit char.IsControl() check so U+0001..U+001F / U+0085 are rejected on Linux/macOS where Path.GetInvalidFileNameChars only returns { 0, / }.
- Fix 3: rename ExcludeAspireifyFromDefaults -> ExcludeOneTimeSetupSkillsFromDefaults backed by a single OneTimeSetupSkillNames set so future bundle bootstrap skills do not silently start auto-selecting.
- Fix 4: ResolveAvailableSkillsAsync now returns the bundle install failure message and AgentInitCommand surfaces it before MatchChoicesOrThrow when --skills names a non-CLI skill the bundle was expected to provide.
- Fix 5: ValidateSkillName also rejects empty strings, NFC-incorrect names, and Windows reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9 with or without extension) to match the PR description.
- Comment 5.1: ThrowNonInteractiveInvalidValue strips Spectre markup from each formatted choice so [[bold]]/[[dim]] tokens do not leak verbatim.
- Comment 5.2: PromptForSelectionsAsync gains an optional bindingChoices parameter; the MCP applicator (UX-only prompt item) is now excluded from --skills non-interactive validation.
Adds regression tests for the SimplifyDescription edge case and a parameterized rejection theory covering control chars, NFC, and Windows reserved names.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds two ConsoleInteractionService tests covering the rejection-message behaviors flagged by the PR testing report: - OmitsItemsOutsideBindingChoices: items present in the visible multi-select prompt but excluded from bindingChoices (e.g. the MCP applicator entry) must not appear in the non-interactive Available values list. - StripsSpectreMarkupFromChoiceLabels: [bold]/[dim] tokens from choice formatters used by the interactive prompt must be stripped before the plain-text rejection message is printed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks for the thorough write-up! Good catches on findings 5.1 and 5.2, but worth flagging that both were actually addressed in commit
Took the optional follow-up too —
If you'd like an additional |
…romptAsync rename Per davidfowl's review: we own the Aspire skills bundle and write its contents, so the defense-in-depth ValidateSkillName check is modelling the wrong threat. Drop the validator, its helpers, the reserved-device list, the now-unused System.Text using, and the unit tests that exercised it. Also rename the AgentCommandTests call site of WaitForSuccessPromptFailFastAsync to WaitForSuccessPromptAsync to match the consolidated helper that landed on main in #17588 (the FailFast variant was folded back into the canonical WaitForSuccessPromptAsync). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/backport to release/13.4 |
|
Started backporting to |
|
@IEvangelist backporting to git am output$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch
Applying: Load Aspire skills catalog from bundle manifest
Using index info to reconstruct a base tree...
M src/Aspire.Cli/Commands/AgentInitCommand.cs
M src/Aspire.Cli/Resources/AgentCommandStrings.Designer.cs
M src/Aspire.Cli/Resources/AgentCommandStrings.resx
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.cs.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.de.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.es.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.fr.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.it.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ja.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ko.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pl.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pt-BR.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ru.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.tr.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hans.xlf
M src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hant.xlf
M tests/Aspire.Cli.Tests/Commands/AgentInitCommandTests.cs
M tests/Aspire.Cli.Tests/Commands/NewCommandTests.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Aspire.Cli/Commands/AgentInitCommand.cs
CONFLICT (content): Merge conflict in src/Aspire.Cli/Commands/AgentInitCommand.cs
Auto-merging src/Aspire.Cli/Resources/AgentCommandStrings.Designer.cs
Auto-merging src/Aspire.Cli/Resources/AgentCommandStrings.resx
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.cs.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.de.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.es.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.fr.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.it.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ja.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ko.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pl.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.pt-BR.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.ru.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.tr.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hans.xlf
Auto-merging src/Aspire.Cli/Resources/xlf/AgentCommandStrings.zh-Hant.xlf
Auto-merging tests/Aspire.Cli.Tests/Commands/AgentInitCommandTests.cs
Auto-merging tests/Aspire.Cli.Tests/Commands/NewCommandTests.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Load Aspire skills catalog from bundle manifest
Error: The process '/usr/bin/git' failed with exit code 128 |
Bundle-sourced skills (aspire, aspireify, aspire-deployment, aspire-init, aspire-monitoring, aspire-orchestration) are now uniformly pre-selected in the agent-init install prompt instead of respecting per-skill IsDefault from the manifest. The CLI is the source of truth for the installable catalog; bundle authors no longer opt in per skill via the manifest. ExcludeOneTimeSetupSkillsFromDefaults continues to strip aspireify from 'aspire new' and standalone 'aspire agent init' flows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
joperezr
left a comment
There was a problem hiding this comment.
LGTM — really solid work. Code is well-structured, comments explain the why in all the right places, and test coverage is broad (loved the SimplifyDescription theory and the CliDefinedSkillsWinBundleNameCollisions regression). Left one tiny non-blocking nit about log level on the bad-asset path; take it or leave it.
@IEvangelist could you also port this to release/13.4? The feature flag default reads as "the 13.4 default" so it would be good to actually have it in that branch.
|
❓ CLI E2E Tests unknown — 109 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26651247059 |
…ls catalog Documents the changes from microsoft/aspire#17553: - Skills catalog is now loaded from the bundle manifest (skill-manifest.json) instead of a hardcoded list, exposing previously invisible bundle-only skills (aspire-init, aspire-monitoring, aspire-orchestration). - Clarifies which skills come from the bundle vs. from the CLI directly. - Documents the aspireify pre-selection difference between aspire init and aspire new. - Documents the aspireSkillsRemoteFetchEnabled feature flag (default off) and the bundle resolution order (cache → GitHub release → embedded snapshot). - Updates --skills option description to list valid bundle and CLI skill names. - Adds examples for installing bundle-only skills and enabling remote fetch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Pull request created: #1125
|
|
📝 Documentation has been drafted in microsoft/aspire.dev#1125 targeting Updated Note This draft PR needs human review before merging. |
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #17551.
Summary
aspire agent initbuilds its installable skill catalog from a hardcodedSkillDefinition.Alllist that only knew about three bundle skills (aspire,aspireify,aspire-deployment). The publishedmicrosoft/aspire-skillsbundle currently ships six skills, soaspire-init,aspire-monitoring, andaspire-orchestrationwere silently invisible to the CLI prompt and to--skills. Future bundle-only additions had the same problem.This PR makes the bundle manifest the source of truth for bundled Aspire skill names, descriptions, defaults, language filters, and install exclusions, and keeps CLI-owned definitions only for skills that don't live in the bundle (
playwright-cli,dotnet-inspect).What changed
AspireSkillsBundle.GetSkillDefinitions()projects every skill fromskill-manifest.jsoninto installableSkillDefinitionentries — bundle-derived defaults, applicable languages, and install excludes flow through automatically.AgentInitCommandresolves the bundle before the skill prompt, merges the bundle-derived catalog with CLI-local static skills, and reuses the same resolved bundle for installation so we don't acquire/validate the bundle twice. CLI-local skills win on name collisions.--skillshelp text no longer claims a stale hardcoded list and documentsall/none.AgentInitCommand.PromptAndChainAsyncnow takes an optionalFunc<SkillDefinition, bool>so callers express policy as data, not a hardcoded enum. The static helperExcludeOneTimeSetupSkillsFromDefaultsis backed by a singles_oneTimeSetupSkillNamesset, so adding a future wiring/bootstrap-style bundle skill is a one-liner instead of an invisible behavior change.aspireifyis preselected only when the workspace was just created byaspire init;aspire newalready produced the skeleton, so preselectingaspireifywould be redundant.**{TYPE} SKILL**marker), and the displayed catalog is sorted alphabetically for determinism. The leading-separator strip only runs when a**TYPE**prefix was actually trimmed, so descriptions like-Quickly do X.keep their leading character.playwright-clianddotnet-inspect. The previous warning is demoted toLogDebug. When the caller passes--skillsand names a non-CLI skill the bundle was expected to provide, the install failure is surfaced before the catalog-rejection error so the underlying cause isn't hidden behind a generic "value not in choices" message.--skills—PromptForSelectionsAsyncnow accepts an optionalbindingChoicessubset, and the unified prompt restricts non-interactive validation to the actualSkillDefinitioncatalog. The non-interactive "value not in choices" error also strips Spectre markup so[bold]/[dim]tokens don't leak verbatim into the error output.AgentCommandStrings.resx(with matching.xlfregen). ThrownInvalidOperationExceptions remainCultureInfo.InvariantCulture-formatted per the existing pattern in this area./,\,.,..,Path.GetInvalidFileNameChars(), or anychar.IsControlcharacter (covers U+0001–U+001F + C1 controls on Linux/macOS whereGetInvalidFileNameCharsis only{ \0, / }), and Windows reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9, with or without extension) are rejected. Prompt markup is escaped; duplicate skill-name detection is case-insensitive.Feature flag —
aspireSkillsRemoteFetchEnabled(default off)The GitHub release fetch path is now gated behind a new
features:aspireSkillsRemoteFetchEnabledtoggle (inKnownFeatures). 13.4 ships with this disabled, so out of the boxaspire agent initonly uses the cached bundle and the embedded.tgzsnapshot baked into the CLI build. No network call goes out togithub.com/microsoft/aspire-skillsunless the user explicitly opts in.Opt in with:
When the flag is on, the resolution order stays cache → GitHub release → embedded snapshot (with sigstore provenance verification on the GitHub asset). When the flag is off, the order is cache → embedded snapshot. Cached bundles still work in both modes because the cache lookup runs before the flag check. This gives us a kill switch we can flip later (or per user) without shipping new CLI bits, and lets 13.4 ship the surface-area fix while we settle the remaining trust-and-distribution questions in the separate threat-model review.
Bundle versioning — how this works in practice
The CLI pins a single
microsoft/aspire-skillsversion (AspireSkillsInstaller.Version = "0.0.1") and resolves bundles in order: versioned cache → GitHub release tagged with that version (if remote fetch is enabled) → embedded snapshot. Caches are version-keyed, so old versions self-evict after 7 days.When
microsoft/aspire-skillsships a new release, the existing scheduled workflowupdate-aspire-skills-bundle.yml(runs daily at 17:00 UTC and on-demand) handles the coordinated update viaeng/scripts/update-aspire-skills-bundle.ps1:Versionconstant, refreshes the embedded.tgzsnapshot + metadata, and updates the SHA-256 inAspire.Cli.csproj.AspireSkillsInstallerTests,AspireSkillsBundleTests, andAgentInitCommandTestsagainst the new bundle.[Automated] Update Aspire skills bundle).After that PR merges and ships in a new CLI build, users on the new CLI transparently pick up the new bundle — including any new skills the bundle adds, because the catalog is now driven by the manifest rather than a hand-maintained list. Users on older CLIs continue requesting the version they were built against.
Tests
AgentInitCommand_NonInteractive_AllBundleSkills_AreInstallableByName(integration): primes the bundle throughIAspireSkillsInstaller, derives the skill list frombundle.GetSkillDefinitions(), and uses that same list for both--skillsand the install assertions. Adding/removing a skill in the fake fixture (or the real bundle) requires no edits to the test body.AgentInitCommand_NonInteractive_BundleOnlySkillsBeyondCliCatalog_AreInstallable(Hex1b end-to-end): focused regression guard for the three bundle-only names the original bug hid (aspire-init,aspire-monitoring,aspire-orchestration). Future bundle additions are intentionally out of scope so this stays a stable snapshot of the original regression.InstallAsync_WhenRemoteFetchFeatureIsDisabled_SkipsGitHubAndUsesEmbeddedandInstallAsync_WhenRemoteFetchFeatureIsDisabledAndCacheExists_UsesCacheWithoutNetwork: assert the new feature flag never reaches the network when off (HTTP handler throws on any call; attestation verifier asserted never called).LoadAsync_ThrowsWhenSkillNameIsUnsafe(theory): parameterized rejection cases for control characters, non-NFC names, and Windows reserved device names (CON, CON.md, nul, LPT3, ...).SimplifyDescription_ProducesExpectedSummary: regression cases for descriptions that start with-or:without a**TYPE**prefix — the leading separator is preserved.--skills all, explicit bundle skill selection, unavailable-bundle fallback behavior, andaspire initvsaspire newdefault selection.All
AgentInitCommandTests(34/34),AspireSkillsBundleTests, andAspireSkillsInstallerTestspass locally; fullAspire.Cli.Testssuite green except for one unrelated, pre-existing Windows\r\nflake inListConsoleLogsToolTests.ListConsoleLogsTool_ReturnsLogs_ForSpecificResource.Manual verification
Installed the PR build, deleted the local skills cache, and disconnected the network —
aspire new(with AI = Y) still surfaces the full catalog from the embedded snapshot. Previously the disconnected path silently dropped to justplaywright-clianddotnet-inspect.