setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

-Quiet)) {\n Add-Content -Path .gitignore -Value '.dotnet/'\n}\n```\n\n### Step 9 — Install workloads (if requested)\n\nOnly do this after `global.json` and `.gitignore` are complete, so a slow or\nplatform-limited workload install does not prevent the base local SDK setup from\nbeing usable.\n\nIf the user mentioned MAUI, mobile, workload, Blazor WASM, or cross-platform,\ninstall using the **local** binary (no sudo needed):\n\n```bash\n./.dotnet/dotnet workload install \u003cworkload> # macOS/Linux\n.\\.dotnet\\dotnet.exe workload install \u003cworkload> # Windows\n```\n\nVerify: `./.dotnet/dotnet workload list` (or `.\\.dotnet\\dotnet.exe workload list`).\n\nFor MAUI, pick a workload supported by the current OS and target platform. On\nLinux, the full `maui` meta-workload is not available; use a supported workload\nsuch as `maui-android` when Android is the target, or explain the platform\nlimitation and ask which target to configure.\n\n> **Always use the local dotnet binary for workload commands.** Workload metadata\n> is stored relative to the host process's dotnet root. The system `dotnet` puts\n> metadata in the wrong location. (See [dotnet/sdk#49825](https://github.com/dotnet/sdk/issues/49825).)\n\n### Step 10 — Create team install scripts\n\nCreate if user mentioned \"team\", \"share\", \"CI\", \"scripts\", etc. Otherwise offer.\nThese examples back up `global.json` and preserve existing settings. The bash script\nuses `jq` when an existing `global.json` must be patched; if `jq` is unavailable,\nit refuses to overwrite the file and prints the settings to merge manually.\nAdapt script variables to the install choice from Step 1: exact versions should\nuse `--version` / `-Version` and `rollForward: \"disable\"`; channel installs should\nuse channel/quality and only set `allowPrerelease: true` for prerelease SDKs.\nIf `global.json` already pins `sdk.version` and the user mainly needs team\nscripts, reuse that version in the scripts and update `global.json` first; do\nnot start a long SDK download just to discover the version. When the user asks\nfor both setup and scripts, create the scripts/config before any long install so\nthe reproducible setup exists even if download or workload installation is slow.\n\n**install-dotnet.sh:**\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\nINSTALL_DIR=\".dotnet\"\nCHANNEL=\"11.0\"\nQUALITY=\"preview\"\nVERSION=\"\"\nROLL_FORWARD=\"latestFeature\"\nALLOW_PRERELEASE=\"true\"\nWORKLOADS=(\"${@}\")\nERROR_MESSAGE=\"Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally.\"\nINSTALL_SCRIPT=\"$(mktemp \"${TMPDIR:-/tmp}/dotnet-install.XXXXXX\")\"\nGLOBAL_JSON_TMP=\"\"\ncleanup() {\n rm -f \"$INSTALL_SCRIPT\"\n [ -n \"$GLOBAL_JSON_TMP\" ] && rm -f \"$GLOBAL_JSON_TMP\"\n}\ntrap cleanup EXIT\ncurl -fsSL https://dot.net/v1/dotnet-install.sh -o \"$INSTALL_SCRIPT\"\nINSTALL_ARGS=(--install-dir \"$INSTALL_DIR\")\nif [ -n \"$VERSION\" ]; then\n INSTALL_ARGS+=(--version \"$VERSION\")\n ROLL_FORWARD=\"disable\"\nelse\n INSTALL_ARGS+=(--channel \"$CHANNEL\" --quality \"$QUALITY\")\nfi\nbash \"$INSTALL_SCRIPT\" \"${INSTALL_ARGS[@]}\"\nSDK_VERSION=$(\"$INSTALL_DIR/dotnet\" --version)\nwrite_global_json() {\n if [ -f global.json ]; then\n cp global.json global.json.bak\n if ! command -v jq >/dev/null 2>&1; then\n echo \"global.json exists; install succeeded, but this script will not overwrite it without jq.\" >&2\n echo \"Merge these sdk settings manually so existing global.json properties are preserved:\" >&2\n cat >&2 \u003c\u003cEOF\n{\n \"sdk\": {\n \"version\": \"$SDK_VERSION\",\n \"allowPrerelease\": $ALLOW_PRERELEASE,\n \"rollForward\": \"$ROLL_FORWARD\",\n \"paths\": [\".dotnet\", \"\\$host\\$\"],\n \"errorMessage\": \"$ERROR_MESSAGE\"\n }\n}\nEOF\n exit 1\n fi\n GLOBAL_JSON_TMP=\"$(mktemp \"${TMPDIR:-/tmp}/global-json.XXXXXX\")\"\n jq --arg version \"$SDK_VERSION\" --arg rollForward \"$ROLL_FORWARD\" --argjson allowPrerelease \"$ALLOW_PRERELEASE\" --arg errorMessage \"$ERROR_MESSAGE\" '\n .sdk = ((.sdk // {}) + {\n version: $version,\n allowPrerelease: $allowPrerelease,\n rollForward: $rollForward,\n paths: [\".dotnet\", \"$host$\"],\n errorMessage: $errorMessage\n })\n ' global.json > \"$GLOBAL_JSON_TMP\"\n mv \"$GLOBAL_JSON_TMP\" global.json\n GLOBAL_JSON_TMP=\"\"\n else\n cat > global.json \u003c\u003cEOF\n{\n \"sdk\": {\n \"version\": \"$SDK_VERSION\",\n \"allowPrerelease\": $ALLOW_PRERELEASE,\n \"rollForward\": \"$ROLL_FORWARD\",\n \"paths\": [\".dotnet\", \"\\$host\\$\"],\n \"errorMessage\": \"$ERROR_MESSAGE\"\n }\n}\nEOF\n fi\n}\nwrite_global_json\ngrep -qxF '.dotnet/' .gitignore 2>/dev/null || printf '\\n.dotnet/\\n' >> .gitignore\n[ ${#WORKLOADS[@]} -gt 0 ] && \"$INSTALL_DIR/dotnet\" workload install \"${WORKLOADS[@]}\"\necho \"Done. SDK: $SDK_VERSION\"\n```\n\n```bash\nchmod +x install-dotnet.sh\n```\n\n**install-dotnet.ps1:**\n\n```powershell\nparam([string[]]$Workloads = @())\n$ErrorActionPreference = 'Stop'\n$installDir = '.dotnet'; $channel = '11.0'; $quality = 'preview'\n$version = ''; $rollForward = 'latestFeature'; $allowPrerelease = $true\n$errorMessage = 'Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally.'\n$installScript = Join-Path $env:TEMP \"dotnet-install-$([guid]::NewGuid()).ps1\"\ntry {\n Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -OutFile $installScript\n $installArgs = @('-InstallDir', $installDir)\n if ($version) {\n $installArgs += @('-Version', $version)\n $rollForward = 'disable'\n } else {\n $installArgs += @('-Channel', $channel, '-Quality', $quality)\n }\n & $installScript @installArgs\n}\nfinally {\n if (Test-Path -LiteralPath $installScript) {\n Remove-Item -LiteralPath $installScript -Force\n }\n}\n$sdkVersion = & \"$installDir\\dotnet.exe\" --version\n$globalJson = if (Test-Path 'global.json') {\n Copy-Item 'global.json' 'global.json.bak'\n Get-Content -Path 'global.json' -Raw | ConvertFrom-Json\n} else {\n [pscustomobject]@{}\n}\nif (-not $globalJson.PSObject.Properties['sdk']) {\n $globalJson | Add-Member -MemberType NoteProperty -Name 'sdk' -Value ([pscustomobject]@{})\n}\n$updates = [ordered]@{\n version = $sdkVersion\n allowPrerelease = $allowPrerelease\n rollForward = $rollForward\n paths = @('.dotnet', '$host

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

)\n errorMessage = $errorMessage\n}\nforeach ($entry in $updates.GetEnumerator()) {\n $property = $globalJson.sdk.PSObject.Properties[$entry.Key]\n if ($property) {\n $property.Value = $entry.Value\n } else {\n $globalJson.sdk | Add-Member -MemberType NoteProperty -Name $entry.Key -Value $entry.Value\n }\n}\n$globalJson | ConvertTo-Json -Depth 10 | Set-Content -Path 'global.json' -Encoding UTF8\nif (-not (Test-Path .gitignore) -or -not (Select-String -Path .gitignore -Pattern '^\\.dotnet/

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

-Quiet)) {\n Add-Content -Path .gitignore -Value '.dotnet/'\n}\nif ($Workloads.Count -gt 0) { & \"$installDir\\dotnet.exe\" workload install @Workloads }\nWrite-Host \"Done. SDK: $sdkVersion\"\n```\n\nCommit these scripts to the repo so teammates can run them.\n\n### Step 11 — Verify SDK resolution\n\n```bash\ndotnet --version\n```\n\nOutput should match the locally installed version. If not, check: global.json\nlocation, `paths` array contents, host dotnet version ≥ 10.\n\n### Step 12 — Summarize and explain cleanup\n\nTell the user: SDK installed, global.json configured, .dotnet/ gitignored, system\ninstall untouched. Cleanup: delete `.dotnet/`, remove `paths`/`errorMessage` from\nglobal.json, optionally delete install scripts. Include the final `global.json`\n`sdk` values (or a short snippet) so the user can see the configured version,\n`paths`, and any `errorMessage`. If workloads were requested, include the local\n`dotnet workload install ...` command used and the workload verification result\nor the exact blocker if the workload could not be installed.\n\n## Common pitfalls\n\n| Pitfall | Cause | Fix |\n|---|---|---|\n| `paths` ignored | Host `dotnet` \u003c v10 | Install .NET 10+ system-wide |\n| Wrong SDK resolves | `global.json` in parent directory | Check for global.json up the tree |\n| Teammates get \"SDK not found\" | `.dotnet/` gitignored, no install script run | Use `errorMessage` in global.json |\n| Workloads missing | Used system `dotnet` instead of local | Use `./.dotnet/dotnet workload install` |\n| `dotnet app.dll` wrong runtime | `paths` is SDK-only, not apphost | Use `dotnet run` or set `DOTNET_ROOT` |","attachment_filenames":[],"attachments":[],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"setup-local-sdk","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Purpose","type":"text"}]},{"type":"paragraph","content":[{"text":"Guide the user through installing a .NET SDK into a project-local ","type":"text"},{"text":".dotnet/","type":"text","marks":[{"type":"code_inline"}]},{"text":" directory and wiring it up via the ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable.","type":"text"}]},{"type":"paragraph","content":[{"text":"The result is a fully isolated SDK that:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Does ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" modify the system-wide .NET installation.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Is picked up automatically by ","type":"text"},{"text":"dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" commands from the project root.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Can be deleted to revert (","type":"text"},{"text":"rm -rf .dotnet/","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"Remove-Item -Recurse -Force .\\.dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When NOT to use","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User wants a ","type":"text"},{"text":"system-wide","type":"text","marks":[{"type":"strong"}]},{"text":" install — direct to the official installer.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Host ","type":"text"},{"text":"dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" is ","type":"text"},{"text":"older than v10","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" doesn't exist; explain and stop.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User needs a ","type":"text"},{"text":"runtime-only","type":"text","marks":[{"type":"strong"}]},{"text":" install — ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" applies to SDK resolution only.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Inputs / Prerequisites","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Input","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Required","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Notes","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Channel or version","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"11.0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"e.g. ","type":"text"},{"text":"11.0","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"STS","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"LTS","type":"text","marks":[{"type":"code_inline"}]},{"text":", or an exact version like ","type":"text"},{"text":"11.0.100-preview.2.26159.112","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Quality","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"preview","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"One of: ","type":"text"},{"text":"daily","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"preview","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ga","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"jq","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"—","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Optional for bash team scripts when patching an existing ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"; without it, do not overwrite the file","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Prerequisites","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A .NET 10+ SDK is installed globally","type":"text","marks":[{"type":"strong"}]},{"text":" — run ","type":"text"},{"text":"dotnet --version","type":"text","marks":[{"type":"code_inline"}]},{"text":"; major ≥ 10.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"curl","type":"text","marks":[{"type":"strong"}]},{"text":" (macOS/Linux) or ","type":"text"},{"text":"PowerShell","type":"text","marks":[{"type":"strong"}]},{"text":" (Windows) is available.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1 — Clarify what to install","type":"text"}]},{"type":"paragraph","content":[{"text":"If the user didn't specify, ask what .NET SDK version they want (e.g., \"latest .NET 11 preview\" or an exact version like ","type":"text"},{"text":"11.0.100-preview.2.26159.112","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Map the answer to ","type":"text"},{"text":"--channel","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"--quality","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"--version","type":"text","marks":[{"type":"code_inline"}]},{"text":" flags.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2 — Verify .NET 10+ host","type":"text"}]},{"type":"paragraph","content":[{"text":"If the user already provided ","type":"text"},{"text":"dotnet --version","type":"text","marks":[{"type":"code_inline"}]},{"text":" output, treat that as the authoritative version for their machine. Do not override it with the agent workspace's version; if the two differ, explain that the workspace differs and continue advising for the user's machine.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"dotnet --version","type":"text"}]},{"type":"paragraph","content":[{"text":"If major version \u003c 10, stop before downloading anything: the ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" feature requires a .NET 10+ host SDK. Tell the user to install .NET 10 or later system-wide first, then return to the local SDK setup.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3 — Detect operating system","type":"text"}]},{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"uname -s 2>/dev/null","type":"text","marks":[{"type":"code_inline"}]},{"text":". If it succeeds (including ","type":"text"},{"text":"MINGW*","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"MSYS*","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"CYGWIN*","type":"text","marks":[{"type":"code_inline"}]},{"text":" — these are bash-capable environments like Git Bash) → use bash/","type":"text"},{"text":"dotnet-install.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":". If it fails (native Windows without Git Bash) → use PowerShell/","type":"text"},{"text":"dotnet-install.ps1","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4 — Check for existing local SDK","type":"text"}]},{"type":"paragraph","content":[{"text":"macOS / Linux:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"test -d .dotnet && echo \"exists\" || echo \"not found\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Windows (PowerShell):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"if (Test-Path -LiteralPath .\\.dotnet) { \"exists\" } else { \"not found\" }","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":".dotnet/","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists, ask: update with the new version, or skip and keep it?","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5 — Download and run the install script","type":"text"}]},{"type":"paragraph","content":[{"text":"macOS / Linux:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"INSTALL_SCRIPT=\"$(mktemp \"${TMPDIR:-/tmp}/dotnet-install.XXXXXX\")\"\ntrap 'rm -f \"$INSTALL_SCRIPT\"' EXIT\ncurl -fsSL https://dot.net/v1/dotnet-install.sh -o \"$INSTALL_SCRIPT\"\nbash \"$INSTALL_SCRIPT\" --channel \u003cCHANNEL> --quality \u003cQUALITY> --install-dir .dotnet","type":"text"}]},{"type":"paragraph","content":[{"text":"Windows (PowerShell):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"$installScript = Join-Path $env:TEMP \"dotnet-install-$([guid]::NewGuid()).ps1\"\ntry {\n Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -OutFile $installScript\n & $installScript -Channel \u003cCHANNEL> -Quality \u003cQUALITY> -InstallDir .dotnet\n}\nfinally {\n if (Test-Path -LiteralPath $installScript) {\n Remove-Item -LiteralPath $installScript -Force\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"For exact versions: use ","type":"text"},{"text":"--version \u003cVERSION>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (bash) or ","type":"text"},{"text":"-Version \u003cVERSION>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (PowerShell) instead of channel/quality flags. The install scripts are from Microsoft's official URLs: ","type":"text"},{"text":"https://dot.net/v1/dotnet-install.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"https://dot.net/v1/dotnet-install.ps1","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 6 — Identify the installed version","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"./.dotnet/dotnet --version # macOS/Linux\n.\\.dotnet\\dotnet.exe --version # Windows","type":"text"}]},{"type":"paragraph","content":[{"text":"Record the exact version string (e.g., ","type":"text"},{"text":"11.0.100-preview.2.26159.112","type":"text","marks":[{"type":"code_inline"}]},{"text":") for ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 7 — Create or update global.json","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"sdk\": {\n \"version\": \"\u003cINSTALLED_VERSION>\",\n \"allowPrerelease\": true,\n \"rollForward\": \"latestFeature\",\n \"paths\": [\".dotnet\", \"$host$\"],\n \"errorMessage\": \"Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally.\"\n }\n}","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":": ","type":"text"},{"text":".dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" first (local priority), ","type":"text"},{"text":"$host$","type":"text","marks":[{"type":"code_inline"}]},{"text":" = system-wide fallback.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rollForward: \"latestFeature\"","type":"text","marks":[{"type":"code_inline"}]},{"text":": use for latest-preview or floating feature-band installs.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Exact version requests: use ","type":"text"},{"text":"rollForward: \"disable\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" so SDK resolution doesn't move to a different feature band.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"allowPrerelease","type":"text","marks":[{"type":"code_inline"}]},{"text":": set to ","type":"text"},{"text":"true","type":"text","marks":[{"type":"code_inline"}]},{"text":" only when installing a prerelease SDK. Omit for stable versions.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"errorMessage","type":"text","marks":[{"type":"code_inline"}]},{"text":": include only when team install scripts are created (Step 10). Otherwise omit.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" already exists, ","type":"text"},{"text":"merge","type":"text","marks":[{"type":"strong"}]},{"text":" carefully: preserve existing properties (","type":"text"},{"text":"msbuild-sdks","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tools","type":"text","marks":[{"type":"code_inline"}]},{"text":", etc.) and only add/update the ","type":"text"},{"text":"sdk","type":"text","marks":[{"type":"code_inline"}]},{"text":" section. Read the existing file first, update/add the ","type":"text"},{"text":"sdk","type":"text","marks":[{"type":"code_inline"}]},{"text":" object, then write it back. This ensures cross-project config (e.g., MSBuild settings) isn't lost. Always back up the original file (e.g., ","type":"text"},{"text":"global.json.bak","type":"text","marks":[{"type":"code_inline"}]},{"text":") before modifying.","type":"text"}]},{"type":"paragraph","content":[{"text":"Minimal config","type":"text","marks":[{"type":"strong"}]},{"text":" (when version pinning isn't needed): ","type":"text"},{"text":"{\"sdk\":{\"paths\":[\".dotnet\",\"$host$\"]}}","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 8 — Update .gitignore","type":"text"}]},{"type":"paragraph","content":[{"text":"macOS / Linux (or Git Bash):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"grep -qxF '.dotnet/' .gitignore 2>/dev/null || printf '\\n.dotnet/\\n' >> .gitignore","type":"text"}]},{"type":"paragraph","content":[{"text":"Windows (PowerShell):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"if (-not (Test-Path .gitignore) -or -not (Select-String -Path .gitignore -Pattern '^\\.dotnet/

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

-Quiet)) {\n Add-Content -Path .gitignore -Value '.dotnet/'\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 9 — Install workloads (if requested)","type":"text"}]},{"type":"paragraph","content":[{"text":"Only do this after ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":".gitignore","type":"text","marks":[{"type":"code_inline"}]},{"text":" are complete, so a slow or platform-limited workload install does not prevent the base local SDK setup from being usable.","type":"text"}]},{"type":"paragraph","content":[{"text":"If the user mentioned MAUI, mobile, workload, Blazor WASM, or cross-platform, install using the ","type":"text"},{"text":"local","type":"text","marks":[{"type":"strong"}]},{"text":" binary (no sudo needed):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"./.dotnet/dotnet workload install \u003cworkload> # macOS/Linux\n.\\.dotnet\\dotnet.exe workload install \u003cworkload> # Windows","type":"text"}]},{"type":"paragraph","content":[{"text":"Verify: ","type":"text"},{"text":"./.dotnet/dotnet workload list","type":"text","marks":[{"type":"code_inline"}]},{"text":" (or ","type":"text"},{"text":".\\.dotnet\\dotnet.exe workload list","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]},{"type":"paragraph","content":[{"text":"For MAUI, pick a workload supported by the current OS and target platform. On Linux, the full ","type":"text"},{"text":"maui","type":"text","marks":[{"type":"code_inline"}]},{"text":" meta-workload is not available; use a supported workload such as ","type":"text"},{"text":"maui-android","type":"text","marks":[{"type":"code_inline"}]},{"text":" when Android is the target, or explain the platform limitation and ask which target to configure.","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Always use the local dotnet binary for workload commands.","type":"text","marks":[{"type":"strong"}]},{"text":" Workload metadata is stored relative to the host process's dotnet root. The system ","type":"text"},{"text":"dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" puts metadata in the wrong location. (See ","type":"text"},{"text":"dotnet/sdk#49825","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/dotnet/sdk/issues/49825","title":null}}]},{"text":".)","type":"text"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 10 — Create team install scripts","type":"text"}]},{"type":"paragraph","content":[{"text":"Create if user mentioned \"team\", \"share\", \"CI\", \"scripts\", etc. Otherwise offer. These examples back up ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" and preserve existing settings. The bash script uses ","type":"text"},{"text":"jq","type":"text","marks":[{"type":"code_inline"}]},{"text":" when an existing ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" must be patched; if ","type":"text"},{"text":"jq","type":"text","marks":[{"type":"code_inline"}]},{"text":" is unavailable, it refuses to overwrite the file and prints the settings to merge manually. Adapt script variables to the install choice from Step 1: exact versions should use ","type":"text"},{"text":"--version","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"-Version","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"rollForward: \"disable\"","type":"text","marks":[{"type":"code_inline"}]},{"text":"; channel installs should use channel/quality and only set ","type":"text"},{"text":"allowPrerelease: true","type":"text","marks":[{"type":"code_inline"}]},{"text":" for prerelease SDKs. If ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" already pins ","type":"text"},{"text":"sdk.version","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the user mainly needs team scripts, reuse that version in the scripts and update ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" first; do not start a long SDK download just to discover the version. When the user asks for both setup and scripts, create the scripts/config before any long install so the reproducible setup exists even if download or workload installation is slow.","type":"text"}]},{"type":"paragraph","content":[{"text":"install-dotnet.sh:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"#!/usr/bin/env bash\nset -euo pipefail\nINSTALL_DIR=\".dotnet\"\nCHANNEL=\"11.0\"\nQUALITY=\"preview\"\nVERSION=\"\"\nROLL_FORWARD=\"latestFeature\"\nALLOW_PRERELEASE=\"true\"\nWORKLOADS=(\"${@}\")\nERROR_MESSAGE=\"Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally.\"\nINSTALL_SCRIPT=\"$(mktemp \"${TMPDIR:-/tmp}/dotnet-install.XXXXXX\")\"\nGLOBAL_JSON_TMP=\"\"\ncleanup() {\n rm -f \"$INSTALL_SCRIPT\"\n [ -n \"$GLOBAL_JSON_TMP\" ] && rm -f \"$GLOBAL_JSON_TMP\"\n}\ntrap cleanup EXIT\ncurl -fsSL https://dot.net/v1/dotnet-install.sh -o \"$INSTALL_SCRIPT\"\nINSTALL_ARGS=(--install-dir \"$INSTALL_DIR\")\nif [ -n \"$VERSION\" ]; then\n INSTALL_ARGS+=(--version \"$VERSION\")\n ROLL_FORWARD=\"disable\"\nelse\n INSTALL_ARGS+=(--channel \"$CHANNEL\" --quality \"$QUALITY\")\nfi\nbash \"$INSTALL_SCRIPT\" \"${INSTALL_ARGS[@]}\"\nSDK_VERSION=$(\"$INSTALL_DIR/dotnet\" --version)\nwrite_global_json() {\n if [ -f global.json ]; then\n cp global.json global.json.bak\n if ! command -v jq >/dev/null 2>&1; then\n echo \"global.json exists; install succeeded, but this script will not overwrite it without jq.\" >&2\n echo \"Merge these sdk settings manually so existing global.json properties are preserved:\" >&2\n cat >&2 \u003c\u003cEOF\n{\n \"sdk\": {\n \"version\": \"$SDK_VERSION\",\n \"allowPrerelease\": $ALLOW_PRERELEASE,\n \"rollForward\": \"$ROLL_FORWARD\",\n \"paths\": [\".dotnet\", \"\\$host\\$\"],\n \"errorMessage\": \"$ERROR_MESSAGE\"\n }\n}\nEOF\n exit 1\n fi\n GLOBAL_JSON_TMP=\"$(mktemp \"${TMPDIR:-/tmp}/global-json.XXXXXX\")\"\n jq --arg version \"$SDK_VERSION\" --arg rollForward \"$ROLL_FORWARD\" --argjson allowPrerelease \"$ALLOW_PRERELEASE\" --arg errorMessage \"$ERROR_MESSAGE\" '\n .sdk = ((.sdk // {}) + {\n version: $version,\n allowPrerelease: $allowPrerelease,\n rollForward: $rollForward,\n paths: [\".dotnet\", \"$host$\"],\n errorMessage: $errorMessage\n })\n ' global.json > \"$GLOBAL_JSON_TMP\"\n mv \"$GLOBAL_JSON_TMP\" global.json\n GLOBAL_JSON_TMP=\"\"\n else\n cat > global.json \u003c\u003cEOF\n{\n \"sdk\": {\n \"version\": \"$SDK_VERSION\",\n \"allowPrerelease\": $ALLOW_PRERELEASE,\n \"rollForward\": \"$ROLL_FORWARD\",\n \"paths\": [\".dotnet\", \"\\$host\\$\"],\n \"errorMessage\": \"$ERROR_MESSAGE\"\n }\n}\nEOF\n fi\n}\nwrite_global_json\ngrep -qxF '.dotnet/' .gitignore 2>/dev/null || printf '\\n.dotnet/\\n' >> .gitignore\n[ ${#WORKLOADS[@]} -gt 0 ] && \"$INSTALL_DIR/dotnet\" workload install \"${WORKLOADS[@]}\"\necho \"Done. SDK: $SDK_VERSION\"","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"chmod +x install-dotnet.sh","type":"text"}]},{"type":"paragraph","content":[{"text":"install-dotnet.ps1:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"param([string[]]$Workloads = @())\n$ErrorActionPreference = 'Stop'\n$installDir = '.dotnet'; $channel = '11.0'; $quality = 'preview'\n$version = ''; $rollForward = 'latestFeature'; $allowPrerelease = $true\n$errorMessage = 'Required .NET SDK not found. Run ./install-dotnet.sh (or .ps1) to install it locally.'\n$installScript = Join-Path $env:TEMP \"dotnet-install-$([guid]::NewGuid()).ps1\"\ntry {\n Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -OutFile $installScript\n $installArgs = @('-InstallDir', $installDir)\n if ($version) {\n $installArgs += @('-Version', $version)\n $rollForward = 'disable'\n } else {\n $installArgs += @('-Channel', $channel, '-Quality', $quality)\n }\n & $installScript @installArgs\n}\nfinally {\n if (Test-Path -LiteralPath $installScript) {\n Remove-Item -LiteralPath $installScript -Force\n }\n}\n$sdkVersion = & \"$installDir\\dotnet.exe\" --version\n$globalJson = if (Test-Path 'global.json') {\n Copy-Item 'global.json' 'global.json.bak'\n Get-Content -Path 'global.json' -Raw | ConvertFrom-Json\n} else {\n [pscustomobject]@{}\n}\nif (-not $globalJson.PSObject.Properties['sdk']) {\n $globalJson | Add-Member -MemberType NoteProperty -Name 'sdk' -Value ([pscustomobject]@{})\n}\n$updates = [ordered]@{\n version = $sdkVersion\n allowPrerelease = $allowPrerelease\n rollForward = $rollForward\n paths = @('.dotnet', '$host

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

)\n errorMessage = $errorMessage\n}\nforeach ($entry in $updates.GetEnumerator()) {\n $property = $globalJson.sdk.PSObject.Properties[$entry.Key]\n if ($property) {\n $property.Value = $entry.Value\n } else {\n $globalJson.sdk | Add-Member -MemberType NoteProperty -Name $entry.Key -Value $entry.Value\n }\n}\n$globalJson | ConvertTo-Json -Depth 10 | Set-Content -Path 'global.json' -Encoding UTF8\nif (-not (Test-Path .gitignore) -or -not (Select-String -Path .gitignore -Pattern '^\\.dotnet/

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…

-Quiet)) {\n Add-Content -Path .gitignore -Value '.dotnet/'\n}\nif ($Workloads.Count -gt 0) { & \"$installDir\\dotnet.exe\" workload install @Workloads }\nWrite-Host \"Done. SDK: $sdkVersion\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Commit these scripts to the repo so teammates can run them.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 11 — Verify SDK resolution","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"dotnet --version","type":"text"}]},{"type":"paragraph","content":[{"text":"Output should match the locally installed version. If not, check: global.json location, ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" array contents, host dotnet version ≥ 10.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 12 — Summarize and explain cleanup","type":"text"}]},{"type":"paragraph","content":[{"text":"Tell the user: SDK installed, global.json configured, .dotnet/ gitignored, system install untouched. Cleanup: delete ","type":"text"},{"text":".dotnet/","type":"text","marks":[{"type":"code_inline"}]},{"text":", remove ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"errorMessage","type":"text","marks":[{"type":"code_inline"}]},{"text":" from global.json, optionally delete install scripts. Include the final ","type":"text"},{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"sdk","type":"text","marks":[{"type":"code_inline"}]},{"text":" values (or a short snippet) so the user can see the configured version, ","type":"text"},{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":", and any ","type":"text"},{"text":"errorMessage","type":"text","marks":[{"type":"code_inline"}]},{"text":". If workloads were requested, include the local ","type":"text"},{"text":"dotnet workload install ...","type":"text","marks":[{"type":"code_inline"}]},{"text":" command used and the workload verification result or the exact blocker if the workload could not be installed.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Common pitfalls","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pitfall","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cause","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" ignored","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Host ","type":"text"},{"text":"dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" \u003c v10","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Install .NET 10+ system-wide","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wrong SDK resolves","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"global.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" in parent directory","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check for global.json up the tree","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Teammates get \"SDK not found\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".dotnet/","type":"text","marks":[{"type":"code_inline"}]},{"text":" gitignored, no install script run","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"errorMessage","type":"text","marks":[{"type":"code_inline"}]},{"text":" in global.json","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workloads missing","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Used system ","type":"text"},{"text":"dotnet","type":"text","marks":[{"type":"code_inline"}]},{"text":" instead of local","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"./.dotnet/dotnet workload install","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dotnet app.dll","type":"text","marks":[{"type":"code_inline"}]},{"text":" wrong runtime","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"paths","type":"text","marks":[{"type":"code_inline"}]},{"text":" is SDK-only, not apphost","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"dotnet run","type":"text","marks":[{"type":"code_inline"}]},{"text":" or set ","type":"text"},{"text":"DOTNET_ROOT","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"setup-local-sdk","author":"@skillopedia","source":{"stars":5797,"repo_name":"skills","origin_url":"https://github.com/dotnet/skills/blob/HEAD/plugins/dotnet/skills/setup-local-sdk/SKILL.md","repo_owner":"dotnet","body_sha256":"6b4904db9ae950da582f85dc2f4cf2adf586776d84ce805a273edb4045f1a74e","cluster_key":"77c3cb8ebb026ea58b8c6db88feb9b198985a413dc9b89599d8d532b53559982","clean_bundle":{"format":"clean-skill-bundle-v1","source":"dotnet/skills/plugins/dotnet/skills/setup-local-sdk/SKILL.md","text_bytes":0,"source_commit":"95e7d0cb7994d47b5789baa68e13f7a2f348b956","skills_sh_rank":6040,"attachment_count":0,"text_attachments":0,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"plugins/dotnet/skills/setup-local-sdk/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"devops-infrastructure","import_tag":"skills-sh-top20k-2026-11","description":"Install a .NET SDK locally for safe preview testing, specific-version pinning, or reproducible team setups — without modifying the system-wide installation. USE FOR: trying .NET previews safely, testing specific SDK versions, installing MAUI or other workloads on a preview, updating or replacing an existing local SDK, creating reproducible team/CI install scripts, configuring global.json paths. DO NOT USE FOR: system-wide SDK installs, .NET hosts older than 10, runtime-only installs, or projects not using SDK-style commands.\n"}},"renderedAt":1793666057908}

setup-local-sdk Purpose Guide the user through installing a .NET SDK into a project-local directory and wiring it up via the feature (.NET 10+). The examples use .NET 11, but this works with any version — prerelease or stable. The result is a fully isolated SDK that: - Does not modify the system-wide .NET installation. - Is picked up automatically by commands from the project root. - Can be deleted to revert ( or ). When NOT to use - User wants a system-wide install — direct to the official installer. - Host is older than v10 — doesn't exist; explain and stop. - User needs a runtime-only inst…