How I Made Code-OSS Support Remote AI Workspaces over SSH
GitHub repository: realreadpaper/coder
The Short Version
I was not building an SSH file editor. I wanted an AI development environment with correct remote semantics:
local desktop IDE
-> SSH into a remote development machine
-> open a remote directory as the workspace
-> let Codex read, write, search, and execute there
-> terminal, Git, Search, LSP, and Debug all run against the remote filesystemSFTP and local mirrors are not enough for that. The final solution is a Code-OSS fork: reuse Workbench, Extension Host, Remote Agent, FileService, Terminal, Search, Git, LSP/DAP, then build the Remote-SSH product layer and AI remote execution layer ourselves.
One-line summary:
Reuse Code-OSS as the IDE platform.
Build Remote-SSH resolver, remote-ai-server, Codex remote bridge, approval, and sandbox.Reading Path
This post follows the decision chain:
- Why SFTP/local mirrors are not enough.
- Why Code-OSS has to be the base.
- How the Remote-SSH loop works.
- How the remote server is packaged and verified.
- The hardest Codex question: where does UI run, and where does execution run?
- How
ai-codex-remote-bridgemoves execution to the remote host. - How approval, sandboxing, and verification close the loop.
1. The Goal Is Remote Semantics, Not SSH
The simplest idea is an SSH editor:
ssh list files
-> read remote file
-> edit locally
-> save back over ssh
-> run commands over sshThat may be enough for a plain editor. It is not enough for Codex.
The Codex VS Code extension is not a simple CLI wrapper. It depends on VS Code platform capabilities:
workspace.workspaceFoldersworkspace.fscommands.registerCommand- Webview / sidebar / custom editor
- diagnostics / references / workspace symbols
- terminal
- Chat Sessions proposed API
- LSP MCP capabilities
With only SFTP, Codex may still see a local file workspace, a virtual URI scheme, or an incomplete VS Code API surface. A sidebar opening does not prove the agent is operating in the right directory.
The first key prompt was investigative:
Do not write code.
Analyze which VS Code APIs the OpenAI Codex extension depends on.
If we implemented a remote IDE from scratch, list the platform capabilities required.
Conclude:
- which parts must reuse Code-OSS
- which parts can be built ourselves
- which closed-source implementations must not be copiedThat moved the plan from “write a remote editor” to “fork Code-OSS.”
2. Why Code-OSS
Code-OSS already provides the parts I should not rewrite:
- Workbench
- Extension Host
- FileService
- Webview
- Commands / Menus / Context keys
- Text model
- Terminal / PTY
- Search / ripgrep
- Git
- LSP / DAP
- Remote Agent protocol
The custom layers are:
our.remote-ssh
-> SSH host selection
-> remote server installation
-> tunnel/local forwarding
-> ResolvedAuthority
-> diagnostics
remote-ai-server
-> server tarball
-> bootstrap
-> manifest/releaseDoctor
-> CentOS 7 ABI gate
ai-codex-remote-bridge
-> remote Linux Codex CLI
-> remote cwd / env
-> approval
-> workspace sandboxThe boundary matters: do not copy Microsoft ms-vscode-remote.remote-ssh closed-source code, and do not rebuild the remote stack Code-OSS already has.
3. The Remote-SSH Skeleton
The final path is:
Local Code-OSS fork
-> our.remote-ssh resolver
-> ssh-remote+dev
-> SSH tunnel
-> remote-ai-server
-> Remote Agent
-> Remote Extension Host
-> remote FileService / Terminal / Search / Git / LSPThe remote workspace URI is not a local path:
vscode-remote://ssh-remote+dev/home/user/projectThe local Workbench renders UI. File access, terminal, search, Git, and language servers sit behind the remote Extension Host and Remote Agent.
The implementation prompt was deliberately narrow:
Implement the minimal Code-OSS Remote-SSH fork loop.
Requirements:
- Do not copy the closed-source Remote-SSH extension
- Reuse Code-OSS Remote Authority Resolver
- Install remote-ai-server over SSH
- Open local port forwarding
- Return ResolvedAuthority
- Provide diagnostics
- Add tests or verification scripts for each stepThis kept Codex on the product layer instead of rebuilding the IDE.
4. Remote Server Distribution
The remote installation looks like:
~/.remote-ai-server/bin/<commit>/
bin/remote-ai-server
node
out/server-main.js
product.json
extensions/The local resolver does four things:
- Check the remote environment over SSH.
- Install or reuse the server tarball for
<commit>. - Start
bin/remote-ai-server. - Open a local tunnel and return the authority to Code-OSS.
There is a real compatibility trap here: many enterprise Linux machines still run CentOS 7 with glibc 2.17. Some requirement scripts conservatively ask for glibc >= 2.28, while the actual binary ABI can be lower.
So I asked Codex for a release gate instead of blindly copying a requirement check:
Write remote server packaging and releaseDoctor.
Requirements:
- manifest records sha256, size, min glibc
- tarball must contain node, bin/remote-ai-server, out/server-main.js, product.json
- can overlay compatible Linux Node and native .node modules
- no macOS AppleDouble metadata in tarballs
- support validation on ssh dev with glibc 2.17That turned “it launches” into a repeatable release condition.
5. The Hardest Codex Question: Where Does It Run?
In a full Remote-SSH workspace, Codex has three kinds of behavior:
UI:
sidebar / webview / custom editor / commands
Workspace:
workspaceFolders / file references / diagnostics / symbols
Agent execution:
codex CLI / shell / git / rg / file patchThese cannot be placed blindly in one process.
The UI should stay local because the user needs the sidebar, webviews, and commands locally. Agent execution must be remote. Otherwise Codex edits local files, runs a local shell, and searches with local rg.
There is also a platform issue: the locally installed Codex extension may ship with a macOS CLI binary. That cannot run on a Linux remote host.
That is why the system needs ai-codex-remote-bridge.
6. What ai-codex-remote-bridge Does
ai-codex-remote-bridge is a workspace extension running in the remote Extension Host.
It is responsible for:
- Detecting whether the current workspace is
ssh-remote. - Detecting the
openai.chatgptextension. - Preparing a Linux Codex CLI on the remote host.
- Pointing
chatgpt.cliExecutableat a managed wrapper. - Syncing the necessary
~/.codex/auth.jsonandconfig.toml. - Setting the remote
cwd, environment, and workspace root. - Forwarding approval requests back to local UI.
Platform selection must be a hard rule:
Remote Codex CLI must be Linux.
linux-x64 -> codex-linux-x64.tar.gz
linux-arm64 -> codex-linux-arm64.tar.gz
darwin-* -> rejectRemote execution also needs explicit environment:
REMOTE_AI=1
REMOTE_AI_AUTHORITY=ssh-remote+dev
REMOTE_AI_WORKSPACE_ROOT=/home/user/project
REMOTE_AI_APPROVAL_CHANNEL=remoteai.approvalThe first rule of remote AI is: never let a task that appears remote silently fall back to local execution.
7. Approval and Sandbox
Once AI can execute commands remotely, the safety model has to be part of the core design.
The default policy is:
read/list/search/git status: allow
write/applyPatch/delete: diff approval
exec: command approval
network command: elevated approval
sudo/root/system path: deny by default
outside workspace root: deny unless explicitly allowedLocal UI can show approval prompts, but path checks cannot live only in local UI. The remote bridge also needs a workspace sandbox:
workspace root realpath = /home/user/project
candidate path
-> clean
-> resolve symlink
-> verify startsWith(root)I had Codex start with tests like:
workspace sandbox:
- /home/user/project/src/a.ts allowed
- /home/user/project2/a.ts blocked
- /home/user/project/../.ssh/id_rsa blocked after normalizationSmall tests like these prevent a dangerous illusion: a path string looking inside the workspace does not mean it is safe.
8. Native Chat UI
Code-OSS includes native Chat, Inline Chat, and Quick Chat entries. This fork is focused on RemoteAI + Codex, so I did not want another native chat surface.
The approach was “disable entry points, do not delete the world”:
- Hide Workbench Chat, Inline Chat, and Quick Chat.
- Remove native Chat picks from the command palette.
- Keep required chat-shaped types and DI services.
- Keep the
openai.chatgptproposed API entries inproduct.json.
That reduces product noise without breaking compatibility layers Codex or third-party extensions may still need.
9. Verification Evidence
I did not want the work to stop at “the architecture sounds right.” The project ended up with several verification layers:
releaseDoctorchecks tarballs and manifests.- Gulp compiles
our-remote-ssh,ai-codex-remote-bridge, andai-approval-ui. - Mocha covers packaging, the SSH resolver, the bridge, and workspace sandboxing.
ssh devvalidates remote install, startup, tunnels, and glibc 2.17.- GUI validation covers the RemoteAI dashboard, remote folder picking, Explorer, terminal, and file saves.
- Codex binding validation ensures remote workspaces do not silently fall back to local
codex.
One remote validation record looked like this:
server dir: ~/.remote-ai-server/bin/<commit>
bundled Node: v20.18.2
remote glibc: 2.17
bridge extension: installed
audit chain: bootstrap -> install -> launch -> tunnelThat evidence is more useful than “I think the architecture is right.”
10. How I Used Codex
In this project, Codex was most valuable in three roles:
- Evidence gathering: find the real registration points for remote authority,
server-main,extensionKind, and chat contributions. - Planning: split Remote-SSH, server packaging, Codex bridge, approval, and CentOS gates into verifiable tasks.
- Convergent implementation: change one boundary at a time with a test or verification script.
The prompt pattern I kept using was:
First search and list evidence. Do not edit code.
Based on the evidence, give 2-3 options and recommend one.
Then implement only the smallest working slice of the recommended option.
Add a test or verification script.
Do not refactor unrelated modules.
Do not delete compatibility layers.
Do not copy closed-source implementations.That pattern makes Codex act as an investigator before it acts as an engineer.
Takeaway
RemoteAI is not about SSH. It is about giving the IDE and AI correct remote semantics.
The judgments I kept are:
- File sync is not Remote-SSH.
- A virtual URI alone is not a full workspace.
- Codex UI running locally does not mean Codex execution should run locally.
- Remote AI needs a platform-correct CLI, remote cwd, remote toolchain, and approval path.
- Forking Code-OSS matters because it reuses the IDE platform instead of rebuilding the extension runtime.
The direction is simple: every action should happen on the machine where it belongs. UI is local. Workspace is remote. AI execution is remote too. The resolver, bridge, server packaging, and sandbox all exist to protect that line.