[GH-ISSUE #4847] [Bug] Setup registers a version-specific entrypoint that breaks after a mise upgrade #3014

Open
opened 2026-10-31 00:34:51 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @yamz8 on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4847

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Setup, packaging, or upgrade

Observed behavior

When REA is installed with mise's npm backend and rea setup is run through it, the MCP registration written to the agent's config points into a version-specific directory reached through mise's latest symlink. Codex, for example, gets:

[mcp_servers.rea]
command = "$MISE_DATA_DIR/installs/npm-rea-agents/latest/node_modules/.mise/rea-agents@6.5.0/node_modules/rea-agents/scripts/rea.mjs"
args = [ "mcp" ]

The latest component moves to the new version when mise upgrades REA, but the rea-agents@6.5.0 component inside it does not, so the registered command stops existing and the agent can no longer start REA's MCP server. Nothing tells the user; the CLI keeps working because it goes through mise.

Reproduction

In a throwaway HOME and MISE_*_DIRs, with Node 26 on PATH:

mise use -g npm:rea-agents          # installs 6.5.0, latest -> 6.5.0
mkdir -p ~/.codex && : > ~/.codex/config.toml
mise x npm:rea-agents -- rea setup --client codex --yes </dev/null
grep '^command' ~/.codex/config.toml
# command = ".../npm-rea-agents/latest/node_modules/.mise/rea-agents@6.5.0/.../scripts/rea.mjs"

To show the upgrade, I installed 6.4.0 and then 6.5.0 in the same way. After the upgrade, latest -> 6.5.0, and latest/node_modules/.mise/ only contains rea-agents@6.5.0, so a command registered as latest/node_modules/.mise/rea-agents@6.4.0/... no longer exists. (When a version is pinned explicitly, e.g. mise x npm:rea-agents@6.4.0 -- rea setup, the registered path goes through installs/npm-rea-agents/6.4.0/ instead. That keeps resolving after an upgrade, but it keeps running the old version.)

Expected behavior

The registered command keeps working, and keeps following the installed version, after the package manager upgrades REA, the way the rea command on PATH does.

Impact and scope

Anyone who installs REA through a version manager that keeps each version in its own directory (mise, and probably asdf or Volta) and lets it upgrade. Their agents lose REA at the next release until rea setup is run again. We hit this while preparing an optional REA installer for Omarchy, which installs npm CLIs through mise wrappers that upgrade on use. So every user of that installer would be affected.

REA version

6.5.0 (also observed with 6.4.0)

Runtime and platform

Arch Linux (Omarchy), x86_64, Node.js 26.12.0, mise 2026.10.11

Interface

Package or setup

Earliest failure stage

Setup or provider admission

Relevant output or evidence

See the registered command above, and the latest symlink after an upgrade:

installs/npm-rea-agents/
  6 -> ./6.5.0
  6.5 -> ./6.5.0
  6.5.0/
  latest -> ./6.5.0

Analysis or suspected cause

From the source at 3ad1032: CURRENT_ENTRYPOINT_PATH is resolve(process.argv[1]) (src/process/CurrentEntrypointPath.ts#L11), and setupRegistrationCommand registers [entrypointPath, "mcp"] unless setup was started from a package runner (src/application/SetupHost.ts#L68). Under mise, argv[1] is the script inside the versioned install, so a path that depends on the release gets written.

Two possible fixes, neither tested:

  • an explicit option, e.g. rea setup --command <path> or a REA_REGISTRATION_COMMAND environment variable, so installers can register their own stable launcher (for us, ~/.local/bin/rea);
  • or, when a rea found on PATH runs this same package, registering that command instead of the resolved script path.

Additional context

Related to #115 (detecting a stale MCP server after an upgrade). This report is about the registered command no longer existing at all.

Originally created by @yamz8 on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4847 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Setup, packaging, or upgrade ### Observed behavior When REA is installed with [mise](https://mise.jdx.dev)'s npm backend and `rea setup` is run through it, the MCP registration written to the agent's config points into a version-specific directory reached through mise's `latest` symlink. Codex, for example, gets: ```toml [mcp_servers.rea] command = "$MISE_DATA_DIR/installs/npm-rea-agents/latest/node_modules/.mise/rea-agents@6.5.0/node_modules/rea-agents/scripts/rea.mjs" args = [ "mcp" ] ``` The `latest` component moves to the new version when mise upgrades REA, but the `rea-agents@6.5.0` component inside it does not, so the registered command stops existing and the agent can no longer start REA's MCP server. Nothing tells the user; the CLI keeps working because it goes through mise. ### Reproduction In a throwaway `HOME` and `MISE_*_DIR`s, with Node 26 on `PATH`: ```bash mise use -g npm:rea-agents # installs 6.5.0, latest -> 6.5.0 mkdir -p ~/.codex && : > ~/.codex/config.toml mise x npm:rea-agents -- rea setup --client codex --yes </dev/null grep '^command' ~/.codex/config.toml # command = ".../npm-rea-agents/latest/node_modules/.mise/rea-agents@6.5.0/.../scripts/rea.mjs" ``` To show the upgrade, I installed 6.4.0 and then 6.5.0 in the same way. After the upgrade, `latest -> 6.5.0`, and `latest/node_modules/.mise/` only contains `rea-agents@6.5.0`, so a command registered as `latest/node_modules/.mise/rea-agents@6.4.0/...` no longer exists. (When a version is pinned explicitly, e.g. `mise x npm:rea-agents@6.4.0 -- rea setup`, the registered path goes through `installs/npm-rea-agents/6.4.0/` instead. That keeps resolving after an upgrade, but it keeps running the old version.) ### Expected behavior The registered command keeps working, and keeps following the installed version, after the package manager upgrades REA, the way the `rea` command on `PATH` does. ### Impact and scope Anyone who installs REA through a version manager that keeps each version in its own directory (mise, and probably asdf or Volta) and lets it upgrade. Their agents lose REA at the next release until `rea setup` is run again. We hit this while preparing an optional REA installer for [Omarchy](https://github.com/basecamp/omarchy), which installs npm CLIs through mise wrappers that upgrade on use. So every user of that installer would be affected. ### REA version 6.5.0 (also observed with 6.4.0) ### Runtime and platform Arch Linux (Omarchy), x86_64, Node.js 26.12.0, mise 2026.10.11 ### Interface Package or setup ### Earliest failure stage Setup or provider admission ### Relevant output or evidence See the registered `command` above, and the `latest` symlink after an upgrade: ``` installs/npm-rea-agents/ 6 -> ./6.5.0 6.5 -> ./6.5.0 6.5.0/ latest -> ./6.5.0 ``` ### Analysis or suspected cause From the source at 3ad1032: `CURRENT_ENTRYPOINT_PATH` is `resolve(process.argv[1])` ([src/process/CurrentEntrypointPath.ts#L11](https://github.com/morluto/rea/blob/3ad1032b11edea2dcb054e78f951cc43159ae83d/src/process/CurrentEntrypointPath.ts#L11)), and `setupRegistrationCommand` registers `[entrypointPath, "mcp"]` unless setup was started from a package runner ([src/application/SetupHost.ts#L68](https://github.com/morluto/rea/blob/3ad1032b11edea2dcb054e78f951cc43159ae83d/src/application/SetupHost.ts#L68)). Under mise, `argv[1]` is the script inside the versioned install, so a path that depends on the release gets written. Two possible fixes, neither tested: - an explicit option, e.g. `rea setup --command <path>` or a `REA_REGISTRATION_COMMAND` environment variable, so installers can register their own stable launcher (for us, `~/.local/bin/rea`); - or, when a `rea` found on `PATH` runs this same package, registering that command instead of the resolved script path. ### Additional context Related to #115 (detecting a stale MCP server after an upgrade). This report is about the registered command no longer existing at all.
Author
Owner

@yamz8 commented on GitHub (Oct 17, 2026):

I dug further, and the trigger is narrower than "version managers". It's the bin shim the installer writes, so a correction and some more detail:

Cause. mise's npm backend now installs with its embedded aube installer by default (npm.package_manager = "auto"). aube writes node_modules/.bin/rea as a POSIX shell shim, not a symlink:

#!/bin/sh
# aube-bin-shim v2 target=../.mise/rea-agents@6.5.0/node_modules/rea-agents/scripts/rea.mjs
...

The shim runs node on that versioned store path, so process.argv[1] never sees the stable launcher. pnpm's global bin shims work the same way, so pnpm global installs are probably affected too (I haven't tested pnpm).

With plain npm it works. I had mise install with npm instead (MISE_NPM_PACKAGE_MANAGER=npm). bin/rea is then a symlink, and setup registered .../installs/npm-rea-agents/latest/bin/rea. After upgrading 6.4.0 → 6.5.0, that path still existed and --version printed 6.5.0. So I was wrong to suggest asdf or Volta in the report: it's the shim style, not version managers in general.

Why I haven't sent a PR. Each fix I can see touches a design decision you've made deliberately:

  1. Register the bare rea command. It's already classified as owned, but ClientRegistrationStatus.ts#L409 marks it stale on purpose, because it depends on the client's PATH.
  2. An explicit launcher option (rea setup --command <absolute path>, or an environment variable). An absolute path that isn't the current entrypoint is classified as foreign by isOwnedClientRegistrationCommand. Uninstall and doctor would then need some other way to prove that launcher is REA's, for example by recording it.
  3. Register realpath(argv[1]). This keeps ownership, since sameEntrypointPath already compares realpaths on POSIX, and the registration survives an upgrade until the old version is pruned. But it pins to one version until setup runs again, and it regresses installs where the bin link is the stable path and its target is versioned (Homebrew-style cellars).

Which direction would you accept? I'm happy to implement and test it. For context, we're adding REA as an optional install in Omarchy. That install goes through mise with its default installer, and mise up runs during system updates, so we can't avoid the aube layout on our side. Until there's a fix, we plan to run setup through npx -y rea-agents@latest setup, which registers the pinned npx command your doctor already knows how to check.

<!-- gh-comment-id:6238463172 --> @yamz8 commented on GitHub (Oct 17, 2026): I dug further, and the trigger is narrower than "version managers". It's the bin shim the installer writes, so a correction and some more detail: **Cause.** mise's npm backend now installs with its embedded [aube](https://github.com/aubepkg/aube) installer by default (`npm.package_manager = "auto"`). aube writes `node_modules/.bin/rea` as a POSIX shell shim, not a symlink: ```sh #!/bin/sh # aube-bin-shim v2 target=../.mise/rea-agents@6.5.0/node_modules/rea-agents/scripts/rea.mjs ... ``` The shim runs node on that versioned store path, so `process.argv[1]` never sees the stable launcher. pnpm's global bin shims work the same way, so pnpm global installs are probably affected too (I haven't tested pnpm). **With plain npm it works.** I had mise install with npm instead (`MISE_NPM_PACKAGE_MANAGER=npm`). `bin/rea` is then a symlink, and setup registered `.../installs/npm-rea-agents/latest/bin/rea`. After upgrading 6.4.0 → 6.5.0, that path still existed and `--version` printed 6.5.0. So I was wrong to suggest asdf or Volta in the report: it's the shim style, not version managers in general. **Why I haven't sent a PR.** Each fix I can see touches a design decision you've made deliberately: 1. **Register the bare `rea` command.** It's already classified as owned, but [ClientRegistrationStatus.ts#L409](https://github.com/morluto/rea/blob/662fad90723b3e5800962bcf02c8c2db1ea2bff5/src/application/ClientRegistrationStatus.ts#L409) marks it stale on purpose, because it depends on the client's `PATH`. 2. **An explicit launcher option** (`rea setup --command <absolute path>`, or an environment variable). An absolute path that isn't the current entrypoint is classified as foreign by [`isOwnedClientRegistrationCommand`](https://github.com/morluto/rea/blob/662fad90723b3e5800962bcf02c8c2db1ea2bff5/src/application/ClientRegistrationIdentity.ts#L169). Uninstall and doctor would then need some other way to prove that launcher is REA's, for example by recording it. 3. **Register `realpath(argv[1])`.** This keeps ownership, since [`sameEntrypointPath`](https://github.com/morluto/rea/blob/662fad90723b3e5800962bcf02c8c2db1ea2bff5/src/application/ClientRegistrationIdentity.ts#L120) already compares realpaths on POSIX, and the registration survives an upgrade until the old version is pruned. But it pins to one version until setup runs again, and it regresses installs where the bin link is the stable path and its target is versioned (Homebrew-style cellars). Which direction would you accept? I'm happy to implement and test it. For context, we're adding REA as an optional install in [Omarchy](https://github.com/basecamp/omarchy). That install goes through mise with its default installer, and `mise up` runs during system updates, so we can't avoid the aube layout on our side. Until there's a fix, we plan to run setup through `npx -y rea-agents@latest setup`, which registers the pinned npx command your doctor already knows how to check.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Reproduced the failure mode conceptually and the analysis is solid — the registered command embeds rea-agents@6.5.0 inside the latest symlink chain, so after a mise upgrade that component path disappears even though latest itself still resolves. Between the two suggested fixes, the second one (registering the rea command resolved from PATH when it runs the same package) feels more robust and requires no extra installer config, but it does assume PATH resolution at registration time stays valid at runtime. A small hardening could be to resolve the PATH entry at registration and also verify it still points to the same package on MCP startup, then fall back to the explicit command option if it diverges. This also aligns nicely with #115's stale-server detection. Thanks for including the throwaway-HOME repro — that made the scenario very easy to follow.

<!-- gh-comment-id:6248195562 --> @XinwangTao commented on GitHub (Oct 18, 2026): Reproduced the failure mode conceptually and the analysis is solid — the registered command embeds `rea-agents@6.5.0` inside the `latest` symlink chain, so after a mise upgrade that component path disappears even though `latest` itself still resolves. Between the two suggested fixes, the second one (registering the `rea` command resolved from PATH when it runs the same package) feels more robust and requires no extra installer config, but it does assume PATH resolution at registration time stays valid at runtime. A small hardening could be to resolve the PATH entry at registration and also verify it still points to the same package on MCP startup, then fall back to the explicit command option if it diverges. This also aligns nicely with #115's stale-server detection. Thanks for including the throwaway-HOME repro — that made the scenario very easy to follow.
Author
Owner

@XinwangTao commented on GitHub (Oct 18, 2026):

Reproduced the failure mode conceptually and the analysis is solid — the registered command embeds rea-agents@6.5.0 inside the latest symlink chain, so after a mise upgrade that component path disappears even though latest itself still resolves. Between the two suggested fixes, the second one (registering the rea command resolved from PATH when it runs the same package) feels more robust and requires no extra installer config, but it does assume PATH resolution at registration time stays valid at runtime. A small hardening could be to resolve the PATH entry at registration and also verify it still points to the same package on MCP startup, then fall back to the explicit command option if it diverges. This also aligns nicely with #115's stale-server detection. Thanks for including the throwaway-HOME repro — that made the scenario very easy to follow.

<!-- gh-comment-id:6248227975 --> @XinwangTao commented on GitHub (Oct 18, 2026): Reproduced the failure mode conceptually and the analysis is solid — the registered command embeds `rea-agents@6.5.0` inside the `latest` symlink chain, so after a mise upgrade that component path disappears even though `latest` itself still resolves. Between the two suggested fixes, the second one (registering the `rea` command resolved from PATH when it runs the same package) feels more robust and requires no extra installer config, but it does assume PATH resolution at registration time stays valid at runtime. A small hardening could be to resolve the PATH entry at registration and also verify it still points to the same package on MCP startup, then fall back to the explicit command option if it diverges. This also aligns nicely with #115's stale-server detection. Thanks for including the throwaway-HOME repro — that made the scenario very easy to follow.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3014
No description provided.