De helft van mijn tijd programmeer ik op mijn telefoon, met Termius en tmux
TLDR
Sinds kort programmeer ik de helft van mijn tijd op mijn telefoon, in exact dezelfde tmux-sessie die op mijn Mac draait. Je leest hoe je die opzet, en waarom je de tmux-server bij je GUI-login moet laten starten en niet vanuit je SSH-login.
Sinds kort programmeer ik (als ik thuis werk) 50% van mijn tijd op mijn mobiel met Termius. Vanaf de bank, mijn tuin, mijn bed, you name it open ik de SSH-client op mijn telefoon en kijk naar exact hetzelfde scherm dat ik op mijn Mac achterliet. Claude Code draait door, en ik tik een vervolgprompt alsof ik nooit ben opgestaan.
Ik gebruik hiervoor één gedeelde tmux-sessie, die werkt doordat ik een paar instellingen op de juiste plek heb gezet.
Eén sessie verdeeld over meerdere schermen
tmux houdt je shell in leven los van wie er kijkt. Sluit je het venster, dan blijft de sessie lopen; open je ‘m ergens anders, dan zie je dezelfde panes weer terug. De sessie draait op mijn laptop, die is de host. Ik noem ‘m termius.
Lokaal stap ik erin met een alias die ik heb gedefinieerd in mijn .zshrc. De -A attacht aan een bestaande sessie, of maakt ‘m aan:
alias termius='tmux new -A -s termius'
Vanaf mijn telefoon wil ik niet in een verse shell landen maar meteen in die sessie. Dat regelt dit blok in mijn .zshrc:
# Auto-attach aan de tmux-sessie "termius", alleen bij een login vanaf mijn telefoon,
# niet als we al in tmux zitten, en alleen interactief.
if [[ -n $TERMIUS && -z $TMUX && $- == *i* ]]; then
tmux has-session -t termius 2>/dev/null || {
launchctl kickstart "gui/$(id -u)/tmux-termius"
sleep 0.5
}
exec tmux attach -t termius
fi
De exec vervangt de login-shell door tmux, zodat een detach me uitlogt in plaats van me in een kale shell achter te laten. De $TERMIUS-check en de launchctl kickstart leg ik hieronder uit, daar zit het echte werk.
De Mac setup
Je hebt vier dingen nodig: tmux, een SSH-ingang, de sessie die op het juiste moment start, en een manier om te weten dát een login van je telefoon komt.
brew install tmux
sudo systemsetup -setremotelogin on # of: Systeeminstellingen -> Delen -> Externe login
De sessie laat ik bij mijn GUI-login starten met een LaunchAgent in ~/Library/LaunchAgents/tmux-termius.plist, zodat er altijd een termius-sessie is:
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/tmux</string>
<string>new-session</string>
<string>-d</string>
<string>-s</string>
<string>termius</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>SHELL</key>
<string>/bin/zsh</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/tmux-termius.plist
KeepAlive herstart ‘m als de server sterft doordat ik mijn laatste venster sluit. De SHELL-key zorgt ervoor dat zsh wordt gebruikt in plaats van de standaard sh shell.
Die $TERMIUS-var zet de app zelf niet; ik heb ‘m gekoppeld aan de SSH-key van mijn telefoon in ~/.ssh/authorized_keys:
environment="TERMIUS=1" ssh-ed25519 AAAA...jouwkey... telefoon
En sshd moet die var doorlaten, scherp afgebakend in een drop-in /etc/ssh/sshd_config.d/100-termius.conf:
PermitUserEnvironment TERMIUS
Alleen een login met die key krijgt TERMIUS=1, dus de auto-attach opent de tmux-sessie alleen bij een login vanaf mijn telefoon, en nooit per ongeluk lokaal.
Op de telefoon voeg je in Termius een host toe met het lokale IP van je Mac, genereer je een SSH-key en zet je de publieke helft in die authorized_keys. Ik verbind bewust alleen binnen mijn eigen netwerk, om te voorkomen dat ik altijd en overal aan het prompten ben.
Zorgen dat je de juiste rechten hebt
Het grootste gedoe zat in waar de tmux-server leeft. Eerst liet ik de sessie aanmaken vanuit de SSH-login. Werkte prima, tot Claude Code me steeds om /login vroeg en mijn git-push faalde met een permission denied.
Start je de server vanuit een SSH-login, dan zit die in een security-sessie met een gelockte login-keychain, en alles wat je daarin start erft dat. Claude Code komt niet bij zijn credentials, en er is geen GUI-ssh-agent, dus git-over-SSH heeft geen sleutel.
Vandaar dat LaunchAgent opzet, en vandaar de launchctl kickstart in het zshrc-blok. Die zorgt ervoor dat de server altijd draait als ik via de app binnen kom.
Twee dingen die je daarna nog wilt fixen
Mijn Mac-scherm kromp zodra mijn telefoon meekeek, want tmux schaalt naar de kleinste client. Eén regel in ~/.tmux.conf:
set -g window-size latest
En als laatste: een SSH-verbinding op een telefoon valt zomaar weg (scherm op slot, van wifi naar 4G). tmux vangt dat op, je detacht en de sessie draait door. Om de drops te beperken laat ik sshd de verbinding actief houden:
ClientAliveInterval 60
Na een wijziging in de sshd-config moet je ‘m herladen, anders draai je nog op de oude:
sudo launchctl kickstart -k system/com.openssh.sshd
Een productiviteitsboost
Ik zat de laatste tijd te vaak onnodig naar mijn scherm te staren terwijl agents aan het werk waren. Nu kan ik ondertussen andere dingen doen. En een klein scherm beperkt je minder dan je denkt, dat merkte ik toen ik ziek was. Ik heb vanuit mijn bed een volledige Mac-app voor mijn PR’s ontwikkeld, van eerste idee tot iets dat ik nu echt gebruik, met alleen mijn telefoon in mijn handen.
Hands-off werkt het pas echt in combinatie met claude-auto-mode; op een telefoon wil je niet om de tien seconden een permissie-prompt wegtikken. Voor een bedrijf dat op agents leunt is dat het punt: de bottleneck is niet meer waar de developer zit, maar hoeveel taken je tegelijk kunt laten lopen en losjes kunt bewaken.
Ik pak nog steeds het liefst mijn laptop voor het echte werk. Maar dat een taak doorloopt terwijl ik andere dingen aan het doen ben en ik ‘m vanaf mijn telefoon bijstuur, scheelt me elke dag een paar context-switches.