When posting multipart form data via curl in a bash script, it's tempting to build the body in a variable and pass it with --data-raw "$DATA". On Linux this often works fine. On Windows Git Bash, it silently breaks — the server receives the request but fields like body come through empty.
Two things go wrong at once. First, Windows-style paths (C:\Users\...) passed to bash utilities like tail and file are misread — the backslashes get misinterpreted and the file read returns nothing. Fix that with cygpath:
filename=$(cygpath -u "$1" 2>/dev/null || echo "$1")
Second, even with the right path, storing the body in a shell variable and passing it via --data-raw is unreliable. Shell variable expansion, CRLF handling, and platform-specific curl behavior all interact badly. The body gets mangled before it reaches the wire.
The fix is to bypass variables entirely: write the multipart payload to a temp file and send it with --data-binary @file. Since the post body is already in a file, tail it directly into the temp file instead of slurping it into a variable:
TMPBODY=$(mktemp)
TMPDATA=$(mktemp)
tail -n +2 "$filename" > "$TMPBODY"
{
printf "%s\r\n" "--${BOUNDARY}"
printf "Content-Disposition: form-data; name=\"body\"\r\n\r\n"
cat "$TMPBODY"
printf "\r\n%s\r\n" "--${BOUNDARY}--"
} > "$TMPDATA"
curl ... --data-binary "@$TMPDATA"
rm -f "$TMPBODY" "$TMPDATA"
--data-binary @file sends the exact bytes on disk — no shell expansion, no line ending conversion. Works the same on Linux, macOS, and Windows Git Bash.
If you're using Codex CLI and want to insert a newline in the prompt box without submitting, Shift+Enter won't work. Use Ctrl+J instead.
Ctrl+J is the ASCII control character for line feed (\n). Many terminal TUI libraries interpret it as "insert newline" rather than "submit," which is exactly what Codex CLI's input component does.
Shift+Enter looks like the right key (it works in browser-based chat UIs), but whether it inserts a newline or submits depends entirely on how the TUI library handles raw key events — and Codex CLI's library doesn't treat it as a newline.
So: Ctrl+J to insert a newline, Enter to submit.
autossh has its own connection monitoring that opens an extra port for heartbeats. But this is redundant — SSH already has native keepalive via ServerAliveInterval. The extra port can even cause problems if it's not available on the remote side.
The modern approach: disable autossh's built-in monitoring with -M 0 and let SSH's native heartbeats handle it. When SSH detects a dead connection (after ServerAliveInterval * ServerAliveCountMax seconds of no response), autossh automatically reconnects.
Put everything in ~/.ssh/config:
Host gateway
HostName your-gateway-ip
User ec2-user
ServerAliveInterval 30
ServerAliveCountMax 3
LocalForward 8080 internal-soap-ec2:8080
Then the command reduces to:
autossh -M 0 -Nf gateway
-M 0 is the only autossh-specific flag you need. Everything else — host, user, keepalive, even the tunnel — lives in SSH config where it belongs. ServerAliveInterval 30 sends a heartbeat every 30 seconds through the SSH port itself (no extra ports needed), and ServerAliveCountMax 3 means 90 seconds of silence triggers a disconnect detection.
Shift+Enter doesn't insert a newline in the OpenAI Codex CLI. This isn't a terminal or environment issue — you'll see the same behavior whether you're using iTerm2, the macOS Terminal app, or anything else. It's built into Codex itself.
The shortcut for a new line is Ctrl-J.
This catches people off guard because Shift+Enter is the standard multiline shortcut in virtually every chat and code editor (Claude Code, ChatGPT web, VS Code, etc.). The muscle memory is strong and there's currently no way to remap it — Codex doesn't expose a keybinding config.
AWS CLI v2.22.0+ switched the default SSO login flow to PKCE, which requires a browser on the same machine. If you're SSH'd into a server with no GUI, aws sso login just hangs waiting for a browser that doesn't exist.
The fix is two flags:
aws sso login --profile prod --no-browser --use-device-code
It prints a URL and a one-time code. Open the URL on any other device (phone, laptop, tablet), enter the code, authenticate, and you're done. The CLI polls in the background and picks up the token automatically.