Doing Claude Code Right on a Remote Server — Ditching the Local Clone, plus tmux and Automatic Screenshot Hand-off
The conclusions I reached while refining a workflow around a remote Ubuntu server and an AI coding agent. Why I dropped the local clone, how I run multiple tmux sessions, and how the ss sync + cc function fills the image-input gap.
I run a Dockerized Magento instance on an Ubuntu server. When I work on it, I jump into the server with VS Code Remote-SSH and run Claude Code from inside the module folder. This is a writeup of the questions I wrestled with and the conclusions I landed on while sharpening that workflow. If you work the same way — "remote server + AI coding agent" — this should be useful.
Why not just clone it locally and work there?
That was the first thing that came to mind. Why not keep a local clone, work comfortably there, and ship the changes up to the server? The answer is don't, and the reasons are what this whole post is built on.
First, commits turn into a precondition for testing. If you keep the local copy as the source of truth and sync over git, every one-line change you want to check forces a commit → push → pull-on-the-server cycle. The moment a commit becomes the mechanism for "let's see if this works," the loop slows to a crawl and your git history rots into wip, fix, fix again. A commit should mean "verified, saved."
Second — and this is the decisive one — there's no Magento locally, so Claude Code can't run bin/magento. The real power of Claude Code isn't just editing code; it's running commands right there and checking the results. Run compile, read the logs, catch the error, fix it, repeat. Locally, the agent can't verify its own work. That's a flat-out downgrade.
So I split the mental model in two. The inner loop (development) lives on the server where Magento actually runs: edit directly, test immediately, no commits. The outer loop (deployment) is push-after-verification → pull-in-production. Here git push is a "staging→prod gate," not a "local→staging sync." When you edit the server directly, staging is always current, so the whole "auto-sync local→staging" problem simply evaporates. That problem only exists if you chose to edit locally in the first place — it was self-inflicted.
"Do I have to run compile after every change?" — Mostly, no
This was something I'd assumed made server work tedious. Turns out it was a misunderstanding. In Magento, only a subset of changes actually need a command.
.phtml templates, the PHP logic inside blocks and models, JS, and Tailwind sources show up the instant you save and refresh (with developer mode + a Docker bind-mount, the container sees the host files directly). .xml layouts and translations just need a cache:flush. The only time you genuinely need di:compile is when you add a new dependency, plugin, or preference to di.xml, or when you setup:upgrade a new module.
In other words, the everyday work of writing logic and touching templates needs zero commands. Running compile after every edit was an unnecessary habit. For theme work, leaving npm run watch (Tailwind watch) running rebuilds the CSS the moment you save. A full static deploy is only for production releases.
And for the moments when compile/flush really are needed, you can just tell Claude Code, "fix this, run whatever Magento commands are required, and check the result," and it'll decide for itself, run them, and verify the errors too. No need to type any of it by hand. This is the very reason to run the agent on the server.
The real reason the VS Code extension felt clunky
To open a new conversation I had to bounce between windows and panels — it was more awkward than using a tool like Warp or Conductor. After flailing for a while, I figured out the cause. The friction wasn't "working on a server"; it was "going through the VS Code extension."
Claude Code is a terminal-native tool at heart. The VS Code extension is an add-on; the CLI is the real thing. The reason Warp feels nice is that you launch it straight from the terminal. So the fix is obvious — skip the extension and just launch several Claude Code instances directly in the server terminal.
tmux: multiple sessions + survives a dropped SSH
The answer was tmux. SSH into the server once, fire up tmux, and inside it you can split panes and run a Claude Code in each. No need to open a fresh SSH connection for every new session.
ssh server (once)
└─ tmux
├─ pane 1: claude in ModuleA
├─ pane 2: claude in ModuleB
└─ pane 3: tail -f var/log/ (logs)
The real strength is something else. A tmux session is attached to the server itself, not to your SSH connection, so it doesn't die when your internet drops or you close your laptop. Work at a café, shut the lid, get home, reconnect, run tmux attach, and your in-progress Claude Code conversation picks up exactly where it left off. That's a server-based advantage GUI tools just don't have.
Now the isolation (git worktree) angle. The reason a tool like Conductor creates branches and worktrees is to prevent conflicts when multiple agents step on the same files at once. But independent work, split across separate module folders, doesn't conflict even without worktrees. On top of that, even if you separate the code into worktrees, Magento runs on a single instance (one DB, one cache, one set of compiled artifacts), so that becomes the bottleneck anyway. For work that doesn't need isolation, bare-hands tmux is plenty.
The image-paste problem, and ss + cc
One of the reasons I couldn't quit VS Code was clipboard image pasting. Capture a broken Magento screen, paste it straight in, and Claude Code sees it. In a plain terminal that doesn't work out of the box.
There's the option of pasting a public CleanShot URL, but I wasn't comfortable putting Magento admin, order, and API-key screens out on the public internet. So I went with a local-sync approach: mirror my screenshot (ss) folder to the server in real time, and put a wrapper function on the server that "automatically grabs the latest screenshot." The point is I never need to know the filename.
# server ~/.bashrc
SHOT_DIR="$HOME/ss"
cc() {
local latest
latest=$(ls -t "$SHOT_DIR"/*.png 2>/dev/null | head -1)
if [ -n "$latest" ]; then
echo "🖼 attaching: $(basename "$latest")"
claude "$@" "$latest"
else
claude "$@"
fi
}Point CleanShot's save location on the Mac at the sync folder (one-way mirror to the server's ~/ss via Mutagen), then in tmux run cc "why is this layout broken?" and the screenshot you just took is pulled in automatically. The whole flow is two steps: capture → cc. Token cost is independent of the delivery method (URL vs. file) and is driven by image resolution, so making a habit of cropping your captures is itself a way to save tokens.
tmux-based session managers already exist
"Forget the isolation-based tools (the Conductor crowd) — is there no tmux multi-session manager that does what I want?" I looked, and there is. Plain tmux can't show you "which session finished," and these tools fill exactly that gap.
craftzdog/tmux-claude-session-manager spins up per-project sessions and surfaces their done/working state in a popup (it uses Claude Code hooks to stamp the status into tmux). NTM (Named Tmux Manager) adds named sessions, broadcast, and conflict detection, and on top of that is designed so sessions survive a dropped SSH when run on a remote server — a particularly good fit for remote setups. nielsgroen/claude-tmux offers a tmux-popup TUI for switching between and monitoring sessions.
Here's the order I settled on. Start with bare-hands tmux to get a feel for it, and once the sessions pile up and "what's running, what's done?" gets frustrating, layer a manager on top.
Wrapping up
Using Claude Code on a remote server isn't inherently clunky — it gets clunky when you pick the wrong conduit. Keep working directly on the server (the big wins — DB and Magento access, the agent verifying its own work — stay intact), but swap the conduit from the VS Code extension to terminal + tmux, and you gain multiple sessions and session persistence. Add the ss sync + cc function to cover image input, and you won't envy the GUI tools at all. If I had to leave just one core lesson: don't reach for an isolation tool on work that doesn't need isolation. In that case, tmux is the right answer.