How I Built a Persistent Remote Workspace for Developers and Coding Agents
Last Updated on September 22, 2026 by Editorial Team
Author(s): Karuppasamy A
Originally published on Towards AI.
A practical Mac-to-Linux setup with Herdr, coding agents, visible browser testing, and deliberate access boundaries.

Start the frontend, API, database, browser, IDE, and coding agent. Add another worktree for a second task. A large application can make the laptop feel like the limit of the workflow.
I have been experimenting with moving development compute to a remote Linux machine. My Mac remains the place where I give instructions, review code, and watch the application. Herdr organizes the remote workspace around Claude Code and Codex.
The visible-browser workflow works in my personal setup. This guide explains how to assemble it, including a simpler direct HTTP connection supported by current Claude documentation. The commands are examples to adapt to your repository; this article is not a benchmark or a completed team rollout.
What you will build
The remote VM runs repositories, application services, development data, tests, and agent CLIs. Chrome and Playwright MCP run on the Mac. SSH carries application requests toward the VM and browser-tool requests back toward the Mac.

The arrows show requests; responses return over the same connections. Example ports are 3000 for the frontend, 4000 for the API, and 8931 for Playwright MCP. Replace them consistently if your project uses others.
You need a Mac with Chrome, SSH, and a supported Node.js LTS release that meets your tool requirements; a Linux development VM with SSH access; and a repository whose development commands you understand. Agent subscriptions or API access remain separate requirements.
Running an agent CLI on your VM does not mean its language model is self-hosted there. Model hosting and provider access remain separate decisions.
1. Prepare a development instance with limited access
Environment: VM provider console, then Mac terminal.
Start with a dedicated development VM and a non-root account. Use a separate SSH key, verify the server’s host-key fingerprint through the provider console, and keep administrative recovery access available while changing SSH or firewall settings.
Limit inbound SSH to your trusted source IP or private network. Do not open ports 3000, 4000, or 8931 to the internet for this workflow. Apply the restriction in the provider firewall and review the host firewall too. The exact commands depend on your distribution and provider; Ubuntu's firewall documentation explains one common implementation.
Confirm the SSH server permits the required forwarding and applies GatewayPorts no to this connection. A server configured with GatewayPorts yes can force a reverse listener onto all interfaces despite the client's loopback request. Have the administrator check the effective policy before creating the browser bridge. OpenSSH server configuration
Use development credentials and synthetic or approved development data. Keep production databases, deployment credentials, personal browser sessions, and cloud administrator roles outside the workspace. Review repository scripts before running them: an agent can invoke tools with the permissions its account possesses.
For ongoing instance safety, I would make these responsibilities explicit:
- Apply security updates and plan reboots so active work can stop and recover cleanly.
- Back up code and configuration, including uncommitted work, and test restoration. Store secrets separately with controlled access.
- Use individual accounts and SSH keys. Avoid shared root access and unrestricted sudo permissions for agent accounts.
- Set spending alerts, monitor CPU, RAM, and disk, and apply resource limits before adding parallel agents.
- Keep attributable action logs without exposing tokens or sensitive output. Require human approval for destructive deletions, deployments, and any exceptional production access; define who can grant it.

Readiness check: From the Mac, connect using your actual non-root username and VM address:
ssh DEV_USER@VM_HOST
On the VM, whoami should show the development account. Finish key-based access before proceeding; avoid placing private keys or passwords in repository files.
2. Install and initialize the remote tools
Environment: remote VM.
Install Git and the runtime versions your repository requires. Follow the official Claude Code quickstart and, optionally, Codex CLI setup. Authenticate each CLI under your development account before installing its Herdr integration.
Herdr manages the workspace; it does not install these agents for you. Its integrations expect their configuration directories to exist. Herdr installation and integration requirements
The documented Herdr installer can be downloaded for inspection first:
curl -fsSL https://herdr.dev/install.sh -o herdr-install.sh
less herdr-install.sh
sh herdr-install.sh
Read the downloaded script before running the third command. Reopen the shell if the installer changes your executable path. Confirm the commands are available:
git --version
node --version
claude --version
codex --version
herdr --version
Skip the Codex checks and integration if you are only using Claude. Run each chosen agent once to complete its normal login flow, then exit back to the shell.
3. Make the application work on the VM first
Environment: remote VM.
Clone your repository into your development account. The following path and URL are placeholders:
mkdir -p ~/work
cd ~/work
git clone YOUR_REPOSITORY_URL my-app
cd my-app
Follow the repository’s setup instructions. Use its pinned runtime, package manager, and lockfile. For an npm project with a committed package-lock.json consistent with package.json, the dependency-install command is:
npm ci
See npm’s clean-install requirements.
Configure development-only environment variables. Bind the frontend, API, and development database to private interfaces appropriate to the setup. For this single-VM example, use 127.0.0.1 for the application listeners.
For a Next.js project whose dev script invokes next dev, this is an example frontend command:
npm run dev -- --hostname 127.0.0.1 --port 3000
These flags are specific to Next.js development commands. Vite and other tools use different options. For an API that already reads HOST and PORT, an example is:
HOST=127.0.0.1 PORT=4000 npm run dev
Environment variables do nothing unless the application consumes them. Check the listener rather than assuming the setting worked:
ss -ltnp
curl -I http://127.0.0.1:3000
Readiness check: The frontend responds and the intended listeners show loopback addresses, rather than 0.0.0.0 or [::]. Test the API using your repository's documented read-only health endpoint. Fix local VM startup failures before adding tunnels.
4. Put the work inside Herdr
Environment: remote VM.
Install integrations for the agents you initialized, then open the project workspace:
herdr integration install claude
herdr integration install codex
herdr integration status
cd ~/work/my-app
herdr
Use separate panes for application services, agents, and tests. Run claude and codex in their intended project directories. If services were started outside Herdr in step 3, stop those test instances normally before restarting them inside panes; avoid duplicate port listeners.
Readiness check: You can identify each pane’s job, and the frontend and API still respond. Keep the agent’s task and working directory explicit, especially when using multiple branches.
5. Prepare the visible browser on your Mac
Environment: Mac, dedicated Chrome profile.
Create a development-only profile and install the official Playwright extension. Sign in only to the development accounts needed for the task.
Keep Chrome open. In a Mac terminal, start the MCP server:
npx -y @playwright/mcp@latest \
--extension \
--host 127.0.0.1 \
--port 8931
The @latest tag moves. After testing, record the tool versions and replace it with the tested package version when creating a repeatable team setup.
Use a terminal without PLAYWRIGHT_MCP_EXTENSION_TOKEN configured. The extension requests connection approval by default; that optional token bypasses the dialog. For this walkthrough, approve the connection yourself and select the intended development tab. Extension setup and approval
Keep the default host check: do not add --allowed-hosts '*'. The explicit host setting keeps this server on loopback. Playwright MCP configuration
Readiness check: The process remains running. In another Mac terminal, inspect its listener:
lsof -nP -iTCP:8931 -sTCP:LISTEN
Expect 127.0.0.1:8931. If several Chrome profiles have the extension, follow its documented profile-selection option rather than relying on whichever profile was used last.
6. Open the SSH connection in both directions
Environment: a separate Mac terminal.
Leave the Playwright terminal running. Replace the SSH destination below:
ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-L 127.0.0.1:3000:127.0.0.1:3000 \
-L 127.0.0.1:4000:127.0.0.1:4000 \
-R 127.0.0.1:8931:127.0.0.1:8931 \
DEV_USER@VM_HOST
-L creates Mac-side listeners for remote application services. -R creates a VM-side listener that reaches Playwright MCP on the Mac. The forwarding connection carries traffic over SSH. OpenSSH forwarding
ExitOnForwardFailure catches listener-setup failures; it does not prove the destination service is healthy. The keepalive options detect an unresponsive connection and can terminate it after roughly 90 seconds here. They do not reconnect it automatically. OpenSSH configuration
Readiness check: Open http://127.0.0.1:3000 in the development Chrome profile. It should show the remote application. On the VM, ss -ltnp should also show the reverse listener on 127.0.0.1:8931. Keep this terminal open.
7. Connect remote Claude Code to the browser tool
Environment: remote VM, development account.
Claude Code supports an HTTP MCP connection directly:
claude mcp add --transport http --scope user \
playwright-mac http://127.0.0.1:8931/mcp
claude mcp get playwright-mac
That endpoint is loopback on the VM; SSH forwards it to the Mac. The older intermediate mcp-remote process is unnecessary for this configuration. The user scope makes this entry available to that user's Claude sessions, so keep the account dedicated to development. Claude Code MCP configuration
Restart or open Claude Code in the intended Herdr pane. The get command shows the saved configuration and connection status; /mcp lets you inspect or reconnect the server inside the active session. Claude MCP server status
For the first request, ask:
Use playwright-mac to open http://127.0.0.1:3000 in my development browser tab. Describe the page and report any visible error. Do not submit forms or change account data.
Approve the extension connection on the Mac. Readiness check: You see Claude interact with the expected tab. Codex can share the workspace, but configuring and validating its browser tools is a separate step.
8. Test one change and one disconnection
Environment: remote Herdr workspace and Mac browser.
Choose a small issue. Reproduce it, request a scoped change, inspect the diff, run the repository’s relevant tests, and review the application. Watching browser actions supplements test assertions and code review.
To detach from Herdr, press Ctrl+b, then q. Reconnect over SSH and run herdr to return. Detaching keeps the server's pane processes running. A server restart ends those original processes; restoration is a different mechanism. Do not use herdr server stop as a detach command. Herdr persistence
The browser bridge still needs the Mac awake, Chrome and Playwright MCP running, and SSH connected. A remote agent waiting for that bridge can stall or fail when the Mac disconnects.

Test this boundary deliberately with a harmless build or test run. For stronger reliability, plan process supervision, resource limits, backups, and recovery. Persistence alone does not guarantee task completion.
If a step fails
SSH reports an occupied port: Inspect listeners on the relevant machine; change the port mapping or stop your known stale process. Do not kill an unidentified process.
The app fails in Mac Chrome: Test it on VM loopback first, then check the local forwarding connection and browser API URL. A browser request uses the Mac’s network perspective.
Claude cannot reach MCP: Confirm the Mac server, SSH reverse listener, /mcp path, and Claude's /mcp status. Server policy may prohibit forwarding.
The wrong Chrome profile appears: Check the extension’s profile-selection instructions and select the development profile explicitly.
Browser actions stop after sleep: Wake the Mac, restore Chrome/MCP and the tunnel, then check the agent’s actual state before retrying.
Before expanding to a team
Measure startup, rebuilds, test duration, memory, latency, recovery effort, and total operating cost against the same local workflow. Size the VM around evidence.
Give each developer an identity and a deliberate isolation boundary. Separate Linux users still share network ports unless network namespaces are separated. Loopback is not private to one user on a shared host. Linux network namespaces
Git worktrees separate working directories; they do not isolate services, databases, credentials, or resources. Allocate those intentionally before parallelizing agents. Git worktrees
The result I am pursuing is a workspace that is easier to return to, inspect, and steer across sessions. The device becomes one way into that work.
One small improvement I built next
I also built Local Clipboard, a Mac app that lets me paste my Mac clipboard into Claude sessions on the remote VM.
Comment “CLIPBOARD” if you’d like a walkthrough in the next post. Follow for more practical developer workflows.
Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.
Published via Towards AI
Towards AI Academy
We Build Enterprise-Grade AI. We'll Teach You to Master It Too.
15 engineers. 100,000+ students. Towards AI Academy teaches what actually survives production.
Start free — no commitment:
→ 6-Day Agentic AI Engineering Email Guide — one practical lesson per day
→ Agents Architecture Cheatsheet — 3 years of architecture decisions in 6 pages
Our courses:
→ AI Engineering Certification — 90+ lessons from project selection to deployed product. The most comprehensive practical LLM course out there.
→ Agent Engineering Course — Hands on with production agent architectures, memory, routing, and eval frameworks — built from real enterprise engagements.
→ AI for Work — Understand, evaluate, and apply AI for complex work tasks.
Note: Article content contains the views of the contributing authors and not Towards AI.