Moorpost — VSCode extension
Hand off your Claude Code session between your laptop and a remote VM, from inside VSCode.
Companion UI to the moorpost CLI. The extension is a thin shell — the CLI does all the real work — but it surfaces every piece of state you care about and removes the need to remember commands.
Requirements
- macOS or Linux (Windows is not supported; use WSL).
- A Google Cloud Platform project. GCP is the only provider Moorpost ships with today; AWS / Azure are on the roadmap. You'll need permission to create Compute Engine instances in the project.
- A Claude Code subscription (or
ANTHROPIC_API_KEY).
Install
Install from the VS Code Marketplace:
code --install-extension LatentAdvisory.moorpost-vscode
The first time the extension activates, it auto-downloads the matching moorpost CLI binary from the GitHub release, verifies its SHA-256 against the published SHA256SUMS, and installs it to ~/.local/bin/moorpost. If that directory isn't on your PATH, the extension also writes the absolute path to its own moorpost.cliPath setting so commands keep working without shell changes.
If the auto-install fails (offline, sandboxed CI environment, etc.), a toast surfaces a one-click link to the GitHub release page where you can grab the binary manually.
The flow
A click-by-click walkthrough of what you actually see in VSCode.
Step 1 — open VSCode in a project
After installing the .vsix, the Moorpost entry appears in the activity bar (left rail, cloud icon). Click it.
┌────────────────────────────────────────────────────────────────┐
│ MOORPOST [↻] │
├────────────────────────────────────────────────────────────────┤
│ No Moorpost project here yet. │
│ │
│ Moorpost lets you hand off Claude Code sessions │
│ between your laptop and a remote VM. │
│ │
│ ┌──────────────────┐ │
│ │ Bootstrap │ ← click here │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────────────┘
Step 2 — Bootstrap (one-shot wizard)
Clicking Bootstrap opens a guided sequence in an integrated terminal. Each step is skipped if it's already done, so re-running is safe.
| # |
What you see |
What it does |
| 1 |
Terminal output: Detecting prereqs... followed by per-tool checkmarks or [install] prompts |
Probes gcloud, mutagen, tmux, ripgrep, rsync, node, claude on PATH; installs missing via brew / apt. |
| 2 |
A browser tab opens to claude.ai |
Standard Claude OAuth flow. The token is cached in your OS keychain. |
| 3a |
Quick-pick: "Pick a gcloud configuration for Moorpost" with one row per existing configuration plus an "Add a new gcloud account" option |
Pins the chosen configuration in .moorpost/config.yaml so all subsequent gcloud calls use it. |
| 3b |
Quick-pick: "Pick a GCP machine type for the remote VM (★ = recommended)" with hourly rate + ~$X/mo estimate per row |
Stores machine_type in .moorpost/config.yaml. |
| 4 |
Modal: "Provision the VM now? (You can also do this later.)" → Yes / No |
If yes: creates a GCE instance, runs the bootstrap script (Node + Claude Code), leaves the VM stopped. ~3 min wall-clock. |
After Bootstrap finishes, the Moorpost panel updates:
┌────────────────────────────────────────────────────────────────┐
│ MOORPOST [↻] │
├────────────────────────────────────────────────────────────────┤
│ Project: my-app │
│ Provider: gcp │
│ Active side: local ← click to │
│ VM: my-app-vm (stopped) switch │
│ Sync engine: mutagen │
│ Cost (MTD): $0.04 │
└────────────────────────────────────────────────────────────────┘
And the status bar at the bottom right reads:
☁ local · stopped · $0.04
Step 3 — work locally as usual
Open a terminal and run claude (or use Anthropic's official Claude Code VSCode extension's panel — Moorpost auto-detects it). Nothing routes through Moorpost yet; you're paying $0.
Step 4 — Handoff (when you step away)
If your session runs in Anthropic's Claude Code panel: close that panel before triggering handoff (Moorpost shows a pre-flight prompt). VSCode doesn't allow one extension to close another's panel programmatically. See Working with Anthropic's Claude Code VSCode extension below for details.
Three ways to trigger:
- Click the status bar (
☁ local · stopped · $0.04) → pick "Handoff a session to remote".
- Right-click "Active side: local" in the Moorpost panel → Handoff to remote.
- Wait for a smart prompt: a non-modal notification "Hand off to remote? You've been away for 30 min." appears automatically (see Smart handoff prompts below).
What you see, in order:
- Notification: "Pause local Claude (be at a turn boundary), then continue?" → Yes.
- Notification: "Starting my-app-vm…" (~15s).
- Notification: "Syncing project files → my-app-vm:~/moorpost/my-app …" (mutagen progress).
- Notification: "Syncing agent session state …".
- An integrated terminal appears titled "Moorpost: Claude (remote)", already attached to the remote tmux session running
claude --resume <id>. Type prompts here as if Claude were local — they go to the VM.
- Status bar updates to
☁ 1 on remote · running · $0.04.
Close the laptop. The VM keeps running, the sync keeps mirroring, Claude keeps working.
Step 5 — Return (when you come back)
Same caveat as handoff: if the session runs in Anthropic's Claude Code panel on the remote, close that panel before triggering return.
Same three triggers, mirrored:
- Click the status bar (
☁ 1 on remote · running · $0.42) → pick "Return a session to local".
- Right-click "Active side: 1 on remote" in the Moorpost panel → Return to local.
- Right-click an individual remote session under the Remote sessions group in the panel → Return (per-session granularity if you have multiple).
What you see, in order:
- Notification: "Pulling project files ← my-app-vm:~/moorpost/my-app …".
- Notification: "Pulling agent session state ←".
- The "Moorpost: Claude (remote)" terminal closes; a new one opens titled "Moorpost: Claude (local)", attached to your local
claude --resume.
- Notification: "Stopping my-app-vm…" (default; toggle via
moorpost.autoStopWhenNoRemoteSessions).
- Status bar back to
☁ local · stopped · $0.42.
Always-on remote (skip the return)
If you don't care about cost optimization and just want the laptop-close-doesn't-matter benefit, you can stay on remote indefinitely after the first handoff:
- Trigger handoff once. The session is now on the VM.
- Keep working from the "Moorpost: Claude (remote)" terminal (or the Anthropic Claude Code panel, if that's your routed surface). Files round-trip via mutagen continuously, so editing a file in VSCode locally is reflected in the VM and vice versa.
- Skip the return. Open VSCode tomorrow morning, the session is still running on the VM, the terminal reattaches automatically.
The VM still auto-stops on idle (default 60 min, configurable via persistent.auto_stop_minutes in .moorpost/config.yaml), and the next prompt re-starts it transparently — so your bill is bounded even in always-on mode. The tradeoff vs. local-first: latency is whatever your VM's region adds (~30 ms typical), and you're paying the full hourly rate while the VM is running, not just while you're actively prompting.
Mix and match: the per-session model means you can have one session always-on-remote (a long-running agent loop) while another session does the local-first dance for ergonomic editing.
Smart handoff prompts
The extension watches three signals and offers a non-modal "Hand off to remote?" notification when you appear to have stepped away — so you don't have to remember:
- Window focus loss — VSCode unfocused for
moorpost.promptOnFocusLossMinutes (default 30 min)
- Editor inactivity — no edits or selection changes for
moorpost.promptOnIdleMinutes (default 15 min)
- OS sleep — wall-clock drift > 60s on the heartbeat tick, indicating the laptop slept
Cooldown of 15 min between prompts. Set either threshold to 0 to disable.
Conflict surface
If mutagen flags a sync conflict (file edited on both sides), the handoff or return aborts with a notification: "3 sync conflicts. Resolve?" Click it to open the Sync conflicts view, which lists each path and offers per-conflict Prefer local / Prefer remote buttons. Re-run the handoff/return after resolving.
Working with Anthropic's Claude Code VSCode extension
If Anthropic's official Claude Code extension is installed, Moorpost auto-detects it. On handoff, instead of (or in addition to) opening the "Moorpost: Claude (remote)" terminal, Moorpost re-routes that extension's panel to talk to the remote claude process. The model retains full conversation context; the panel scrollback resets (prior messages remain in Claude Code's history list).
⚠️ You must close the Claude Code panel before handoff/return. VSCode does not let one extension programmatically close another extension's panel, so Moorpost cannot do this for you. When you trigger handoff or return on a session running in Anthropic's panel, Moorpost shows a pre-flight notification ("Moorpost: close the Claude Code panel for …, then click 'I closed it' to handoff.") — close the tab in VSCode first, then click the button. Terminal sessions don't need this step; only the Anthropic-plugin surface does.
Control which surface gets swapped via the moorpost.handoffSurface setting:
auto (default) — terminal if a "Moorpost: Claude" terminal is open, plugin if Anthropic's extension is installed and routed, otherwise terminal.
terminal — only ever swap the Moorpost terminal.
plugin — only ever swap the Anthropic extension's panel.
What you can see
Status bar (bottom right)
A one-line summary, refreshed every 10s (configurable via moorpost.statusBarRefreshSeconds). The side label reflects per-session routing:
☁ local · stopped · $0.42 ← all sessions on this laptop
☁ 1 on remote · running · $0.42 ← one session routed to the VM
☁ 3 on remote · running · $1.08 ← multiple sessions on the VM
Click it to open a quick-pick that routes to the next-needed step (bootstrap → sign-in → provision when setup is incomplete) or, once configured, lets you pick Handoff a session to remote, Return a session to local (when any session is on remote), or Show status details.
Project tree (activity bar)
A persistent panel showing every piece of state at a glance:
| Row |
Example value |
Notes |
| Project |
my-app |
Slug from .moorpost/config.yaml |
| Provider |
gcp |
The configured cloud |
| Active side |
local / 1 on remote / N on remote |
Per-session: counts how many sessions are routed to the VM. Click to open the Handoff/Return/Status quick-pick. |
| VM |
my-app-vm (running) |
Only when provisioned |
| Sync engine |
mutagen |
|
| Cost (MTD) |
$0.42 |
Month-to-date estimate, click for breakdown |
| Remote sessions (N) |
expandable |
Each remote SID with first-message preview |
Right-click any row for context actions (Handoff, Return, Attach, Destroy, Show cost, Show conflicts). The "Refresh" button in the view title re-runs moorpost status --json.
Output panel
Output → Moorpost shows activation messages, command exits, and any CLI stderr. Useful when something fails silently.
Sessions view (commands)
- Moorpost: Show sessions (local + remote) — a quick-pick listing every session under
~/.claude/projects/<encoded>/, marked by side. Pick one to open or return it.
- Moorpost: Open remote session — open a session that's currently routed to remote in a fresh terminal.
- Moorpost: Return this session to local — return a single session without affecting others.
Commands reference
All commands live under the Moorpost category in the command palette (⌘⇧P / Ctrl⇧P).
| Command |
What it does |
| Bootstrap (one-shot setup) |
Wizard: prereqs → sign-in → init → (optional) provision |
| Install prerequisites (setup) |
Just the prereq check + install |
| Run doctor (diagnostics) |
moorpost doctor — verifies gcloud, mutagen, tmux, claude, GCP API enablement |
| Initialize project (choose folder) |
Writes .moorpost/config.yaml for the chosen folder |
| Sign in (claude OAuth) |
moorpost auth — caches the OAuth token |
| Provision VM |
Creates the GCE VM (left stopped) |
| Handoff to remote |
The handoff command |
| Return to local |
The return command |
| Switch local ↔ remote |
Opens the Handoff/Return/Status quick-pick (also bound to the status-bar click) |
| Attach to remote tmux |
SSH + tmux attach to the live Claude session |
| Show status |
Full status pane (active side, VM, sync, cost) |
| Show sync conflicts |
Lists mutagen conflicts with resolution actions |
| Show sessions (local + remote) |
Quick-pick over every session, both sides |
| Show cost details |
MTD breakdown by VM-hours, disk, IP |
| Edit project config |
Opens .moorpost/config.yaml |
| Destroy VM… |
Confirms, then deletes the VM (disk preserved by default) |
Settings
| Setting |
Default |
Purpose |
moorpost.cliPath |
moorpost |
Path to the CLI binary |
moorpost.statusBarRefreshSeconds |
10 |
Status-bar poll interval |
moorpost.promptOnFocusLossMinutes |
30 |
Idle-prompt threshold for window focus loss; 0 disables |
moorpost.promptOnIdleMinutes |
15 |
Idle-prompt threshold for editor inactivity; 0 disables |
moorpost.autoAttachOnHandoff |
true |
After handoff, open a terminal attached to the remote Claude session |
moorpost.autoMigrateOnHandoff |
false |
Skip the "Migrate this conversation?" prompt when the Anthropic Claude Code plugin is the active surface |
moorpost.autoStopWhenNoRemoteSessions |
true |
Auto-stop the VM when no sessions are routed to remote |
moorpost.handoffSurface |
auto |
Which surface handoff swaps: terminal, plugin, or auto-detect |
Architecture
The extension is intentionally tiny. Per PLUGIN.md §6.1, the CLI is the source of truth; the extension is a thin UI shell.
- Resilience: when VSCode crashes or restarts, the remote tmux session and the mutagen sync keep running. Re-opening VSCode picks up exactly where it left off.
- Terminal-only users use the CLI directly without ever installing this extension. Every UI action has a stable CLI equivalent.
- One source of state: all UI panels read from
moorpost status --json. There's no parallel state-tracking in the extension.
extension/
├── package.json # manifest, commands, settings, walkthroughs
├── esbuild.js # bundler config
├── media/walkthrough/ # markdown shown in Get-Started walkthroughs
└── src/
├── extension.ts # activate(): wires everything up
├── cli.ts # child_process wrapper around `moorpost`
├── statusBar.ts # right-aligned status bar item
├── treeView.ts # activity-bar Project tree
├── idleMonitor.ts # focus-loss / idle / OS-sleep heuristics
├── claudeTerminal.ts # detect & re-route Moorpost: Claude terminals
├── claudePluginIntegration.ts # bridge to Anthropic's Claude Code plugin
├── sessionTracker.ts # which sessions are routed where
├── sessionList.ts # parse ~/.claude/projects/<encoded>/<sid>.jsonl
├── runState.ts # transient operation state (e.g., handoff in flight)
├── output.ts # output channel helpers
└── commands/
├── index.ts # registers every command
├── extras.ts # walkthrough, first-run nudge, context watcher
└── getStarted.ts # bootstrap wizard
Develop
cd extension
npm install
npm run build # esbuild bundles src → dist/extension.js
npm run watch # rebuild on change
npm test # node --test on src/**/*.test.mts
npm run package # produces moorpost-X.Y.Z.vsix
To debug inside VSCode:
- Open the
extension/ folder in VSCode.
- Press
F5 — opens an Extension Development Host with Moorpost loaded.
- Run any Moorpost command from the palette.
License
Apache 2.0.