Windows SilentLauncher in Claude Subconscious: How It Spawns Background Workers Without Console Flash

The Windows SilentLauncher is a native C# executable in the letta-ai/claude-subconscious repository that creates a hidden PseudoConsole and sets the CREATE_NO_WINDOW flag to spawn Node.js background workers without the visible console flash that normally occurs on Windows 11 and Windows Terminal.

The letta-ai/claude-subconscious project implements a seamless way to run long-lived background tasks from Claude Desktop hooks. The Windows SilentLauncher, located at hooks/silent-launcher.exe, solves the persistent UX problem where spawning Node.js processes via npx or tsx triggers a brief but distracting console window appearance on Windows systems.

What Is the Windows SilentLauncher?

The Windows SilentLauncher is a small native Windows executable written in C# and compiled to hooks/silent-launcher.exe. Its sole purpose is to start a child Node/TSX process without ever showing a console window, eliminating the "flash" effect visible on Windows 11 and Windows Terminal when standard node commands create new consoles.

Unlike typical workarounds that merely hide the window after creation, this launcher prevents the window from ever being created by the OS, ensuring zero visual disruption to the user experience.

How the SilentLauncher Hides the Console Window

The launcher employs a two-pronged approach using modern Windows console APIs and specific process creation flags:

  1. Creating a hidden PseudoConsole (ConPTY) – The Windows API provides a virtual terminal attached to the process but with no visible window.
  2. Setting the CREATE_NO_WINDOW flag – This guarantees that the OS never allocates a console for the child process, regardless of subsystem flags in the executable.

Creating a Hidden PseudoConsole

In hooks/SilentLauncher.cs, the launcher initializes a ConPTY session with specific dimensions before spawning the child:

// Create a hidden pseudo‑console
var ptySize = new COORD { X = 120, Y = 30 };
CreatePseudoConsole(ptySize, ptyInR, ptyOutW, 0, out var hPC);

This PseudoConsole provides the Node.js process with a valid console handle for standard I/O operations while remaining completely invisible to the user.

Process Creation with CREATE_NO_WINDOW

The launcher constructs a command line that preloads a special bridge script and invokes the TSX CLI, then executes it with flags that suppress all window creation:

// Build the command line for the child (node + tsx loader + script)
var cmdLine = new StringBuilder();
cmdLine.Append("node");
cmdLine.Append(" --require ").Append(preloadPath);
cmdLine.Append(" --import ").Append(tsxEsmUrl);
cmdLine.Append(' ').Append(args[2]); // script path

// Launch the child with CREATE_NO_WINDOW and the pseudo‑console attribute
CreateProcess(null, cmdLine, …, flags: EXTENDED_STARTUPINFO_PRESENT |
                                   CREATE_NO_WINDOW |
                                   CREATE_UNICODE_ENVIRONMENT, …);

Source: [hooks/SilentLauncher.cs → line 53–84](https://github.com/letta-ai/claude-subconscious/blob/main/hooks/SilentLauncher.cs#L53-L84)

Spawning Background Workers with spawnSilentWorker

When the Subconscious system needs a detached background worker—such as scripts/send_worker_sdk.ts that communicates with the Letta SDK—it invokes the spawnSilentWorker helper defined in scripts/conversation_utils.ts.

The spawnSilentWorker Implementation

On Windows, this function resolves the absolute paths to silent-launcher.exe and the TSX CLI (node_modules/tsx/dist/cli.mjs), then executes the launcher with the worker script and a payload file:

import { spawnSilentWorker } from './conversation_utils.js';

// Inside send_messages_to_letta.ts …
const workerScript = path.join(__dirname, 'send_worker_sdk.ts');
const payloadFile  = path.join(TEMP_STATE_DIR, `payload-${hookInput.session_id}-${Date.now()}.json`);

fs.writeFileSync(payloadFile, JSON.stringify(sdkPayload), 'utf‑8');
const child = spawnSilentWorker(workerScript, payloadFile, hookInput.cwd);
log(`Spawned SDK worker (PID: ${child.pid})`);

Source: [send_messages_to_letta.ts → line 30–33](https://github.com/letta-ai/claude-subconscious/blob/main/scripts/send_messages_to_letta.ts#L30-L33)

Detached Execution Model

The spawnSilentWorker function passes detached: true to the spawn options. Because the SilentLauncher has already created a hidden PseudoConsole, the spawned worker inherits that invisible console context and continues running even after the original hook process exits. This enables fire-and-forget background tasks that persist for the duration of a conversation without holding open the parent Claude Desktop hook.

Bridging I/O with stdio-preload.cjs

Because PseudoConsole handles are incompatible with anonymous pipes for standard I/O redirection, the system uses an alternative strategy: temporary files. The launcher writes the worker's payload to a temp file and redirects stdout/stderr to another temp file, then uses a Node preload script to wire these files to the process streams.

The Preload Bridge Logic

The hooks/stdio-preload.cjs script reads environment variables SL_STDIN_FILE and SL_STDOUT_FILE to bridge the gap:

// hooks/stdio-preload.cjs
const stdinFile  = process.env.SL_STDIN_FILE;
const stdoutFile = process.env.SL_STDOUT_FILE;

if (stdinFile) {
  const data = fs.readFileSync(stdinFile);
  const sock = process.stdin;
  sock.pause();
  sock.unshift(data);
  process.nextTick(() => sock.push(null));
}

// Capture all writes
if (stdoutFile) {
  const fd = fs.openSync(stdoutFile, 'a');
  const origWrite = process.stdout.write.bind(process.stdout);
  process.stdout.write = (chunk, enc, cb) => {
    fs.writeSync(fd, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, enc || 'utf8'));
    return origWrite(chunk, enc, cb);
  };
  // same for stderr…
}

Source: hooks/stdio-preload.cjs

This approach allows the parent process to capture the worker's output after completion while maintaining the silent, windowless execution environment.

Cross-Platform Entry Points

The repository provides hooks/silent-npx.cjs as a platform-agnostic wrapper consumed by hooks.json. On Windows, this wrapper detects the presence of silent-launcher.exe and delegates execution to it; on macOS and Linux, it falls back to standard npx tsx execution:

// On Windows we delegate to silent‑launcher.exe
if (isWindows && fs.existsSync(silentLauncher) && fs.existsSync(tsxCli)) {
  child = spawn(silentLauncher, ['node', tsxCli, …scriptArgs], {
    stdio: 'inherit',
    windowsHide: true,
  });
}

Source: hooks/silent-npx.cjs → line 28‑38

Summary

  • The Windows SilentLauncher is a native C# executable at hooks/silent-launcher.exe that prevents console window creation entirely.

  • It uses the ConPTY API to create a hidden PseudoConsole and the CREATE_NO_WINDOW flag to ensure zero visual flash.

  • Background workers are spawned via spawnSilentWorker in scripts/conversation_utils.ts, which invokes the launcher with detached: true for persistence.

  • I/O redirection occurs through temporary files managed by hooks/stdio-preload.cjs, overcoming the incompatibility between PseudoConsole and anonymous pipes.

  • The system enables truly silent, fire-and-forget background workers on Windows while maintaining cross-platform compatibility through hooks/silent-npx.cjs.

Frequently Asked Questions

Why does the Windows SilentLauncher use temporary files instead of pipes?

The Windows PseudoConsole (ConPTY) API does not support standard anonymous pipe redirection for stdin/stdout. To work around this limitation, the launcher writes input to a temporary file and captures output to another, then uses the stdio-preload.cjs script to stream these files into the Node.js process's standard streams.

How does the background worker survive after the parent hook exits?

The worker process is spawned with the detached: true option, and because the SilentLauncher has already established a hidden console context, the child inherits this environment. This allows the Node.js worker to continue executing independently even after the Claude Desktop hook process that spawned it has terminated.

What Node.js scripts does the SilentLauncher typically execute?

According to the source code, the launcher primarily executes scripts/send_worker_sdk.ts via the TSX CLI loader. This script handles asynchronous communication with the Letta SDK. The entry point scripts/send_messages_to_letta.ts prepares the payload and initiates the launch sequence.

Is the SilentLauncher required on macOS or Linux?

No. The hooks/silent-npx.cjs wrapper detects the operating system and only invokes silent-launcher.exe on Windows. On macOS and Linux, the system uses the standard npx tsx command directly, as these platforms do not exhibit the console flash issue that necessitates the native launcher.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →