<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tmux on Matt Goodrich</title><link>https://mattgoodrich.com/tags/tmux/</link><description>Recent content in Tmux on Matt Goodrich</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 12 May 2026 12:00:00 -0700</lastBuildDate><atom:link href="https://mattgoodrich.com/tags/tmux/index.xml" rel="self" type="application/rss+xml"/><item><title>Agents Don't Travel Well</title><link>https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/</link><pubDate>Tue, 12 May 2026 12:00:00 -0700</pubDate><guid>https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/</guid><description>&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/header.png" alt="Featured image of post Agents Don't Travel Well" />&lt;p>&lt;strong>AI just hits different.&lt;/strong>&lt;/p>
&lt;p>A lot of us in security have drifted further and further from our deep technical roots. For many of my peers, and for me, that meant writing real code early in our careers, then watching it become something other people did while we became &amp;ldquo;the security person who used to write code.&amp;rdquo; I&amp;rsquo;ve lost count of practitioners who have told me some version of &lt;em>&amp;ldquo;I&amp;rsquo;m writing more code right now than I have in the past several years combined.&amp;rdquo;&lt;/em> I am one of them.&lt;/p>
&lt;p>Here&amp;rsquo;s mine, year by year:&lt;/p>
&lt;p>&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2022.png"
width="1860"
height="432"
srcset="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2022_hu6019992355517135839.png 480w, https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2022_hu17989680996902469561.png 1024w"
loading="lazy"
alt="GitHub Contributions — 2022"
class="gallery-image"
data-flex-grow="430"
data-flex-basis="1033px"
>
&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2023.png"
width="1858"
height="436"
srcset="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2023_hu11505461284717528601.png 480w, https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2023_hu8638931826610771490.png 1024w"
loading="lazy"
alt="GitHub Contributions — 2023"
class="gallery-image"
data-flex-grow="426"
data-flex-basis="1022px"
>
&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2024.png"
width="1834"
height="430"
srcset="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2024_hu16177627807396584054.png 480w, https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2024_hu626222845036856175.png 1024w"
loading="lazy"
alt="GitHub Contributions — 2024"
class="gallery-image"
data-flex-grow="426"
data-flex-basis="1023px"
>
&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2025.png"
width="1852"
height="428"
srcset="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2025_hu14253384637596303173.png 480w, https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2025_hu12165648935622424477.png 1024w"
loading="lazy"
alt="GitHub Contributions — 2025"
class="gallery-image"
data-flex-grow="432"
data-flex-basis="1038px"
>
&lt;img src="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2026.png"
width="1844"
height="428"
srcset="https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2026_hu14275161153782393295.png 480w, https://mattgoodrich.com/posts/my-ai-workspace-tmux-cloudflared/github-2026_hu2835142205634918627.png 1024w"
loading="lazy"
alt="GitHub Contributions — 2026"
class="gallery-image"
data-flex-grow="430"
data-flex-basis="1034px"
>&lt;/p>
&lt;p>I have no shame in saying AI writes better code than I do. Some people in security aren&amp;rsquo;t ready to say that yet. I am. In the last week I&amp;rsquo;ve shipped more working code on a personal project (one I plan to write about soon) than I could have produced manually in months, maybe years. Lines of code isn&amp;rsquo;t the metric. The metric is that I can stand up a real, good-looking, useful app and start iterating on it the same day the idea hits me. That used to take a quarter. Now it takes a weekend.&lt;/p>
&lt;p>What&amp;rsquo;s actually changed is the &lt;em>excitement&lt;/em>. I&amp;rsquo;m building things I&amp;rsquo;ve thought about for years, and things a conversation sparked three days ago that I just want to see how far I can push. Once you&amp;rsquo;re moving at that pace, every interruption is expensive — and the workspace that worked fine when you were writing a few hundred lines a week is suddenly the thing fighting you. That&amp;rsquo;s what drove me to the setup I&amp;rsquo;m about to describe.&lt;/p>
&lt;p>My personal daily driver is a fully-loaded M3 Max MacBook Pro with 128GB of RAM. It&amp;rsquo;s a beast — there&amp;rsquo;s almost nothing I throw at it that it can&amp;rsquo;t handle. But &amp;ldquo;beast&amp;rdquo; is the wrong bar when the work is &lt;em>running agents&lt;/em>. Working remotely, working from different spots in the house, ducking out for school drop-off or pickup — the laptop comes with me. And if I have agents running, the laptop coming with me is a problem.&lt;/p>
&lt;p>I&amp;rsquo;ve literally caught myself in bed at night thinking &lt;em>&amp;ldquo;I don&amp;rsquo;t have any agents working on anything right now — what should I kick off before I go to sleep?&amp;rdquo;&lt;/em> Which is, let&amp;rsquo;s be honest, a little unhealthy. But it&amp;rsquo;s also the tell. &lt;strong>The work is the running session now.&lt;/strong> The agent has loaded files, made decisions, started down a path. Lose that and you&amp;rsquo;re not picking up where you left off — you&amp;rsquo;re starting over. Closing the lid is a cost. Driving to school is a cost. Getting on a plane is a cost. Anything that interrupts the agent is a tax on the thing I&amp;rsquo;m most excited about doing.&lt;/p>
&lt;p>So I needed two things. Long-running sessions that survive every kind of interruption a normal day produces. And a way to reach them from anywhere with an internet connection without leaning on a VPN. (I learned the VPN half the hard way recently — cruise ships block most of them.)&lt;/p>
&lt;p>The answer wasn&amp;rsquo;t a better laptop. The answer was to stop putting the important work on the laptop at all. What I have now is one workspace, on a Mac Studio at home, that I reach from anywhere. Three pieces make it work: a Cloudflare Tunnel, tmux, and the discipline of treating the laptop as a thin client, not a workstation.&lt;/p>
&lt;h2 id="the-setup">The Setup
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Mac Studio at home as the always-on host.&lt;/strong> M3 Ultra, 96GB unified memory, plugged in, never sleeps. Runs the local models, the agents, and the long-running jobs.&lt;/li>
&lt;li>&lt;strong>Cloudflare Tunnel for secure access.&lt;/strong> No port forwards, no public IP, no NAT punching. The Mac dials out to Cloudflare. My clients dial in.&lt;/li>
&lt;li>&lt;strong>tmux as the workspace.&lt;/strong> One named session, one window per project. SSH in, attach, everything is exactly where I left it.&lt;/li>
&lt;/ol>
&lt;p>Mac Studio is the compute. Cloudflare is the front door. tmux is the workspace. Everything else is a thin client.&lt;/p>
&lt;h2 id="why-a-cloudflare-tunnel">Why a Cloudflare Tunnel
&lt;/h2>&lt;p>I&amp;rsquo;ve used Tailscale. I&amp;rsquo;ve used a plain VPN. I&amp;rsquo;ve port-forwarded with dynamic DNS. They all work until they don&amp;rsquo;t. The reason I landed on a Cloudflare Tunnel is that it removes the parts of the other options that fail.&lt;/p>
&lt;p>Nothing on my home network is exposed. The Mac Studio runs &lt;code>cloudflared&lt;/code> as a service. It dials &lt;em>out&lt;/em> to Cloudflare and holds an open connection. Inbound traffic comes in via Cloudflare&amp;rsquo;s edge and rides that outbound connection back. My router never accepts a single inbound packet from the public internet.&lt;/p>
&lt;p>Setup on the Mac Studio is short:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install cloudflared
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cloudflared tunnel login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cloudflared tunnel create ai-workspace
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Configure ~/.cloudflared/config.yml with an ingress rule&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># mapping ssh.mydomain.com -&amp;gt; ssh://localhost:22&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cloudflared service install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>On the client, just an SSH config entry:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-ssh" data-lang="ssh">Host studio
HostName ssh.mydomain.com
User yourusername
ProxyCommand cloudflared access ssh --hostname %h
&lt;/code>&lt;/pre>&lt;p>After that, &lt;code>ssh studio&lt;/code> works from anywhere. Same on hotel WiFi as it is at home.&lt;/p>
&lt;p>The other thing I like: authentication happens at the Cloudflare edge, before traffic ever reaches the Mac. And the policy matters — &amp;ldquo;Cloudflare Access enabled&amp;rdquo; without specifics can mean anything from a real identity check down to &amp;ldquo;anyone with the right email address gets a one-time code.&amp;rdquo; I gate on a specific identity provider plus an MFA factor stronger than email codes, with the identities explicitly allowlisted rather than wildcarded. That class of policy is what makes the edge-auth claim hold up; defaults alone don&amp;rsquo;t. Defense in depth, without me having to maintain a second layer of auth on the Mac itself.&lt;/p>
&lt;h2 id="tmux-one-pane-per-project">tmux: One Pane Per Project
&lt;/h2>&lt;p>Once I&amp;rsquo;m SSH&amp;rsquo;d in, tmux is the workspace.&lt;/p>
&lt;p>One named session called &lt;code>work&lt;/code>. One window per active project. Two or three panes per window — usually one for Claude Code, one for a shell where I run commands, sometimes a third for tailing logs.&lt;/p>
&lt;p>Roughly:&lt;/p>
&lt;pre tabindex="0">&lt;code>session: work
├── window: mattgoodrich.com
├── window: claude-chats
└── window: zsh
&lt;/code>&lt;/pre>&lt;p>Switching projects is one key combo. The agent in &lt;code>mattgoodrich.com&lt;/code> is still where I left it when I jump back from &lt;code>claude-chats&lt;/code>. No new SSH session, no new shell, no rebuilding context.&lt;/p>
&lt;p>I don&amp;rsquo;t have a fancy tmux config. Named windows. A status bar I can read. Sane keybindings. The deeper rabbit hole is there if you want it, but I&amp;rsquo;ve found the marginal value of every tweak past those basics drops fast.&lt;/p>
&lt;p>The important part is that tmux keeps running on the Mac Studio. The SSH connection can drop. The laptop can close. The WiFi can flake. None of that touches the session. I &lt;code>ssh studio &amp;amp;&amp;amp; tmux attach&lt;/code> and everything is right where it was.&lt;/p>
&lt;h2 id="what-this-buys-me">What This Buys Me
&lt;/h2>&lt;h3 id="one-place-to-manage-context">One place to manage context
&lt;/h3>&lt;p>All my AI work is on one screen. Not &amp;ldquo;all my AI work on this machine.&amp;rdquo; All of it. If an agent is running, it&amp;rsquo;s running here. If a job is in flight, it&amp;rsquo;s in flight here. If I want to check last night&amp;rsquo;s run, I switch to that window.&lt;/p>
&lt;p>I used to spend more time than I&amp;rsquo;d admit thinking &amp;ldquo;wait, was that on the Mac or the MacBook.&amp;rdquo; That&amp;rsquo;s gone. There&amp;rsquo;s one place. The thing is either there or it isn&amp;rsquo;t.&lt;/p>
&lt;h3 id="same-session-from-any-device">Same session from any device
&lt;/h3>&lt;p>The Mac Studio is the compute. Whatever I&amp;rsquo;m holding is just a window. MacBook on a plane, iPad in a coffee shop with a Bluetooth keyboard, phone in a pinch with Termius — same session, same state, same windows.&lt;/p>
&lt;p>The clients don&amp;rsquo;t need to be powerful. They don&amp;rsquo;t need the local models. They don&amp;rsquo;t even need the project source. They just need an SSH client.&lt;/p>
&lt;h3 id="resumable-everything">Resumable everything
&lt;/h3>&lt;p>This is the one I value most. Close the laptop in the middle of a Claude Code session — the agent keeps going. Get on a plane and lose connectivity for four hours — when I reconnect, the session is exactly where it was. Hotel WiFi drops the SSH connection — tmux doesn&amp;rsquo;t care.&lt;/p>
&lt;p>For regular coding this matters less because the work is the files. For AI work, the running state &lt;em>is&lt;/em> the work. tmux is what makes that state durable across every kind of interruption a normal day produces.&lt;/p>
&lt;h2 id="what-i-havent-solved">What I Haven&amp;rsquo;t Solved
&lt;/h2>&lt;p>The setup is good. It also has edges I work around rather than fix.&lt;/p>
&lt;h3 id="artifacts-have-to-land-somewhere-synced">Artifacts have to land somewhere synced
&lt;/h3>&lt;p>Anything an agent produces — an image, a generated config, a PDF — lives on the Mac Studio&amp;rsquo;s filesystem. If I want it outside the terminal, it has to land somewhere that syncs or is otherwise reachable from the client. Code goes into a Git repo, which is the cleanest path. Notes go into Obsidian with Sync turned on. Everything else lands in iCloud Drive, Google Drive, or Dropbox — pick your sync of choice. None of this is hard, but it&amp;rsquo;s a habit you have to build. The first time you produce something cool and realize it&amp;rsquo;s stuck on a machine sitting in your office at home, you remember to wire it up next time.&lt;/p>
&lt;h3 id="some-macos-dialogs-still-want-a-hand-on-the-mac">Some macOS dialogs still want a hand on the Mac
&lt;/h3>&lt;p>It&amp;rsquo;s rare, but every so often a system or permissions dialog needs me to click &amp;ldquo;Allow&amp;rdquo; on the actual Mac Studio. Rebooting after an OS update is the most common culprit. The fix is VNC over the same SSH connection — forward the Screen Sharing port to the client, connect with a viewer, and click whatever needs clicking. Same Cloudflare Tunnel, same auth, just a different local port.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ssh -L 5900:localhost:5900 studio
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Screen Sharing must be enabled on the Mac Studio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Then point any VNC viewer at localhost:5900&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Two things to keep in your threat model when you do this. First, the same Cloudflare Access policy that gates SSH also gates this VNC path — an SSH-key compromise grants screen access too, with no second factor in between. Second, I leave Screen Sharing turned off by default and only flip it on for the few minutes I actually need it. Together those keep the VNC surface small and well-gated, but it&amp;rsquo;s a place where defense-in-depth is thinner than the rest of the setup, and worth being deliberate about.&lt;/p>
&lt;h3 id="pasting-screenshots-into-the-remote-session">Pasting screenshots into the remote session
&lt;/h3>&lt;p>This is the one I haven&amp;rsquo;t cracked. Copy an image to my laptop&amp;rsquo;s clipboard, switch to my tmux session on the Mac Studio, hit paste — nothing lands. The clipboard lives on the client. The session lives on the server. The bridge doesn&amp;rsquo;t exist, at least not in any form I&amp;rsquo;ve gotten clean. The workaround is dropping the file into a synced folder and pasting the path, which works for one screenshot and falls apart when I want to drop ten into a conversation. It&amp;rsquo;s my biggest day-to-day gripe with the setup, and I haven&amp;rsquo;t seriously gone looking for a fix yet. If you&amp;rsquo;ve solved this, please find me.&lt;/p>
&lt;h2 id="whats-next">What&amp;rsquo;s Next
&lt;/h2>&lt;p>A couple of things I&amp;rsquo;m watching.&lt;/p>
&lt;p>The Mac Studio is a single point of failure for availability. If it goes down, the workspace is down. So far it&amp;rsquo;s been reliable enough that I haven&amp;rsquo;t built a standby.&lt;/p>
&lt;p>The same centralization that gives me one place to manage availability also concentrates &lt;em>confidentiality&lt;/em>. Every agent, every loaded context, every credential the agents can reach lives on the same host. So my threat model for that machine is closer to &amp;ldquo;production server&amp;rdquo; than &amp;ldquo;personal Mac&amp;rdquo; — patching cadence, audit logging, account separation, and least-privilege all get treatment I&amp;rsquo;d never bother applying to the laptop. The single-host architecture is the right tradeoff for me. It&amp;rsquo;s also a tradeoff I had to be deliberate about, not a default I drifted into.&lt;/p>
&lt;p>The honest answer on multi-machine is that 95% of what I do fits comfortably on one Mac Studio, and the other 5% is rare enough that I just deal with it. The setup does what I wanted: one place, reachable from anywhere, always there when I come back.&lt;/p></description></item></channel></rss>