Is your feature request related to a problem? Please describe
Issue #17615 reported that aspire ls was silently writing aspire.config.json to the working tree on first invocation in workspaces that contained a legacy .aspire/settings.json. PR #17631 (L1 fix) addresses the silent write by removing the eager migration from ConfigurationHelper.RegisterSettingsFiles — migration is now deferred to commands that already mutate the workspace (aspire run/add/init/update/pipeline via ProjectLocator.CreateSettingsFileAsync → AspireConfigFile.LoadOrCreate).
This is the correct fix, but it leaves a small gap (originally raised in #15488): a user who runs only read-only commands (aspire ls, aspire ps, aspire doctor, aspire --version, etc.) will stay on the legacy layout indefinitely with no signal that a newer format exists. The legacy file continues to work — AppHostPathConfigurationPolicy.TryFindAppHostPathKey accepts both the legacy flat appHostPath and the modern hierarchical appHost:path keys — so nothing is broken, but the user never gets the prompt to move forward.
Describe the solution you'd like
Have aspire doctor detect the legacy layout and surface a one-time informational hint:
ℹ️ Legacy .aspire/settings.json detected at /path/to/workspace/.aspire/settings.json.
Run `aspire init` (or any aspire run/add/update command) to migrate to aspire.config.json.
The legacy file continues to work — this is informational only.
aspire doctor is already a diagnostic/advisory surface (no side effects, presents check results to the user), so a migration-readiness check fits naturally without violating the read-command contract that motivated #17615.
Implementation notes
- Add a new doctor check that detects the presence of
.aspire/settings.json without a sibling aspire.config.json at the workspace root (use ConfigurationHelper.FindNearestConfigFilePath + GetLegacySettingsRootDirectory for the existing detection helpers).
- Surface as informational (not warning), since the legacy file is fully supported.
- Do not write anything from doctor — that would re-introduce the L1 bug class on a different command.
Alternatives considered
- Print the hint at the bottom of
aspire ls output when a legacy file is detected — also viable, but aspire ls is meant to be parser-friendly (especially in --format json mode), so adding free-form footer text risks regressing scripts.
- Add an explicit
aspire migrate command — heavier; redundant with the existing fact that any write command already migrates.
Additional context
Is your feature request related to a problem? Please describe
Issue #17615 reported that
aspire lswas silently writingaspire.config.jsonto the working tree on first invocation in workspaces that contained a legacy.aspire/settings.json. PR #17631 (L1 fix) addresses the silent write by removing the eager migration fromConfigurationHelper.RegisterSettingsFiles— migration is now deferred to commands that already mutate the workspace (aspire run/add/init/update/pipelineviaProjectLocator.CreateSettingsFileAsync→AspireConfigFile.LoadOrCreate).This is the correct fix, but it leaves a small gap (originally raised in #15488): a user who runs only read-only commands (
aspire ls,aspire ps,aspire doctor,aspire --version, etc.) will stay on the legacy layout indefinitely with no signal that a newer format exists. The legacy file continues to work —AppHostPathConfigurationPolicy.TryFindAppHostPathKeyaccepts both the legacy flatappHostPathand the modern hierarchicalappHost:pathkeys — so nothing is broken, but the user never gets the prompt to move forward.Describe the solution you'd like
Have
aspire doctordetect the legacy layout and surface a one-time informational hint:aspire doctoris already a diagnostic/advisory surface (no side effects, presents check results to the user), so a migration-readiness check fits naturally without violating the read-command contract that motivated #17615.Implementation notes
.aspire/settings.jsonwithout a siblingaspire.config.jsonat the workspace root (useConfigurationHelper.FindNearestConfigFilePath+GetLegacySettingsRootDirectoryfor the existing detection helpers).Alternatives considered
aspire lsoutput when a legacy file is detected — also viable, butaspire lsis meant to be parser-friendly (especially in--format jsonmode), so adding free-form footer text risks regressing scripts.aspire migratecommand — heavier; redundant with the existing fact that any write command already migrates.Additional context
aspire lsbugs from #17620 (L1–L5) #17631 — specifically the L1-removal-of-eager-migration tradeoff.aspire.config.jsonis not created. #15488 (original eager-migration design intent), [bug] aspire ls silently writes aspire.config.json by migrating legacy .aspire/settings.json (introduced by #17408) #17615 (silent-write bug fixed by Fix fiveaspire lsbugs from #17620 (L1–L5) #17631), Clean up legacy CLI configuration file support (settings.json, apphost.run.json, globalsettings.json) #15239 (long-term legacy reader removal).