Hello! This is my favorite Claude Code experience to work locally and have maximum flexibility to remote Claude Code. It uses cmux + tmux + Tailscale + Echo app.
I run Claude Code in cmux on my Mac Studio and control sessions from my iPad or iPhone while on the road over Tailscale using Echo. tmux keeps everything alive between connections.
- A Mac running cmux - www.cmux.com
- Tailscale on both your Mac and iPhone - www.tailscale.com
- Echo on your iPhone - www.replay.software/echo ($2.99)
- tmux - (
brew install tmux)
All items are free for personal use except Echo app.
Download and install on both devices, sign in with the same Tailscale account. Note your Mac's Tailscale hostname from the menu bar app. No port forwarding, no firewall rules, no dynamic DNS. Both devices land on the same encrypted private network.
On your Mac, enable this: System Settings > General > Sharing > Remote Login.
Three files need changes.
Add the following to the bottom of ~/.zshrc.
(Open with open ~/.zshrc, edit, save, then run source ~/.zshrc)
# alias to quickly start claude code in cmux with correct workspace naming
ccode() {
local name="${1:-$(basename $PWD)}"
local cmd="claude"
local wants_continue=false
for arg in "${@:2}"; do
case "$arg" in
-c) cmd="claude --continue"; wants_continue=true ;;
-d) cmd="claude --dangerously-skip-permissions" ;;
-cd|-dc) cmd="claude --continue --dangerously-skip-permissions"; wants_continue=true ;;
esac
done
if $wants_continue; then
local project_dir="$HOME/.claude/projects/$(pwd | tr '/' '-')"
local newest=$(find "$project_dir" -maxdepth 1 -name '*.jsonl' -print 2>/dev/null | head -1)
if [ -z "$newest" ]; then
echo "ccode: no sessions to continue in $(pwd)" >&2
return 1
fi
fi
cmux rename-workspace "$name"
if tmux has-session -t "$name" 2>/dev/null; then
tmux attach -t "$name"
else
tmux new -s "$name" -c "$PWD" "$cmd"
fi
}
# Shift+Enter inserts newline instead of executing command
insert-newline() { LBUFFER+=$'\n' }
zle -N insert-newline
bindkey '\e\r' insert-newlinecmux rename-workspace syncs the sidebar name to the tmux session name so everything matches across local and remote. The tmux session wraps Claude Code so it persists between connections - disconnect from Echo and reattach later without losing your place.
The -c and -cd flags include a pre-flight check that verifies a prior session exists before trying to continue. Without this, you get a blank tmux window if there's nothing to continue. The check uses find instead of glob expansion because zsh's NOMATCH behavior breaks ls *.jsonl when no files match.
set -g status off
set -g allow-passthrough on
set -g mouse on
# Selection highlight - matrix green on black
set -g mode-style "fg=black,bg=#00ff00"
# Mouse release copies to system clipboard and exits copy mode
bind -T copy-mode MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"
bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"allow-passthrough on lets escape sequences pass through tmux to the terminal. This is required for cmux sidebar notifications and other terminal integrations. mouse on gives you scroll-wheel scrollback. The pbcopy bindings send selected text to the macOS clipboard on mouse release so Cmd+V works everywhere.
~/.config/ghostty/config (cmux reads keybindings from Ghostty's config):
keybind = shift+enter=text:\x1b\x0d
The Ghostty keybind sends an escape sequence for Shift+Enter, and the zsh binding catches it to insert a newline instead of submitting the command.
On your Mac in a cmux pane:
ccode # session named after the folder
ccode projectName -c # continue last conversation
ccode projectName -d # skip permissions
ccode projectName -cd # continue + skip permissionsOpen Echo on your iPhone, SSH to your Mac's Tailscale hostname, then:
tmux ls # list active sessions
tmux a -t projectName # attach to an active sessionYou're now in Claude Code from your phone - same session, same state, same conversation.
SSH connections can drop when you switch networks or your phone locks. Mosh handles this - it reconnects automatically without losing your session.
Install Mosh on your Mac:
brew install moshNo local install needed. In the Echo app, enable Mosh in your connection settings and it handles the rest.