Post-Mortem ⏱️ 6 min read

Two Slashes Killed Our Terminals (Godmode+ Found It First Try)

TL;DR

>> The symptom: Every spawned Windows Terminal tab opened as a dead cmd.exe window. No Claude Code. Useless terminal.

>> The fake bug: We thought it was claude -p print mode. Rewrote the helper. Still broken.

>> The real bug: Git Bash used to defang //c/c when passing to native exes. It doesn't anymore. cmd saw a literal //c, didn't recognise the switch, dropped to interactive mode.

>> The fix: MSYS2_ARG_CONV_EXCL='/c' wt.exe ... -- cmd /c <launcher>. Two characters changed. Verified in one smoke test.

>> How Godmode+ won: Phase 5's smoke test — "verify the build actually works" — surfaced the real root cause that hours of manual debugging had missed.

The symptom: every new tab was DOA

Every time one of our scripts spawned a new Windows Terminal tab, the tab opened as a black window with the cmd banner. The prompt text we'd written sat below it, dangling like someone had typed it but never pressed Enter.

No Claude TUI. No prompt box. No way to interact. A perfectly useless terminal.

Think of it like a car that turns on but never starts the engine. The dashboard lights come on. The radio plays. But nothing moves. You can't tell from the outside that the engine never engaged — you can only tell because the car isn't driving.

The spawn chain: how a terminal SHOULD be born

Spawning a fresh Claude Code session in Windows is a four-step relay. Each step hands off to the next process, and any link can break.

[1] wt.exe new-tab
Opens a fresh Windows Terminal tab with the "Claude Code (Admin)" profile. This is the only step the user sees as "a terminal appearing".
If it breaks: no tab ever appears. Loud failure — easy to debug.

First hypothesis: blame claude -p

The original helper had a default branch that invoked claude -p <prompt> — "print mode." Print mode runs claude, prints the response to stdout, and exits.

That's exactly what produces a dead terminal: claude prints, exits, bash falls through, the tab parks at a dead shell with the response text on screen. Open and shut. Obvious culprit.

[ HYPOTHESIS 1 :: claude -p ] >> spawn tab >> bash runs `claude -p "<prompt>"` >> claude prints response & exits >> bash continues, tab idles RESULT: dead tab looks exactly like our symptom [ FIX :: always interactive ] >> remove claude -p branch entirely >> spawn always runs `claude` (TUI) >> add --done-flag for auto-close >> tab survives until task ships RESULT: smoke-test it does it actually work now?
The first fix made every spawn use interactive claude. Reasonable. Not enough.

So we rewrote the helper. Removed the print-mode branch. Made every spawn use interactive claude. Shipped the change.

Then Godmode+ ran the smoke test.

Phase 5: the smoke test refused to nod along

Godmode+ runs in phases. Build is phase 2. Smoke test — "verify the deliverable actually works in the real environment" — is phase 5. It's the phase that exists specifically to catch builds that looked done.

The smoke test spawned a tab via the fixed helper, took a screenshot, and asked the obvious question. Is there a Claude TUI rendered in that screenshot? There was not.

screenshot[0] :: cmd banner + dangling prompt text + cursor ··· no TUI ··· smoke test FAILED

This is the moment a normal "ship it" workflow ships it. Type-check passed. Lint passed. The diff looked sensible. But the spawned tab was dead, and only an actual spawn-and-screenshot would prove it.

Without phase 5, this bug ships. The whole point of Godmode+ is that "the code compiles" is not the same as "the feature works." A smoke test is cheap. A user discovering the bug in production is not.

Follow the process tree

When a build looks healthy but the output is wrong, the next move is forensics on the process tree. What's actually alive in that tab? What died?

WindowsTerminal.exe PID 23820 :: ALIVE cmd.exe //c launcher.cmd PID 31436 :: STUCK (interactive) bash.exe -l launcher.sh NEVER RAN claude.exe (TUI) NEVER RAN cmd was alive but did NOTHING why did /c not fire?
The terminal had a parent and a child cmd. But cmd never invoked bash. Why?

The process tree showed cmd alive. Stuck. Not running anything. We ran the launcher .cmd file by hand to see what cmd was actually doing — and watched cmd open and drop straight into interactive mode. As if no command had been passed.

Which is exactly what was happening.

The real bug: MSYS ate the slashes

The helper invoked the tab with cmd //c <launcher.cmd>. The double-slash is supposed to be a Git Bash idiom: pass //c through, and MSYS converts it to /c when handing off to the native Windows exe. That way cmd sees its /c switch ("run this and exit") and MSYS doesn't path-mangle the leading slash into C:/.

That defang stopped firing in the current Git Bash binary. //c now passes through literally. cmd received //c as its first argument, didn't recognise it as a switch, and fell through to interactive mode — cmd's default when given no command.

The MSYS layer used to chew the extra slash. It doesn't anymore. There's a way to tell it to step aside.

bash passes
/c
MSYS converts to
C:/
cmd receives
C:/
[ FAIL ] · cmd doesn't see a /c switch · drops to interactive

Once the diagnosis was named, the same flavour of bug showed up elsewhere — taskkill //F //T //PID in the auto-close watcher, schtasks //run //tn in the layout helper, the same pattern in handover-go.sh. None of those switches were firing either.

The fix: two characters and an env var

The patch is small. The reasoning behind the patch is the part you have to write down so future you understands why.

# invoke a fresh wt tab running cmd /c <launcher.cmd> - WT_ARGS+=(-- cmd //c "$LAUNCHER_CMD_WIN") - wt.exe "${WT_ARGS[@]}" & + WT_ARGS+=(-- cmd /c "$LAUNCHER_CMD_WIN") + MSYS2_ARG_CONV_EXCL='/c' wt.exe "${WT_ARGS[@]}" & disown

Same pattern applied to the watcher's taskkill /F /T /PID, the layout helper's schtasks /run /tn, and the matching code in handover-go.sh (the auto-handover spawn path — same MSYS layer, same defang failure).

[ BEFORE ] wt.exe ... -- cmd //c "$LAUNCHER"     ↓ bash hands "//c" untouched wt → cmd: argv[1] = "//c"     ↓ cmd: "//c"? no switch. cmd: drop to interactive prompt [ DEAD TERMINAL ] [ AFTER ] MSYS2_ARG_CONV_EXCL='/c' wt.exe   ... -- cmd /c "$LAUNCHER"     ↓ MSYS leaves "/c" alone wt → cmd: argv[1] = "/c"     ↓ cmd: run launcher, exit [ CLAUDE TUI RENDERS ]
Same script. Two characters changed. The whole chain wakes up.

How Godmode+ caught it

This bug had survived multiple sit-down debugging sessions. The first rewrite (removing claude -p) wasn't wrong — print mode was a real footgun — but it wasn't the active cause of the dead-terminal symptom. The active cause was the MSYS defang. We just couldn't see it without spawning an actual tab and inspecting what cmd received.

Godmode+'s protocol forces that inspection. The phases are non-negotiable:

[1] Recon — map every spawn path

[2] Build — rewrite the helper, drop the print branch

[3] Check — static review, type-check

[4] Test — unit-level, no actual spawn yet

[5] Smokespawn it for real, screenshot it, verify the TUI loads

[6] Harden — patch the actual root cause

[7] Verify — re-run the smoke test, confirm the tab boots and auto-closes
The protocol that won. The build phase wasn't enough — phase 5 is what surfaced the real bug.

Build stats

Receipt, not a brag. Here's what Godmode+ actually spent finding and shipping the fix.

MetricValue
Toolgodmode-plus (continuation)
Time taken41m 36s (initial run) + ~25m verification
Assistant turns170
Total tokens21.5M (20.9M cache read, 414K cache create)
Output tokens167,656
Estimated cost$51.85 USD (Opus rates)
Files changedclaude-tab.sh, handover-go.sh, spawn-agent SKILL.md, two memory entries
Bugs found by smoke test1 (the one that mattered)
VerdictShipped

The honest trade-off: a previous (non-Godmode+) attempt had spent significant time on the wrong root cause. The "first try" in this post's headline refers to Godmode+'s first try — phase 5 caught the bug on the first smoke test it ran.

Why this bug was so sneaky

>>

Silent failure

cmd didn't error on unknown //c. It just opened an interactive prompt — cmd's default with no command. No exit code, no log line, no red flag.

[*]

Windows-only

The MSYS layer only exists on Windows. Code reviewed on Mac/Linux looks perfect. The bug only fires in the exact env where it bites.

+--

Version drift

The //c defang DID work in older Git Bash. A binary upgrade changed the conversion rules silently. No release note flagged it.

o-o

Stale folklore

Every Windows-bash tutorial online still recommends //c. The advice was right in 2015 and quietly stopped being right.

What changed in our scripts

Do

Use MSYS2_ARG_CONV_EXCL='/c' cmd /c <file> when invoking cmd from Git Bash. Same idea for taskkill, schtasks, and any native exe that takes /flag switches. Exclude only what you need.

Don't

Don't trust the //flag double-slash defang. It's brittle. It depends on which MSYS build you have. It can break on a Git Bash update with no warning and no log.

The lesson is not "MSYS is bad." The lesson is that a build can pass review, compile, and look correct, and still be broken in the one environment that matters. A smoke test is the difference between catching that yourself and finding out from a user.

Run your own max-effort protocol

Godmode+ runs the seven-phase protocol on any task you point it at — recon, build, check, test, smoke, harden, verify. The phase that catches "looks fine, isn't fine" is built in.

Get Godmode+ More post-mortems