Skip to content

fix(windows): suppress startup-folder cmd window flash via wscript silent launcher #70788

@gthgomez

Description

@gthgomez

Problem

On Windows, the Startup folder login item (OpenClaw Gateway.cmd) launches the gateway using:

```batch
start "" /min cmd.exe /d /c C:\Users<user>.openclaw\gateway.cmd
```

The `/min` flag minimizes the window but does not suppress rendering — Windows still composites the `cmd.exe` frame before minimizing it. On Windows 11 this produces a visible white/black terminal flash on screen at every login.

Root location: `src/daemon/schtasks.ts` → `renderStartupLaunchCommand()` / `buildStartupLauncherScript()`

This is the startup-folder variant of the same root cause in #57682 (visible CMD window during `openclaw update` gateway restart).

Environment

  • Windows 11 Home 10.0.26200
  • OpenClaw 2026.4.21
  • Startup folder item: `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\OpenClaw Gateway.cmd`

Expected Behaviour

Gateway starts at login with zero visible window — no flash, no minimized taskbar entry.

Proposed Fix

Replace `start "" /min cmd.exe` with a `wscript.exe` VBScript shim. `wscript.exe` with window style `0` suppresses the window before the process is created — the frame never enters the compositor. This is the canonical Windows method for truly invisible background process launch.

The fix lives entirely in `src/daemon/schtasks.ts`. Instead of one `.cmd` in the Startup folder, generate two files:

  1. `OpenClaw Gateway.cmd` — unchanged path/name (service detector still finds it), now delegates to the `.vbs`
  2. `OpenClaw Gateway.vbs` — the silent launcher

`src/daemon/schtasks.ts` — `renderStartupLaunchCommand()`:

```typescript
// BEFORE
function renderStartupLaunchCommand(scriptPath: string): string {
return `start "" /min cmd.exe /d /c ${quoteCmdScriptArg(scriptPath)}`;
}

function buildStartupLauncherScript(opts: StartupScriptOpts): string {
const lines = ['@echo off'];
if (opts.description) lines.push(`rem ${opts.description}`);
lines.push(renderStartupLaunchCommand(opts.scriptPath));
return lines.join('\r\n') + '\r\n';
}
```

```typescript
// AFTER
const VBS_LAUNCHER_FILENAME = 'OpenClaw Gateway.vbs';

// window style 0 = hidden — frame is never created, zero flash
function buildStartupVbsLauncher(gatewayCmdPath: string): string {
const escaped = gatewayCmdPath.replace(/"/g, '""');
return [
`Set sh = CreateObject("WScript.Shell")`,
`sh.Run "cmd.exe /d /c """ & "${escaped}" & """", 0, False`,
].join('\r\n') + '\r\n';
}

function buildStartupLauncherScript(opts: StartupScriptOpts): string {
const vbsPath = path.join(path.dirname(opts.startupItemPath), VBS_LAUNCHER_FILENAME);
const lines = ['@echo off'];
if (opts.description) lines.push(`rem ${opts.description}`);
// delegate to .vbs so service detector still finds the .cmd at its registered path
lines.push(`wscript.exe //nologo "${vbsPath}"`);
return lines.join('\r\n') + '\r\n';
}

export { buildStartupVbsLauncher, VBS_LAUNCHER_FILENAME };
```

Install path (wherever `installStartupFolderItem` writes the `.cmd`): also write the `.vbs` alongside it.

Uninstall path: also remove the `.vbs`.

Why Not Other Approaches

Approach Problem
`start /min` (current) Window flashes before minimizing
PowerShell `-WindowStyle Hidden` PowerShell host itself flashes
Task Scheduler hidden flag Unreliable on interactive logon sessions
`CREATE_NO_WINDOW` in Node spawn Only applies to Node-spawned processes, not Startup folder items launched by Windows shell
VBScript window style 0 ✅ No window ever created — zero flash

Verified

  • `wscript.exe` confirmed present on Windows 11 and all supported Windows versions
  • `wscript.exe //nologo` suppresses the VBScript logo banner
  • The `.cmd` path stays unchanged — `openclaw gateway status` service detection is unaffected
  • On VBScript deprecation (Windows 11 24H2+): if `wscript.exe` is eventually removed, the fallback should be a small compiled shim. Suggest adding a `// TODO(windows-vbs-deprecation)` at the generation site.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions