Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Read by thought-leaders and decision-makers around the world. Phone Number: +1-650-246-9381 Email: pub@towardsai.net
228 Park Avenue South New York, NY 10003 United States
Website: Publisher: https://towardsai.net/#publisher Diversity Policy: https://towardsai.net/about Ethics Policy: https://towardsai.net/about Masthead: https://towardsai.net/about
Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Founders: Roberto Iriondo, , Job Title: Co-founder and Advisor Works for: Towards AI, Inc. Follow Roberto: X, LinkedIn, GitHub, Google Scholar, Towards AI Profile, Medium, ML@CMU, FreeCodeCamp, Crunchbase, Bloomberg, Roberto Iriondo, Generative AI Lab, Generative AI Lab VeloxTrend Ultrarix Capital Partners Denis Piffaretti, Job Title: Co-founder Works for: Towards AI, Inc. Louie Peters, Job Title: Co-founder Works for: Towards AI, Inc. Louis-François Bouchard, Job Title: Co-founder Works for: Towards AI, Inc. Cover:
Towards AI Cover
Logo:
Towards AI Logo
Areas Served: Worldwide Alternate Name: Towards AI, Inc. Alternate Name: Towards AI Co. Alternate Name: towards ai Alternate Name: towardsai Alternate Name: towards.ai Alternate Name: tai Alternate Name: toward ai Alternate Name: toward.ai Alternate Name: Towards AI, Inc. Alternate Name: towardsai.net Alternate Name: pub.towardsai.net
5 stars – based on 497 reviews

Frequently Used, Contextual References

TODO: Remember to copy unique IDs whenever it needs used. i.e., URL: 304b2e42315e

Resources

Free: 6-day Agentic AI Engineering Email Guide.
Learnings from Towards AI's hands-on work with real clients.
How I Built a Persistent Remote Workspace for Developers and Coding Agents
Latest   Machine Learning

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.

How I Built a Persistent Remote Workspace for Developers and Coding Agents
A persistent remote workspace can remain available between client sessions. Continued processes depend on the remote environment; the local browser bridge still needs an active Mac connection. Illustration created with AI.

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 Mac opens remote applications through local SSH forwarding. Claude Code reaches the Mac’s browser tooling through reverse forwarding. Illustration created with AI.

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.
A recommended access model: development data and test accounts are available; staging access is limited; production access is denied by default. Worktrees organize code, while access controls protect services and secrets. Illustration created with AI.

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.

Write on Medium

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.

Remote files and independent processes can remain available after disconnection. The local browser bridge needs the Mac, Chrome, Playwright MCP, and SSH connection to be available again. Illustration created with AI.

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.