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 entirelyHideWindow = 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:
internal/git/git.go– Hardens all Git invocations (lines 43, 76, 127, 169, 191, 206, 317, 526)internal/shellenv/shell_command_windows.go– Applies to generic shell commands (lines 62, 90, 151)internal/daemon/proc_windows.go– Hardens daemon-side subprocesses (line 31)internal/daemon/recover_servers_windows.go– Protects recovery helpers (line 16)internal/daemon/service_render.go– Secures service-render commands (line 252)internal/config/config.go– Hardens configuration-related commands (line 420)internal/cli/doctor.go– Protects health-check Git commands (line 44)internal/agent/server_windows.go– Hardens the managed agent server (line 14)internal/pipeline/steps/common_exec.go– Secures pipeline step executors (line 161)internal/scm/scm.go– Hardens generic SCM commands (line 197)
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.Hardenininternal/winproc/harden_windows.gosetsCREATE_NO_WINDOWandHideWindowflags to prevent visible console allocation on Windows.- The function is idempotent and safe to call multiple times, preserving existing
SysProcAttrconfigurations likeCREATE_NEW_PROCESS_GROUP. - A no-op stub in
harden_other.goensures 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →