How no-mistakes Handles Windows Console Interactions with Process Hardening

The no-mistakes repository prevents console window flooding on Windows by using winproc.Harden, a helper that sets CREATE_NO_WINDOW and HideWindow flags on subprocesses while preserving I/O pipe redirection.

When running as a console-less daemon on Windows, no-mistakes spawns numerous child processes including Git operations, shell commands, and agent processes. Without intervention, each subprocess would trigger the Windows loader to allocate a visible console window, flooding the screen with dozens of pop-ups. The project solves this through a centralized process hardening utility implemented in internal/winproc.

The Problem: Console Window Flooding

Windows behavior dictates that child processes launched from a console-less parent automatically receive a fresh visible console window for their lifetime. Since no-mistakes operates as a daemon and runs agents, Git commands, provider CLIs, and various helper subprocesses, this would result in a cascade of rapidly appearing and disappearing console windows.

Issue #287 in the repository specifically addresses this UX problem. The solution requires suppressing the console window while maintaining the ability to capture stdout and stderr through pipes.

The Solution: The winproc.Harden Utility

The project introduces a small Windows-specific package that hardens child processes to prevent console allocation. This approach uses platform-specific system calls while providing a unified API across all operating systems.

Windows-Specific Implementation

In internal/winproc/harden_windows.go, the Harden function modifies exec.Cmd configurations to prevent window creation:

//go:build windows

package winproc

import (
	"os/exec"
	"syscall"

	"golang.org/x/sys/windows"
)

// Harden marks cmd so Windows launches it without a visible console window,
// preserving any creation flags already set (e.g. CREATE_NEW_PROCESS_GROUP)
// and leaving stdout/stderr redirection untouched.
func Harden(cmd *exec.Cmd) {
	if cmd == nil {
		return
	}
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	cmd.SysProcAttr.CreationFlags |= windows.CREATE_NO_WINDOW
	cmd.SysProcAttr.HideWindow = true
}

The function sets two critical attributes:

  • windows.CREATE_NO_WINDOW – Tells the Windows loader to skip console allocation entirely
  • HideWindow = true – Ensures the window remains hidden if created

The implementation preserves existing SysProcAttr settings, making it safe to call even when other process attributes (like CREATE_NEW_PROCESS_GROUP) are already configured.

Cross-Platform Compatibility

For non-Windows builds, internal/winproc/harden_other.go provides a no-op stub:

//go:build !windows

package winproc

import "os/exec"

func Harden(cmd *exec.Cmd) {
	// No-op on non-Windows platforms
}

This ensures the same API works across Linux, macOS, and Windows without conditional compilation at every call site.

Where Process Hardening Is Applied

The winproc.Harden call appears throughout the codebase wherever subprocesses might spawn on Windows:

Because the function is idempotent, developers can call it unconditionally without checking whether SysProcAttr is already populated.

Technical Implementation Examples

Direct Usage Pattern

When executing external commands, hardening is applied immediately after command construction:

package main

import (
	"os"
	"os/exec"

	"github.com/kunchenguid/no-mistakes/internal/winproc"
)

func runGitStatus() error {
	cmd := exec.Command("git", "status")
	
	// Prevent console window on Windows
	winproc.Harden(cmd)
	
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

Pipeline Integration

In internal/pipeline/steps/common_exec.go, hardening integrates with the execution context:

func execCommand(ctx context.Context, cmd *exec.Cmd) error {
	// Setup command context and cancellation...
	
	// Ensure no console window appears on Windows
	winproc.Harden(cmd)
	
	// Execute with proper I/O handling
	return shellenv.RunShellCommand(ctx, cmd)
}

The hardening occurs before stream attachment, ensuring that while the console window is suppressed, the parent process retains full access to the child's output and error streams through pipes.

Summary

  • winproc.Harden in internal/winproc/harden_windows.go sets CREATE_NO_WINDOW and HideWindow flags to prevent visible console allocation on Windows.
  • The function is idempotent and safe to call multiple times, preserving existing SysProcAttr configurations like CREATE_NEW_PROCESS_GROUP.
  • A no-op stub in harden_other.go ensures cross-platform compatibility without build tags at every call site.
  • The utility is applied consistently across Git operations, shell commands, daemon processes, and pipeline steps to prevent window flooding while maintaining I/O redirection.
  • Standard streams remain functional through pipes, allowing the daemon to capture output normally despite the lack of a console window.

Frequently Asked Questions

What is process hardening in no-mistakes?

Process hardening in no-mistakes refers to the winproc.Harden utility that configures Windows subprocesses to run without visible console windows. According to the source code in internal/winproc/harden_windows.go, it modifies SysProcAttr to include CREATE_NO_WINDOW and HideWindow flags, preventing the Windows loader from allocating a console window while keeping stdout and stderr pipes intact.

Why does no-mistakes need to suppress console windows on Windows?

When no-mistakes runs as a console-less daemon, spawning child processes like Git, shell commands, or agents would normally cause Windows to open a fresh visible console window for each subprocess. As documented in issue #287, this results in dozens of rapidly appearing and disappearing windows that flood the screen. Process hardening eliminates this behavior while preserving the ability to capture command output.

Is winproc.Harden safe to call multiple times?

Yes, winproc.Harden is designed to be idempotent and safe for repeated invocation. The function checks if cmd.SysProcAttr is nil and initializes it if necessary, then uses bitwise OR to add the CREATE_NO_WINDOW flag. This means calling it multiple times or on commands with existing process attributes will not cause errors or lose existing configuration.

Does process hardening affect stdout and stderr capture?

No, process hardening does not interfere with I/O redirection. The implementation specifically preserves stdout and stderr pipes, allowing the parent daemon to capture output and errors normally. The CREATE_NO_WINDOW flag only suppresses the console window allocation; it does not detach the process from its parent's standard streams or pipes.

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 →