Summary
The MiniMax Code desktop app's startup pre-flight check misidentifies the daemon's own CLI shim at <dataDir>/bin/mavis.cmd (a 172-byte Windows batch file the daemon writes on first boot to expose the mavis command via the bundled cli.js) for a global npm install of @minimax/mavis. The check produces a false-positive conflict dialog and a self-recovery loop that the user cannot break without manual intervention.
Environment
- MiniMax Code version 3.0.42 (daemon mtime 2026-06-09, version 3.0.42 per
daemon/package.json)
- Windows 10
- Node 22.22.3, npm 10.9.8
- No global npm install of
@minimax/mavis (npm list -g @minimax/mavis returns empty; npm root -g is %AppData%\Roaming\npm\node_modules which contains no @minimax directory)
- Reproducible after the vendor's silent auto-update has run at least once (the trigger condition: the user-state
bin/mavis.cmd exists from a prior boot AND the auto-updater has stamped the install)
Steps to reproduce
- Install MiniMax Code via the official installer.
- Launch MiniMax Code once. Verify the daemon creates the CLI shim at
<dataDir>/bin/mavis.cmd (the daemon's first-boot does this — see daemon.js:349371-349384 in the bundle, function ensureMavisCli()).
- Wait for the vendor's auto-updater to fire. The default update interval is approximately 30 minutes after first launch (observed in the wild, but not documented in any public spec; the actual interval is per the Updater config embedded in the app).
- The next user-initiated or auto-triggered relaunch hits the "Installation Conflict Detected" dialog.
Observed behavior
The app shows:
Installation Conflict Detected
The npm package @minimax/mavis is already installed (<dataDir>\bin\mavis). It conflicts with the desktop app. Please uninstall it first, then restart the app:
npm uninstall -g @minimax/mavis
The app then enters a "recovery" loop that:
- Calls
npm uninstall -g @minimax/mavis (returns up to date in Nms — no-op, because nothing is globally installed)
- Removes the scheduled tasks
MavisDaemon and AgentArchonDaemon
- Relaunches
- Hits the same conflict check
- Repeats indefinitely (every ~5 seconds in the captured log)
The daemon never starts. Port 15321 is never bound. The MiniMax Code window never appears.
Expected behavior
The conflict check should return a negative result because no global install exists. The recovery loop should detect that the npm uninstall was a no-op and stop, rather than relaunching into the same false-positive.
Evidence
archon-06-09.log lines from one observed failure (timestamps from the user's local log; path redacted to <dataDir>):
[06:39:06.990] [info] [Daemon] mode=prod, NODE_ENV=undefined
[06:39:07.599] [info] Data directory already migrated (.mavis → .minimax)
[06:39:07.602] [error] [Daemon] npm package @minimax/mavis conflict detected: <dataDir>\bin\mavis
[06:39:24.514] [info] [KillNpmDaemon] Removed scheduled task: MavisDaemon
[06:39:24.547] [info] [KillNpmDaemon] Removed scheduled task: AgentArchonDaemon
[06:39:31.731] [info] [UninstallNpm] up to date in 6s
[06:39:32.969] [error] [Daemon] npm package @minimax/mavis conflict detected: <dataDir>\bin\mavis
[06:39:51.379] [info] [KillNpmDaemon] Removed scheduled task: MavisDaemon
[06:39:51.422] [info] [KillNpmDaemon] Removed scheduled task: AgentArchonDaemon
[06:39:51.915] [info] [UninstallNpm] up to date in 283ms
[06:39:52.XXX] [error] [Daemon] npm package @minimax/mavis conflict detected: <dataDir>\bin\mavis
The conflict error and the up to date no-op alternate ~5 seconds apart, confirming the self-recovery loop. Total observed run: 16 conflict detections in a 6-minute window before the user intervened.
What's known about the conflicting file
<dataDir>/bin/mavis.cmd is a 172-byte Windows batch file the daemon's first-boot writes itself. The actual content (from the user's install):
@echo off
chcp 65001 > nul
set ELECTRON_RUN_AS_NODE=1
"<install-path>\MiniMax Code.exe" "<install-path>\resources\resources\daemon\cli.js" %*
It is NOT a global npm install. It is a self-installed shim that invokes the bundled cli.js via the Electron binary. The same logic is in the daemon bundle at daemon.js:349371-349384:
const localBinDir = path.join(_config.dataDir, "bin");
mkdirSync(localBinDir, { recursive: true });
const isWin = process.platform === "win32";
const localSymlink = path.join(localBinDir, isWin ? "mavis.cmd" : "mavis");
if (isWin) {
const wrapperContent = `@echo off\r\r\nchcp 65001 > nul\r\r\nnode "${cliEntry}" %*\r\r\n`;
let needsWrite = true;
try {
if (existsSync(localSymlink) && readFileSync(localSymlink, "utf-8") === wrapperContent) {
needsWrite = false;
}
} catch {}
if (needsWrite) writeFileSync(localSymlink, wrapperContent);
} else {
// POSIX: real symlink
}
(Note: the bundled wrapperContent template invokes node "${cliEntry}", but the version on the user's install invokes the Electron binary as Node via ELECTRON_RUN_AS_NODE=1. The exact content differs from the bundled template, but the intent — exposing mavis as a CLI shim — is the same.)
Where the conflict check is NOT (helpful for triage)
The strings npm package @minimax/mavis conflict detected, KillNpmDaemon, UninstallNpm, and MavisDaemon do NOT appear in the current daemon.js bundle (verified by ripgrep against daemon.js version 3.0.42). The conflict-detection code may live in:
app.asar (the Electron renderer, 143MB, not currently extractable without npx @electron/asar)
- A different module loaded at runtime
- A newer daemon build installed by the silent auto-updater
If the maintainer can identify the actual location of the conflict check, that would unblock the fix. The log evidence above should make that straightforward.
Suggested fix (vendor-side)
Replace the filesystem-presence check at the conflict-detection call site with the canonical npm list -g @minimax/mavis check, which returns the right answer (no global install) and does not false-positive on the daemon's own self-installed shim. The daemon bundle already has NPM_REGISTRY = "https://npmmirror.xaminim.com/" and NPM_PACKAGE = "@minimax/mavis" (see daemon.js:216139-216140) and a fetchLatestNpmVersion() function (L216185+) that consults the registry — the same call pattern would correctly identify the absent global install.
Additionally, the recovery loop should detect the up to date in Nms no-op response from npm uninstall and exit instead of relaunching into the same false-positive.
Workaround (until the vendor fixes it)
The user can rename the bin/ directory so the conflict check sees a missing path, then re-launch. After a successful boot, the daemon re-creates bin/ correctly. Note: the daemon's first-boot logic may re-seed other user-state files with defaults; users who customize the agent's opencode config should re-apply their changes after the relaunch.
Get-Process -Name 'MiniMax Code' -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 2
if (Test-Path "$env:USERPROFILE\.minimax\bin") {
Rename-Item "$env:USERPROFILE\.minimax\bin" "$env:USERPROFILE\.minimax\bin-disabled-by-fix"
}
Start-Process -FilePath (Get-Command 'MiniMax Code.exe').Source
Start-Sleep -Seconds 15
Get-NetTCPConnection -LocalPort 15321 -State Listen
Severity
P3 (medium). The app is blocked from starting, but the user can recover with a documented workaround that does not touch the bundle. A P0/P1 severity would require that the workaround be impossible, undocumented, or destructive.
Related prior issues (same vendor app-lifecycle family)
Summary
The MiniMax Code desktop app's startup pre-flight check misidentifies the daemon's own CLI shim at
<dataDir>/bin/mavis.cmd(a 172-byte Windows batch file the daemon writes on first boot to expose themaviscommand via the bundledcli.js) for a global npm install of@minimax/mavis. The check produces a false-positive conflict dialog and a self-recovery loop that the user cannot break without manual intervention.Environment
daemon/package.json)@minimax/mavis(npm list -g @minimax/mavisreturns empty;npm root -gis%AppData%\Roaming\npm\node_moduleswhich contains no@minimaxdirectory)bin/mavis.cmdexists from a prior boot AND the auto-updater has stamped the install)Steps to reproduce
<dataDir>/bin/mavis.cmd(the daemon's first-boot does this — seedaemon.js:349371-349384in the bundle, functionensureMavisCli()).Observed behavior
The app shows:
The app then enters a "recovery" loop that:
npm uninstall -g @minimax/mavis(returnsup to date in Nms— no-op, because nothing is globally installed)MavisDaemonandAgentArchonDaemonThe daemon never starts. Port 15321 is never bound. The MiniMax Code window never appears.
Expected behavior
The conflict check should return a negative result because no global install exists. The recovery loop should detect that the
npm uninstallwas a no-op and stop, rather than relaunching into the same false-positive.Evidence
archon-06-09.loglines from one observed failure (timestamps from the user's local log; path redacted to<dataDir>):The conflict error and the
up to dateno-op alternate ~5 seconds apart, confirming the self-recovery loop. Total observed run: 16 conflict detections in a 6-minute window before the user intervened.What's known about the conflicting file
<dataDir>/bin/mavis.cmdis a 172-byte Windows batch file the daemon's first-boot writes itself. The actual content (from the user's install):It is NOT a global npm install. It is a self-installed shim that invokes the bundled
cli.jsvia the Electron binary. The same logic is in the daemon bundle atdaemon.js:349371-349384:(Note: the bundled
wrapperContenttemplate invokesnode "${cliEntry}", but the version on the user's install invokes the Electron binary as Node viaELECTRON_RUN_AS_NODE=1. The exact content differs from the bundled template, but the intent — exposingmavisas a CLI shim — is the same.)Where the conflict check is NOT (helpful for triage)
The strings
npm package @minimax/mavis conflict detected,KillNpmDaemon,UninstallNpm, andMavisDaemondo NOT appear in the currentdaemon.jsbundle (verified by ripgrep againstdaemon.jsversion 3.0.42). The conflict-detection code may live in:app.asar(the Electron renderer, 143MB, not currently extractable withoutnpx @electron/asar)If the maintainer can identify the actual location of the conflict check, that would unblock the fix. The log evidence above should make that straightforward.
Suggested fix (vendor-side)
Replace the filesystem-presence check at the conflict-detection call site with the canonical
npm list -g @minimax/mavischeck, which returns the right answer (no global install) and does not false-positive on the daemon's own self-installed shim. The daemon bundle already hasNPM_REGISTRY = "https://npmmirror.xaminim.com/"andNPM_PACKAGE = "@minimax/mavis"(seedaemon.js:216139-216140) and afetchLatestNpmVersion()function (L216185+) that consults the registry — the same call pattern would correctly identify the absent global install.Additionally, the recovery loop should detect the
up to date in Nmsno-op response fromnpm uninstalland exit instead of relaunching into the same false-positive.Workaround (until the vendor fixes it)
The user can rename the
bin/directory so the conflict check sees a missing path, then re-launch. After a successful boot, the daemon re-createsbin/correctly. Note: the daemon's first-boot logic may re-seed other user-state files with defaults; users who customize the agent's opencode config should re-apply their changes after the relaunch.Severity
P3 (medium). The app is blocked from starting, but the user can recover with a documented workaround that does not touch the bundle. A P0/P1 severity would require that the workaround be impossible, undocumented, or destructive.
Related prior issues (same vendor app-lifecycle family)