The Problem to Solve
VS Code Remote (SSH) is powerful, but there are situations where you want to handle terminal operations in your favorite external terminal like iTerm2 instead of the integrated terminal.
However, when working from an external terminal, you can't seamlessly use VS Code as your editor out of the box.
- Open files with
code <filename>from external terminals like iTerm2, Alacritty, or WezTerm - Use VS Code as the editor for
git commitorcrontab -e, but automatically fall back to another editor when VS Code isn't running
This article introduces a wrapper script that solves both.
Background: Why code Doesn't Work from Terminals Outside VS Code
Inside VS Code's integrated terminal, environment variables for communicating with the VS Code server (VSCODE_IPC_HOOK_CLI) and paths to dedicated executables are set automatically.
These aren't inherited by external terminals, though. So simply running the code command won't actually "open the file in a VS Code window."
This issue is well known, and there are existing articles offering solutions:
- Controlling VSCode From Tmux | Vinnie dot Work
- Set up
codecommand line usage in external terminal | microsoft/vscode-remote-release#3983
A common approach is to write the socket lookup in .zshrc or .bashrc — both references above take this route. The downside is that it's evaluated once at shell startup, so it can't keep up when VS Code is started or restarted afterward. The Vinnie article works around this by wrapping the lookup in a shell function you can re-run manually, but neither reference handles the case where VS Code isn't running at all.
In this article, we'll put the lookup in a standalone script that re-evaluates on every invocation and gracefully falls back to another editor when VS Code isn't running.
The Solution: A Wrapper Script Called editor
First, create a directory to hold the script (e.g., ~/bin) and save the following as editor.
Creating the Script
#!/bin/bash
# Find the most recent IPC socket
export VSCODE_IPC_HOOK_CLI=$(ls -t /run/user/$(id -u)/vscode-ipc-*.sock 2>/dev/null | head -1)
# Get the path to the VS Code CLI executable
vscode_code=$(ls -td ~/.vscode-server/cli/servers/*/server/bin/remote-cli/code 2>/dev/null | head -1)
# When VS Code is available
if [ -S "$VSCODE_IPC_HOOK_CLI" ] && [ -n "$vscode_code" ]; then
if [ $# -eq 0 ]; then
# Running `code` with no arguments often just exits silently,
# so prompt the user to specify a file when invoked as an editor
echo "When using VS Code, please specify a file: editor <filename>"
exit 1
fi
# VS Code may be hidden behind other windows or take a moment to surface
echo "Opening in VS Code..."
# --wait blocks until the file is closed in VS Code
"$vscode_code" --wait "$@" >/dev/null 2>&1
exit $?
else
# If VS Code isn't available, fall back to another editor (nano, vim, etc.)
nano "$@"
fi
Granting Execute Permission
chmod +x ~/bin/editor
Shell Configuration
Make the script callable from anywhere and register it as the system's default editor. Add the following to your .zshrc or .bashrc:
# Add ~/bin to PATH (if not already)
export PATH="$HOME/bin:$PATH"
# Register as the default editor
export EDITOR="$HOME/bin/editor"
export VISUAL="$HOME/bin/editor"
How It Works
Auto-discovering the Latest Socket
You could hardcode the socket path in .zshrc, but it changes every time VS Code restarts and breaks. This script looks under /run/user/ on every invocation, so it adapts to whatever the current connection state is.
Use from External Terminals
With this script in place, you don't have to think about whether you're inside VS Code's integrated terminal. Just type editor in your favorite external terminal and VS Code opens the file.
Handling No-Argument Invocation
Running code with no arguments simply exits. That's confusing when invoked as an editor — nothing happens — so the script prints a hint instead.
Programs differ in whether they read EDITOR or VISUAL. Many tools, including git and crontab, prefer VISUAL, but some only check EDITOR. Setting both is the most reliable approach.
Where This Helps
Once EDITOR/VISUAL point at this script, VS Code is automatically used in situations like:
-
git commit— Editing commit messages -
git rebase -i— Interactive rebase operations -
crontab -e— Editing crontabs -
Ctrl+x, Ctrl+e— Bash/Zsh command-line editing -
Claude Code's
Ctrl+X, Ctrl+E— Launching an external editor for prompt input
If VS Code isn't running when you invoke any of these, nano (or whatever you configured) takes over, so your workflow doesn't stall.
Behavior Summary
| State | editor file.txt |
editor (no arguments) |
|---|---|---|
| VS Code running | Opens in VS Code | Shows a guidance message |
| VS Code not running | Opens in nano | Opens in nano |
Closing Thoughts
I love VS Code, but iTerm2's tmux integration (tmux -CC) is so handy that I often skip the integrated terminal entirely. Even then, I still want VS Code for actual file editing, and this wrapper made that workflow much smoother. Getting Copilot completions while editing crontabs is a quietly nice bonus.
It's a small piece of configuration, but if you're a fellow VS Code user in the same situation, hopefully this is useful.
This article was originally published in Japanese at archelon-inc.jp.
Top comments (0)