When dispatching commands between tmux sessions, tmux send-keys -t <target> '<command>' Enter exits 0 and the command text appears in the target's input buffer — but the Enter never commits. The agent sits idle. The dispatcher sees success. Nothing happened.
This hits hardest with long commands that trigger tmux's bracketed paste mode: the trailing Enter gets absorbed into the paste block instead of executing it. Two other failure modes: the target app is in a modal state (dialog, secondary prompt) that swallows Enter, or the input handler is loaded and drops the keystroke.
The fix is a verify-and-retry loop after every dispatch:
dispatch() {
local target="$1" cmd="$2"
# 1. Send
tmux send-keys -t "$target" "$cmd" Enter
# 2. Wait for the target to start processing
sleep 3
# 3. Verify it's actually working, not just staged
if tmux capture-pane -t "$target" -p -S -10 | tail -10 \
| grep -qE "Working|Exploring|Reading|Analyzing"; then
return 0
fi
# 4. Retry — empty Enter kicks the paste buffer
tmux send-keys -t "$target" "" Enter
sleep 2
# One more check, then give up
if tmux capture-pane -t "$target" -p -S -10 | tail -10 \
| grep -qE "Working|Exploring|Reading|Analyzing"; then
return 0
fi
# 5. Fallback: write to file, let target poll for it
echo "$cmd" > "/tmp/dispatch-${target##*.}.cmd"
return 1
}
Cap retries at 2. If both fail, fall back to writing the command to a file the target reads on its own polling cycle — this sidesteps the pty entirely.
The broader lesson: any async channel where the sender gets a local exit code instead of a structured delivery ACK has this failure class. Pty pipes, shell sessions, anything interactive. If you're building multi-agent coordination over interactive channels, bake verification into the dispatch protocol and don't trust exit code 0.
Apply the same pattern in reverse for callbacks: workers should verify their "done" message was received by the dispatcher, not just fire-and-forget.
When you need a clean slate — testing, debugging, or isolating a project — each major AI coding CLI lets you override its config directory via an environment variable:
# Claude Code
CLAUDE_CONFIG_DIR=/tmp/claude-clean claude
# GitHub Copilot CLI
COPILOT_HOME=/tmp/copilot-clean copilot
# OpenAI Codex CLI
CODEX_HOME=/tmp/codex-clean codex
These replace the entire config directory (~/.claude/, ~/.copilot/, ~/.codex/), so existing sessions, permissions, and plugins won't carry over. Copy the default directory contents if you need to preserve anything.
Copilot also has a separate COPILOT_CACHE_HOME for marketplace cache and update packages — setting COPILOT_HOME alone won't relocate those.
In the HTTP era, virtual hosting was trivial: one IP serves many domains, the Host header tells them apart. HTTPS breaks this because TLS handshake happens before any HTTP header — the server must pick a certificate before knowing which domain the client wants.
SNI — the standard fix
Server Name Indication is a TLS extension where the client sends the target hostname during handshake. All modern clients support it. Nginx uses it automatically — just define separate server blocks:
server {
listen 443 ssl;
server_name a.com;
ssl_certificate /etc/ssl/a.com.crt;
ssl_certificate_key /etc/ssl/a.com.key;
}
server {
listen 443 ssl;
server_name b.com;
ssl_certificate /etc/ssl/b.com.crt;
ssl_certificate_key /etc/ssl/b.com.key;
}
Each domain gets its own certificate. Nginx routes based on SNI. Zero extra config needed.
When you'd rather use one certificate
For a handful of related domains, a SAN certificate (Subject Alternative Name) covers multiple names in one cert:
server {
listen 443 ssl;
server_name a.com b.com c.com;
ssl_certificate /etc/ssl/multi.crt;
ssl_certificate_key /etc/ssl/multi.key;
}
Let's Encrypt makes this painless:
certbot --nginx -d a.com -d b.com -d c.com
For lots of subdomains (*.example.com), a wildcard certificate is the way to go.
SNI + Let's Encrypt covers 99% of real-world setups — free and automatic.
Use CLAUDE_CONFIG_DIR to point Claude Code at a different config directory — credentials, settings, sessions all go there instead of ~/.claude.
mkdir -p ~/.claude-work
CLAUDE_CONFIG_DIR=$HOME/.claude-work claude
Set up aliases in your shell config for quick switching:
alias claude-work='CLAUDE_CONFIG_DIR=$HOME/.claude-work claude'
First launch in the new directory triggers the login flow — that's how you get account isolation. Both instances can run simultaneously without interference.
Share session history between instances
CLAUDE_CONFIG_DIR is all-or-nothing — no built-in way to share just sessions. Symlink the projects/ directory back to the original to get shared session history with separate settings:
mkdir -p ~/.claude-work
cp ~/.claude/settings.json ~/.claude-work/settings.json
ln -s ~/.claude/projects ~/.claude-work/projects
This gives you independent config/credentials but a unified session list. New sessions written by either instance appear in both (bidirectional). No read-only option exists — if you need isolation, don't symlink.
If curl throws SSL certificate problem: unable to get local issuer certificate every time in WSL, it's usually a stale CA bundle — especially common on corporate networks running SSL inspection (Zscaler, etc.).
First, refresh the bundle:
sudo apt-get update && sudo apt-get install -y ca-certificates
sudo update-ca-certificates
That fixes most cases. If not, try a full reinstall:
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates --fresh
On corporate networks, you likely need your company's root CA certs. You probably already have them somewhere in your Windows filesystem (.crt or .cer files). Copy them all into the trusted store:
sudo cp /c/Certificates/*.crt /usr/local/share/ca-certificates/
sudo cp /c/Certificates/*.cer /usr/local/share/ca-certificates/
sudo update-ca-certificates
Skip .pfx files — those contain private keys and are a different format.
If you don't have the certs handy, export them from Windows:
# PowerShell — list all root certs, look for your company name
Get-ChildItem Cert:\LocalMachine\Root | Select-Object Subject, Issuer | Sort-Object Subject
Or use certmgr.msc (Win+R → certmgr.msc) → Trusted Root Certification Authorities → find your company's cert → right-click → Export → Base-64 encoded X.509.
Test with curl https://google.com after each step.