Posts tagged with “tools”

Garbled text before PS1 over SSH? Your OSC sequences are leaking

You SSH into a machine and see garbage like ile://host/home/userurrentDir=/home/user before your prompt. Locally everything is fine. What happened?

Your PROMPT_COMMAND includes an OSC 7 / OSC 1337 sequence that reports the current directory to the terminal emulator. Locally, WezTerm (or iTerm2, etc.) intercepts these invisible escape sequences. Over SSH with TERM=linux, no terminal emulator is listening — the raw bytes print as text.

The fix is a guard condition before wiring __report_cwd into PROMPT_COMMAND:

if [[ -n "${TERM_PROGRAM:-}" || "${TERM:-}" =~ xterm|screen|tmux|wezterm|alacritty ]]; then
  [[ ":$PROMPT_COMMAND:" != *__report_cwd* ]] && \
    PROMPT_COMMAND="__report_cwd${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
fi

When TERM=linux (plain SSH) and TERM_PROGRAM is empty, the function is skipped entirely. No escape sequences, no garbage.

After deploying the fix, start a fresh shell — PROMPT_COMMAND is already set in the running session and won't be cleared by re-sourcing.

Run Multiple Claude Code Instances with Separate Configs

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.

whoseport: Find What's Listening on a Port (With Working Directory)

ss -tlnp and lsof -i :PORT tell you the PID and command name, but for Node.js or Python processes, "node" or "python" alone doesn't tell you which project is running. The working directory is what you actually need — and it's sitting right there in /proc/$pid/cwd.

Put this in ~/.bashrc:

whoseport() {
  if [ -z "$1" ]; then
    sudo ss -tlnp | tail -n +2 | while read -r line; do
      port=$(echo "$line" | grep -oP ':\K[0-9]+(?=\s)')
      pid=$(echo "$line" | grep -oP 'pid=\K[0-9]+' | head -1 | tr -dc '0-9')
      [ -n "$pid" ] && echo "PORT: $port | PID: $pid | CMD: $(ps -p $pid -o comm=) | CWD: $(readlink /proc/$pid/cwd)"
    done
  else
    whoseport | grep 'PORT: '$1
  fi
}

Usage:

$ whoseport 6173
PORT: 6173 | PID: 1326886 | CMD: node | CWD: /home/davidw/Projects/ccode_viewer/server

$ whoseport          # list all listening ports
PORT: 61217 | PID: 1356 | CMD: tailscaled | CWD: /
PORT: 22     | PID: 1385  | CMD: sshd      | CWD: /

A few things that went wrong before arriving at this version:

Don't use an alias for this — $1 in a single-quoted alias gets swallowed by inner sh -c calls, and local variables don't survive xargs boundaries. A function avoids both problems. The tr -dc '0-9' on the PID is not cosmetic — ss output can carry trailing whitespace or newlines that break ps -p with a "process ID list syntax error".

Git Worktree: Checkout an Existing Branch Into a Separate Directory

Need to work on two branches simultaneously without stashing or cloning? git worktree creates a separate working directory that shares the same .git — no duplicate objects, no wasted space.

git worktree add <path> <branch>

For example, to checkout feature/login into a sibling directory:

git worktree add ../my-feature feature/login

This creates ../my-feature with the branch checked out and ready to work. Commits, branches, and remotes are shared — it's one repository, multiple workspaces.

Day-to-day operations:

  • git worktree list — see all linked worktrees
  • git worktree remove <path> — clean up when done

One restriction: the same branch cannot be checked out in two worktrees at once. Git enforces this to prevent conflicting writes to the ref.

WezTerm stealing Alt+Enter? Here's the fix

WezTerm binds Alt+Enter to toggle fullscreen by default. That hijacks Alt+Enter newline in Claude Code, GitHub Copilot, and other terminal-based tools.

Drop this in ~/.wezterm.lua to disable the default and remap fullscreen to Ctrl+Shift+F11:

local wezterm = require 'wezterm'
local config = wezterm.config_builder()

config.keys = {
  {
    key = 'Enter',
    mods = 'ALT',
    action = wezterm.action.DisableDefaultAssignment,
  },
  {
    key = 'F11',
    mods = 'CTRL|SHIFT',
    action = wezterm.action.ToggleFullScreen,
  },
}

return config

Config takes effect immediately on save — no restart needed.