Skip to content

Install the mounted project's pinned tools at provision time - #13

Merged
defkode merged 1 commit into
mainfrom
mise-project-install
Aug 30, 2026
Merged

Install the mounted project's pinned tools at provision time#13
defkode merged 1 commit into
mainfrom
mise-project-install

Conversation

@defkode

@defkode defkode commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Follow-up to #12, which made mise actually read the mounted project's mise.toml. This installs what that config asks for.

Problem

A fresh sandbox now greets you with:

mise WARN  missing: node@24.16.0 ruby@4.0.5

The versions are not permanently absent — auto_install defaults to true, so mise fetches a missing tool the first time a shim runs it. The problem is when. Left alone, a multi-minute download lands on whoever first types ruby, minutes after orbx reported the machine ready, with nothing on the provisioning log they were watching. An agent driving orbx run cannot distinguish that from a hang. In practice the first person to hit it just ran mise install by hand — precisely the step automated here.

Fix

At the end of the mise section of user-setup.sh:

while read -r projdir; do
  for f in mise.toml .mise.toml .tool-versions; do
    [ -f "$projdir/$f" ] || continue
    log "Installing project tools pinned by $projdir/$f..."
    ( cd "$projdir" && "$HOME/.local/bin/mise" install ) \
      || log "mise install failed in $projdir (continuing)"
    break
  done
done < <(awk '$3 == "virtiofs" { print $2 }' /proc/mounts)

The path is discovered, not passed in. This template never learns the project path — orbx::mount_target only rewrites paths under $HOME, and a project outside it keeps an absolute path the template cannot guess. OrbStack surfaces every host share as a virtiofs mount, so the mount table is exactly the set of directories that came from the host.

It reads the project, never writes it. mise install resolves versions into ~/.local/share/mise and touches the repo only when lockfiles are enabled, which they are not by default. The mount is the user's real working tree, so it has to come back clean.

Non-fatal and logged, consistent with the rest of provision.sh.

Verification

Fresh machine (orbx-install-test, since deleted) with a project pinning ruby 4.0.5, node 24.16.0, yarn 1.22.22:

Check Result
Provisioning log [user] Installing project tools pinned by /home/tomasz/code/orbx-install-test/mise.toml...
mise ls — no shim invoked, no manual install node 24.16.0, ruby 4.0.5, yarn 1.22.22, all from the project config
Interactive zsh -ic no warning of any kind; ruby -v / node -v / yarn -v correct immediately
Host directory after a full provision same file list, identical shasum — repo untouched

shellcheck clean; 90/90 bats (89 + the new template test). YAML re-parsed to confirm the block reaches the guest intact.

Still open

The trust scoping gap from #12 is untouched: a project outside the host's $HOME still falls outside trusted_config_paths, and since mise skips an untrusted config, this install step would find nothing to do there either. The mount table used here is exactly the mechanism that would close it — happy to do that as a third PR if wanted.

#12 made mise read the project's mise.toml; this installs what it asks
for. mise auto-installs a missing tool the first time a shim runs it
(auto_install defaults to true), so the versions were never permanently
absent -- the problem is when they arrive. Left alone, the download lands
on whoever first types `ruby`, minutes after orbx reported the machine
ready, with nothing on the provisioning log they were watching. An agent
driving `orbx run` cannot tell that from a hang, and the first person to
hit it in practice just ran `mise install` by hand, which is precisely
the step automated here.

The project path is discovered rather than passed in: this template never
learns it, since orbx::mount_target only rewrites paths under $HOME and a
project outside it keeps an absolute path the template cannot guess.
OrbStack surfaces every host share as a virtiofs mount, so the mount
table is exactly the set of directories that came from the host. That
same table is how the trust gap noted in #12 could later be closed, but
this change deliberately leaves trust alone.

Reads the project, never writes it. `mise install` resolves versions into
~/.local/share/mise and touches the repo only when lockfiles are enabled,
which they are not by default. The mount is the user's real working tree,
so it has to come back clean.

Verified on a fresh machine pinning ruby 4.0.5, node 24.16.0 and yarn
1.22.22: the provisioning log records the step, `mise ls` reports all
three installed with no shim ever invoked and no manual install, an
interactive shell warns about nothing, and the host directory is
byte-identical afterwards.
@defkode
defkode merged commit c0181af into main Aug 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant