| 1 | <!-- English translation of adr/0090-launch-profiles-and-debug-startup-configurations.md. Canonical Russian: ../../adr/0090-launch-profiles-and-debug-startup-configurations.md --> |
| 2 | |
| 3 | # ADR 0090: Launch profiles and multiple debug startup configurations (VS-style) |
| 4 | |
| 5 | **Status:** Accepted · Implemented |
| 6 | **Date:** 2026-04-23 |
| 7 | |
| 8 | ## Related ADRs |
| 9 | |
| 10 | | ADR | Role | |
| 11 | |-----|------| |
| 12 | | [0002](0002-debug-human-agent-parity.md) | unified debug layer for human and agent | |
| 13 | | [0028](0028-user-settings-toml-localappdata-and-secrets.md) | user settings — `settings.toml`, `%LocalAppData%\CascadeIDE\`, secrets separate | |
| 14 | | [0029](0029-configuration-toml-canonical-ui-facade.md) | TOML-first config; holistic settings UI **deferred**; point UI is **canon facade** | |
| 15 | | [0093](0093-mfd-embedded-browser-for-launch-url.md) | embedded launch URL on MFD (extends profiles and launchBrowser) | |
| 16 | |
| 17 | ### Outside ADR |
| 18 | |
| 19 | | Document | Role | |
| 20 | |----------|------| |
| 21 | | [MCP-PROTOCOL.md](../../MCP-PROTOCOL.md) | `debug_launch` and related tools | |
| 22 | | [MsBuildDebugTargetResolver.cs](../../../Services/MsBuildDebugTargetResolver.cs) | MSBuild debug target resolver | |
| 23 | |
| 24 | ## Summary |
| 25 | |
| 26 | - **Launch profiles** and multiple debug startup configurations (as in VS). |
| 27 | - Storage, MCP, migration from `startup-project.json`. |
| 28 | - Optional URL on MFD — [0093](0093-mfd-embedded-browser-for-launch-url.md). |
| 29 | |
| 30 | --- |
| 31 | |
| 32 | ## Context |
| 33 | |
| 34 | Today **one solution** has **at most one** explicit startup project: path to `.csproj` in `.cascade-ide/startup-project.json` as single `StartupProjectRelativePath`. F5 and interactive `debug_launch` resolve **one** target; MSBuild configuration for debug is effectively **Debug** in the resolver. |
| 35 | |
| 36 | In Visual Studio and SDK projects the familiar model is **several named profiles** — different projects, configurations (Debug/Release/…), command-line args, working directory, environment variables. Developer switches “current profile” and presses F5 without resetting startup project each time. |
| 37 | |
| 38 | Without this Cascade IDE stays closer to “one start per solution”, weak for monorepos, multiple executables in one `.sln`, and “run API / console / test host” without a file dialog. |
| 39 | |
| 40 | **Web (ASP.NET Core)** is not “later”: typical portal/SPA-host solutions (including product **EDW.Portal**, scope `portal` in operational memory) depend on `Properties/launchSettings.json`: Kestrel **URLs**, `ASPNETCORE_ENVIRONMENT`, sometimes `launchBrowser`, profiles (`http` / `https` / IIS). Without mapping these fields into DAP launch (process env + host args if needed) F5 in CIDE **will not** match familiar `dotnet run` / VS. Console exe is a subset; **web is mandatory** v1 horizon per this ADR. |
| 41 | |
| 42 | <a id="adr0090-decision"></a> |
| 43 | |
| 44 | ## Decision (direction) |
| 45 | |
| 46 | Introduce a **launch profile catalog** in the workspace zone, with **currently selected profile**, and run debug (DAP launch) **through the active profile**, not sole `StartupProjectRelativePath`. |
| 47 | |
| 48 | <a id="adr0090-profile-model-v1"></a> |
| 49 | |
| 50 | ### Minimal profile model (v1) |
| 51 | |
| 52 | Per profile, at minimum: |
| 53 | |
| 54 | - **Id** — stable name within solution (display name may match or localize separately). |
| 55 | - **Project** — path to `.csproj` / `.fsproj` **relative to solution root** (same base as `BreakpointsFileService.GetWorkspaceRoot(solutionPath)`). |
| 56 | - **MSBuild configuration** — e.g. `Debug` / `Release` (string; default `Debug` for debug). |
| 57 | - **Program arguments** — optional, string list or quoted string rules (refine at implementation). |
| 58 | - **Working directory** — optional; if empty — inherit from [IdeDapDebugSession](../../../Services/IdeDapDebugSession.cs) (`ResolveLaunchWorkingDirectory` logic exists). |
| 59 | |
| 60 | - **Process environment variables** — for web at minimum merge what profile supplies (often `ASPNETCORE_ENVIRONMENT=Development`). Implementation: env in DAP `launch` (extend [IdeDapDebugSession](../../../Services/IdeDapDebugSession.cs) if missing), no silent drop. |
| 61 | |
| 62 | <a id="adr0090-aspnet-v1"></a> |
| 63 | |
| 64 | ### ASP.NET Core / web (v1, not deferred) |
| 65 | |
| 66 | Profile must express what is already in `launchSettings.json` for `commandName: Project` (Kestrel): |
| 67 | |
| 68 | - **`applicationUrl`** — one or several bindings (`;` as in SDK template or URL array in TOML); on launch set in environment as `dotnet` does (typically `ASPNETCORE_URLS` or host-aligned — refine with `dotnet`/hosts). |
| 69 | - **`launchBrowser`** — optional; if `true`, open URL after start (CIDE wrapper if added; else mark deferred/v2 explicitly). |
| 70 | - Separate profiles like `http` / `https` — multiple named entries in TOML, 1:1 import from `launchSettings.profiles` where possible. |
| 71 | |
| 72 | **IIS Express** (`commandName: IISExpress`) and full VS IIS parity — **may** be separate phase; ADR minimum: Kestrel + `Project` — web v1 baseline; IIS — best effort or separate ticket after baseline. |
| 73 | |
| 74 | **Import:** reading web project `Properties/launchSettings.json`, TOML in `.cascade-ide` must **preserve URL and env semantics** so portal-style scenarios do not break vs `dotnet run --launch-profile …`. |
| 75 | |
| 76 | <a id="adr0090-storage"></a> |
| 77 | |
| 78 | ### Storage |
| 79 | |
| 80 | - **Canonical format: TOML**, not JSON — e.g. `.cascade-ide/launch-profiles.toml` (plus schema version key, e.g. `version = 1`). Same philosophy as user/canonical IDE config ([0028](0028-user-settings-toml-localappdata-and-secrets.md), [0029](0029-configuration-toml-canonical-ui-facade.md)): readability, comments, one style with `settings` / `workspace` beside repo. |
| 81 | - **One file** per open solution (path to `.sln` / standalone `.csproj` — as for breakpoints and startup): **profile list** and **active** profile (`active_profile` or equivalent), no second file to desync. |
| 82 | - **JSON** (`Properties/launchSettings.json`) remains external de-facto SDK/VS standard — **not** duplicated as primary canon in `.cascade-ide`; **import/export** into TOML model. |
| 83 | |
| 84 | **Migration:** if only `startup-project.json` exists, on first read build **one** default profile (name like `Default` / from project name), set active, write `launch-profiles.toml`, keep old JSON for strangler until explicit removal. |
| 85 | |
| 86 | <a id="adr0090-ui"></a> |
| 87 | |
| 88 | ### UI |
| 89 | |
| 90 | - Visible **current profile selector** (toolbar or explorer strip / debug banner) — **keyboard-first** per [0013](0013-command-surface-and-discoverability.md). |
| 91 | - Commands: manage profiles (add/delete/duplicate) — MFD or modal by volume ([0074](0074-settings-ui-mfd-compact-layout-overflow.md) overflow policy). |
| 92 | - F5 / “start debugging” uses **active profile** without `.dll` dialog when resolve succeeds ([0002](0002-debug-human-agent-parity.md) parity). |
| 93 | |
| 94 | <a id="adr0090-mcp-parity"></a> |
| 95 | |
| 96 | ### Agent parity (MCP / IdeCommands) — v1 contract |
| 97 | |
| 98 | Debug launch contract at `IdeCommands.DebugLaunch` and `MCP-PROTOCOL`: |
| 99 | |
| 100 | - Command: `debug_launch`. |
| 101 | - Mode A (explicit target): `workspace_path` + `target_path` (as today, backward compatible). |
| 102 | - Mode B (profile): `profile_name` (optional) + open workspace/solution context. |
| 103 | - if `profile_name` omitted, use `active_profile`; |
| 104 | - if profile not found — explicit contract error (no silent random startup fallback). |
| 105 | - Additional: `netcoredbg_path`, `program_args`. |
| 106 | - If both `target_path` and `profile_name` — **`target_path` wins** (explicit agent path stronger than profile). |
| 107 | |
| 108 | Human and agent share F5/Launch meaning: “launch by active profile”; direct `target_path` kept for point scenarios. |
| 109 | |
| 110 | <a id="adr0090-dotnet-alignment"></a> |
| 111 | |
| 112 | ### .NET alignment |
| 113 | |
| 114 | - **Optional import** from `Properties/launchSettings.json` (after v1) — less friction for `dotnet`/VS projects. Canon remains **TOML in `.cascade-ide`**; **semantic compatibility** with standard `launchSettings`, not bitwise file identity. |
| 115 | - Optional **export** to `launchSettings`-like form for other tools — not mandatory. |
| 116 | |
| 117 | <a id="adr0090-build-resolve"></a> |
| 118 | |
| 119 | ### Build resolve |
| 120 | |
| 121 | - [MsBuildDebugTargetResolver](../../../Services/MsBuildDebugTargetResolver.cs): pass **configuration** from profile (`-p:Configuration=...`), not only constant `Debug`, when active profile is source of truth. |
| 122 | |
| 123 | <a id="adr0090-consequences"></a> |
| 124 | |
| 125 | ## Consequences |
| 126 | |
| 127 | - Refactor `MainWindowViewModel` / `StartupProjectStore` toward **“set + active”** model; old APIs — strangler. |
| 128 | - Tests: TOML parse, migration from single `startup-project.json`, import **web** `launchSettings`, F5 scenarios: console + **Kestrel** with valid URL. |
| 129 | - User Guide — product layer, not mandatory ADR volume (see [README](README.md)). |
| 130 | |
| 131 | <a id="adr0090-rejected"></a> |
| 132 | |
| 133 | ## Rejected / deferred alternatives |
| 134 | |
| 135 | - **Only** read `launchSettings.json` without own file — rejected: worse for IDE MVP parity (monorepos, paths relative to solution, stable agent contract in `.cascade-ide` beside breakpoints). |
| 136 | - **Multiple parallel debug sessions** in one IDE — out of scope (one DAP session unless separately fixed). |
| 137 | |
| 138 | <a id="adr0090-implementation-status"></a> |
| 139 | |
| 140 | ## Rollout status |
| 141 | |
| 142 | - Storage canon: `.cascade-ide/launch-profiles.toml`, migration from `startup-project.json`, `MsBuildDebugTargetResolver` with profile configuration, DAP `launch` with `env` and optional cwd, `debug_launch` with `profile_name` and explicit contract errors; tests `LaunchProfilesStoreTests`, docs `IdeCommands` / `MCP-PROTOCOL.md`. |
| 143 | |
| 144 | <a id="adr0090-implementation-checklist"></a> |
| 145 | |
| 146 | ## Implementation checklist (decision → code) |
| 147 | |
| 148 | 1. Introduce `.cascade-ide/launch-profiles.toml` (profiles + `active_profile`) and migration from `startup-project.json`. |
| 149 | 2. Update debug resolve: `MsBuildDebugTargetResolver` gets `Configuration` from profile. |
| 150 | 3. Update `debug_launch` pipeline: `profile_name`, clear errors (`profile_not_found`, `active_profile_missing`, `profile_target_unresolved`), compatibility with `workspace_path + target_path`. |
| 151 | 4. Sync docs: XML-doc `IdeCommands.DebugLaunch`, `docs/MCP-PROTOCOL.md`, ADR index links if needed. |
| 152 | 5. Test plan: console profiles Debug/Release with different args; ASP.NET Core import `applicationUrl`/env and launch by profile; negative: missing profile and unresolvable target give explicit errors. |
| 153 | |