Environment Manager
MangoStudio can tell a non-expert what their machine is missing, install or update it with one
click on Linux, macOS and Windows, and make sure the toolchain it chose is the one every spawned
process actually runs with: the shell tool, the terminal, vendor agent CLIs and the installers
themselves. The surface lives under Environments and describes whichever machine the
environmentId search param names; the hub’s own machine is local.
Where things run
| Concern | Owner |
|---|---|
| Detecting toolchains, version managers and agent CLIs | Runtime (crates/mangostudio-runtime) |
Building the environment a spawned process starts with (commands/toolchain.rs) |
Runtime (crates/mangostudio-runtime) |
| Storing and validating the per-environment toolchain selection | Hub (apps/api) |
| Recipes, guards, audit rows, prerequisite findings, the setup checklist | Hub (apps/api) |
| Rendering cards, the picker and the checklist | Frontend |
Setup checklist
Environments → Overview opens with a Setup section for people who do not know what a version manager is. Each row is a finding with the remedy that clears it:
- Git installed (on Windows,
git.install.windowsrunswinget install --id Git.Git); - a Node LTS that is neither below MangoStudio’s floor nor past its support window;
- Bun, marked optional;
- at least one agent CLI installed and signed in;
- the hub running as a user service, on the Local environment only.
Nothing here adds an endpoint. The section reads the same queries the Toolchains, Agents and
This machine tabs already own, so the checklist cannot disagree with mangostudio doctor.
Toolchain selection
Every environment carries a selection, { node: 'auto' | <path>, bun: 'auto' | <path> },
stored in environment_toolchains keyed by (userId, environmentId). The Local environment is
virtual, so local is a sentinel key here exactly as it is for install runs, and there is no
foreign key to environments. Deleting an environment removes its row in the same transaction.
PUT /api/environments/:id/toolchainwrites one or both fields. A path is accepted only when the environment’s own probe reported an installation at exactly that path; anything else is a 422 that names the expected values and the received one. An environment that cannot be probed answers 503.- Every listed environment includes its
toolchain; absent reads asautofor both. - The Toolchains tab offers Use this version on every Node and Bun installation and Back to automatic once one is pinned; the effective line says what spawned processes run with.
The hub resolves the selection and sends it on every spawn method — shell.run,
install.run, terminal.open and external-agent.open. The runtime’s commands/toolchain.rs builds
the base environment once per spawn: at most one directory per runtime is put first on PATH,
plus NVM_DIR, FNM_DIR or BUN_INSTALL when the directory came from that manager and the
variable was not already set. Each consumer then applies its own secret policy on top.
auto means “what a login shell would see”, computed without executing any profile: nvm’s
default alias (including lts/* chains and the listing-based aliases node, stable and a
bare major), then fnm’s default alias, then the well-known directories the scanner already
knows. On Windows that includes %ProgramFiles%\nodejs, because the Node MSI edits the machine
PATH and a runtime that is already running never sees that edit. A selection is omitted for
a runtime whose manifest does not advertise features.toolchain; such a peer keeps its own
PATH exactly as before.
What the scanner knows
Each installation carries a pathSource: nvm, fnm and volta come from the
version-manager classification (fnm’s Windows default root %APPDATA%\fnm and macOS root are
recognised without FNM_DIR); bun is Bun’s own installer; winget is not visible by path,
because winget’s MSI and the nodejs.org MSI both land in Program Files\nodejs, so a Windows
probe asks winget list --id OpenJS.NodeJS.LTS --exact once per scan and marks the match. A
probe that times out leaves the installation as system; the exit-code allowlist on the winget
recipes makes an install offered on top of a winget Node harmless.
git, fnm and winget are probed as runtimes (winget only on Windows targets). fnm is also
a version manager with the same status shape as nvm: managed versions, the default alias, the
current version and LTS status per version. Cursor’s CLI is found under its current binary name
agent as well as the older cursor-agent.
A prerequisite-missing finding names a recipe this machine would offer and the tool it needs
but does not have. Nothing installs winget itself, so its remedy is a link to App Installer on
the Microsoft Store, rendered with the copy-only shape rather than a run button. A remedy is a
bare URL and never a sentence: it is interpolated into a localized finding message, so prose put
there would reach a pt-BR reader in English, and the frontend only renders a remedy as a
followable link when the whole value is a URL.
Recipes
The recipe table is described in environment-installs.md.
What matters for this page:
- Windows Node defaults to winget’s
OpenJS.NodeJS.LTS(install and upgrade; the.LTSpackage tracks the current LTS line, so an upgrade crosses majors when Node promotes a new one). fnm is the second, helper-managed Node manager: installed through winget on Windows, driven on every platform throughfnm installandfnm defaultonly — neverfnm use, which needs a shell hook a service-launched runtime would not see. Every other Node installation (nvm-windows, Volta, a nodejs.org MSI, Scoop, mise) is detected, never managed: the card lists it with its source and its update action is copy-only. - Update and uninstall exist for Bun, Claude Code, Codex and Cursor. A recipe MangoStudio runs
must have a vendor-documented shape; Codex and Cursor do not document an uninstall, so those two
are listed as copy-only commands with the reason beside them. A runnable uninstall is offered
only when the binary that actually runs is one the recipe’s own
writescover — the file it deletes, or a file inside a directory it deletes. A Homebrew Bun or a package-managedclaudeis detected and updated, never uninstalled from here, because that step would remove a different installation (or none) and still report success. Copy-only uninstalls stay visible whatever the provenance: they remove nothing themselves. Bun’s uninstall removes the default root (~/.bun) and proves abin/bunis inside it first;$BUN_INSTALLis deliberately not expanded, because it is a prefix rather than the Bun directory and a machine pointing it at a shared location would turn the step into a delete of that whole tree. Tracked in #1011. - Chains: “Install Node” on a POSIX machine without nvm runs nvm first, then Node, then sets the default, with one confirmation listing every step and one console per step. On Windows the default chain is one step; the fnm alternative is three.
CLI mirror
mangostudio env install <recipe> and mangostudio env update <recipe> call the same install
service and stream the same log to the terminal, and mangostudio env toolchain reads or writes
the same selection as the picker, for people on SSH. See cli.md.
Deferred
Node managers beyond winget LTS and fnm (nvm-windows v2 once it has a winget id, a POSIX
fnm.install, detect-only classification for Scoop and mise) are tracked in
#1011.