Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>VineyardNew to Visual Studio Code? Get it now.
Vineyard

Vineyard

Peter Dolkens

| (0) | Free
Tend your AI agents across machines: see every Claude Code session on every box, what it is doing, and when it needs you.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Vineyard

Tend your AI coding agents across machines from VS Code. Vineyard shows every Claude Code session on every machine you own as Machines › Workspaces › Agents, with live state (working, thinking, running a tool, asking you a question, waiting for permission, idle), model and effort, context size, the last prompt and the conversation title. Open the transcript, jump to a terminal on that machine, or resume a session from wherever you happen to be sitting.

Only Claude Code is supported today; the model, daemon and tree are provider-agnostic so others can be added.

What you can do

  • See every agent on every machine, grouped Machines › Workspaces › Agents, with live state, model, effort, context size, title and last prompt. Each tier's order is yours to choose (vineyard.sort.machines / .workspaces / .agents: status, name, recent or attention-first) with stable tie-breaks, so rows stay put while agents work. Vineyard: Settings opens all of them.
  • Open a chat for any agent: a panel styled like the Claude Code pane that streams the transcript as it grows (railway margin with coloured event markers, the current prompt pinned while you scroll, thinking collapsed and greyed, IN/OUT command blocks, an activity ticker while the agent is busy) with an info strip for model, effort, mode, prompt-cache hit rate, token totals and a map of spawned subagents.
  • Message any running agent from the composer. For sessions you drive elsewhere (the Claude extension, a terminal) the text is delivered over Claude Code's cross-session messaging socket and read between tool calls or when the agent is idle.
  • Start agents from Vineyard in any workspace on any machine (New Agent Here…), or resume an existing session under Vineyard's control. These managed sessions run as children of that machine's daemon over the stream-json control protocol, so permission prompts and questions appear as cards in the chat and are answered there. They still write the normal registry and transcript. New agents start with no questions asked (default model and effort, the configured permission mode, no first prompt); the composer carries pickers for model, reasoning effort and permission mode that change the running session in place, like the ones in the Claude Code pane.
  • Resume a past session (Resume a Past Session…, the history button) from the transcripts on any machine, newest first with title, first/last prompt, model and branch, whether or not an agent is currently attached to it. Stop / Terminate ends any live session: managed ones cleanly over their control channel, others by terminating the Claude Code process (transcript kept).
  • Rename a session by clicking its title in the chat (or Rename Session… in the tree). Managed sessions are renamed through Claude Code's rename_session control request; for others Vineyard appends the same custom-title transcript line /rename writes, so Claude Code shows the new name too.
  • Sign a machine in to Claude from wherever you are (Sign In to Claude on Machine…, or the card the chat shows when a session reports an expired OAuth session). The daemon there runs claude auth login without a browser, Vineyard opens the sign-in URL in your browser and passes the code it shows back over the mesh.
  • Join machines without SSH with a single-use invite code.
  • Self-updating fleet: install a newer extension on one machine and it upgrades every daemon over the mesh (see Staying up to date).

Observed sessions (started outside Vineyard) cannot have their permission prompts or questions answered from here: Claude Code only accepts those in the originating UI. The chat shows a card explaining that and offers to open the workspace on that machine.

Design

 ┌──────────────┐        mTLS, fleet cert         ┌──────────────┐
 │ VS Code      │◄──────────────┐                  │ falcon       │
 │  (viewer)    │  localhost    │   subscribe      │  vineyardd   │
 │      │       │──────────────►│◄────────────────►│  (quiet)     │
 │  vineyardd   │               │   snapshots      └──────────────┘
 │  (watching)  │               │                  ┌──────────────┐
 └──────────────┘               └─────────────────►│ magpie …     │
       frogmouth                                    └──────────────┘
  • One static Go binary per machine (vineyardd, ~6 MB, no runtime). It runs as a login service (launchd / systemd --user / Scheduled Task) and reads Claude Code's own on-disk state: ~/.claude/sessions/*.json (registry: pid, cwd, busy|shell|idle|waiting), the tail of the session transcript (model, effort, pending tool calls, AskUserQuestion, end of turn), and ~/.claude/ide/*.lock (which folders VS Code has open).
  • No hub. Every daemon is equal. The daemon on the machine where you open VS Code is your orchestrator: it dials the others and subscribes. Any machine can step in at any time.
  • Silent unless watched. A daemon with no VS Code attached holds no connections, runs no timers and does not even read the Claude directory. When a viewer attaches, the local daemon connects to peers and subscribes; peers push their snapshot only on change, coalesced to one poll per second, plus one 30 s ping per connection. When the last viewer leaves (30 s grace for reloads) everything is unsubscribed and torn down. There is no gossip and no periodic re-broadcast, so N machines cost at most N-1 connections per watching machine and zero bytes when nobody is looking.
  • Sleeping machines are woken. Daemons report their hardware addresses; when a watched peer stops answering, its neighbours send Wake-on-LAN magic packets for those addresses (LAN broadcast plus unicast) and open a connection to its SSH port so a Bonjour sleep proxy wakes it, at most once every 45 s and only while a viewer is attached. Wake Machine on an offline machine does it on demand. wakePeers: false in config.json opts out.
  • A watched Mac stays awake. A Mac that idle-sleeps only surfaces for ~45 s per Wake on Demand, so its link flaps and its agents stall. While anyone is subscribed to a machine, its daemon holds a caffeinate -s assertion (macOS only, keepAwakeWhileWatched in config.json to opt out); the moment the last viewer leaves it is released. Nothing is held while nobody is looking.
  • Stateless connections. A fresh connection carries everything it needs: hello, then subscribe. Reconnects use exponential backoff (2 s → 60 s) only while someone is watching. Offline or unreachable machines show their last-known snapshot from ~/.vineyard/cache.json.
  • Security. All traffic is TLS 1.3 with mutual authentication using one shared fleet certificate (ECDSA P-256, self-signed, 100 years) generated on the first machine and copied to the others over SSH during setup. Possession of fleet.key is membership, exactly like a pre-shared key; rotate by regenerating and re-running setup. Transcript reads are sandboxed to ~/.claude/projects.
  • Joining without SSH: invite codes. Any member can mint a single-use code valid for 15 minutes (vineyardd invite, or Vineyard: Create Invite Code). The code is vineyard: + base64url JSON carrying the inviter's addresses (advertised name plus its LAN IPs), a 128-bit fingerprint of the fleet certificate, and a 128-bit random token. The joiner dials the inviter, pins the fingerprint, presents the token over TLS 1.3, and receives the fleet certificate + key and the peer list. The inviter accepts certificate-less connections only while an invite is outstanding, and such a connection may send exactly one join. This is how Windows boxes (no SSH server) and machines without key-based SSH get in; the extension bundles binaries for every platform so the joiner runs its own copy locally. Codes also work as vscode://peter-dolkens.vineyard/join?code=… links.
  • SSH is an optional bootstrap. For machines you can SSH to, Add Machine copies the binary and certificate with scp and runs vineyardd init && vineyardd install remotely. Day-to-day traffic never touches SSH either way.

Agent state derivation

Evidence State
pid gone exited
pending AskUserQuestion tool call question
pending ExitPlanMode, or registry waiting permission
pending tool call (no result yet) tool
last line is a user prompt or tool result working
last assistant block is thinking, turn not ended thinking
assistant stop_reason: end_turn idle
registry shell shell

Sessions whose working directory is a Claude Code scratchpad (…/claude-<uid>/<encoded project>/<session>/scratchpad) are shown under the project that spawned them; the encoded name is decoded against the filesystem.

Registry and transcript disagreements are reconciled (e.g. busy after end_turn = "starting next turn"; idle mid-turn for >30 s = "interrupted"). See daemon/internal/claude/derive.go and its tests.

Repository layout

daemon/                 Go module: vineyardd
  cmd/vineyardd         CLI: init | run | install | uninstall | restart | status | probe | peer | invite | join
  internal/claude       collector (reads ~/.claude), state derivation (+ tests), cross-session message sender
  internal/managed      daemon-spawned sessions over stream-json: prompts, permission prompts, questions
  internal/mesh         TLS, framing, demand-driven peer subscriptions, viewer fan-out, request relay, invites
  internal/service      launchd / systemd / Task Scheduler installers (Windows needs no elevation: XML logon task, then HKCU Run key)
src/core                wire types + formatting shared by the extension
src/extension           VS Code extension: daemon client, fleet store, tree, chat panel host, setup over SSH
src/webview             chat panel UI (bundled separately; marked for Markdown)
scripts/build-daemon.sh cross-compiles vineyardd into bin/: macOS arm64/amd64, Linux and Windows arm64/amd64/386

Install

Vineyard is on the Visual Studio Marketplace as peter-dolkens.vineyard; search for "Vineyard" in the Extensions view. VS Code then keeps it up to date on its own, and each new extension build brings the fleet's daemons along (see Staying up to date).

Every tagged release is also on the Releases page as a vineyard-<version>.vsix with the daemon binaries for all platforms bundled inside, plus the standalone vineyardd-* binaries and a SHA256SUMS.txt. Install with Extensions: Install from VSIX… or:

code --install-extension vineyard-<version>.vsix

To cut a release: bump version in package.json, git tag v0.3.6 && git push --tags. The Release workflow cross-compiles the daemon, runs the tests, packages the extension, publishes the GitHub release and pushes the VSIX to the Marketplace (secret VSCE_PAT; skipped for pre-releases). Running the workflow manually from the Actions tab produces a pre-release named after the commit.

Staying up to date

Updates flow from the extension outwards, so upgrading one VS Code is enough to upgrade the fleet:

  • Extension. Installed from the Marketplace, VS Code updates it itself. For VSIX installs the extension asks the GitHub Releases API at most once a day whether a newer version exists and offers to download and install it (vineyard.checkForUpdates, or run Vineyard: Check for Extension Updates). That single request is the only time Vineyard talks to anything outside your machines.
  • Daemons. The extension bundles a vineyardd build for every platform. When a Vineyard view is open and it sees an online machine reporting an older daemon than the bundled one, it streams the matching binary to that machine over the existing mesh connection (the upgrade request, relayed by the local daemon in 512 KB chunks). The receiving daemon stages the file, checks the SHA-256, runs vineyardd version on it to prove it executes on that platform, then hands over to it: the new binary copies itself into ~/.vineyard/bin, re-registers the login service and restarts. No SSH, no polling, and nothing at all happens while every daemon is current. Turn it off with vineyard.autoUpdateDaemons; Update Daemon on a machine or Update All Daemons does the same by hand. Only the numeric part of a version is compared, so two different dev builds never overwrite each other; unparseable versions (dev) are never touched. Daemons older than 0.3.0 do not understand upgrade, so the first update of those goes over SSH (or the local installer) once.

Build and run

npm install
npm run build:all        # Go cross-compile into bin/ + esbuild bundle into dist/
npm test                 # node --test + go test

Press F5 ("Run Vineyard") to launch an Extension Development Host. In the Vineyard view:

  1. Set Up This Machine – writes ~/.vineyard/config.json, generates the fleet certificate and installs the login service. The view connects to the local daemon within a second.
  2. Create Invite Code on this machine, then on another machine (with the extension installed) run Join Fleet with Invite Code and paste it. The joiner fetches the certificate and peers from the inviter, installs its own service and shows up in both views. This needs only TCP reachability on the daemon port, no SSH.
  3. Add Machine (alternative) – enter an SSH host. The extension detects the platform, copies the matching binary and the certificate, runs init with the current peer list, installs the service, and registers the new peer locally. Repeat for each machine, from any machine.
  4. Every daemon learns other peers' addresses from their hellos and persists them, so a machine that was set up from frogmouth can itself be the orchestrator later.

Useful on any machine:

~/.vineyard/bin/vineyardd status        # fleet table from the local daemon
~/.vineyard/bin/vineyardd probe | jq    # this machine's snapshot without a daemon
tail -f ~/.vineyard/vineyardd.log

Protocol (newline-delimited JSON over mTLS)

Message Direction Purpose
hello {role: peer\|viewer, machineId, listen} both identity + advertised address
subscribe / unsubscribe peer→peer "push me your snapshot on change"
snapshot {snapshot} peer→subscriber full self-report (idempotent, newest at wins)
ping / pong outbound side pings liveness, 30 s
fleet, update, peerstatus daemon→viewer aggregated view for VS Code
req {id, target, op, args} / res viewer→daemon→peer transcript (tail or from a byte offset), send, spawn, respond, interrupt, stop, configure (model / effort / permission mode of a managed session, via Claude Code's set_model, apply_flag_settings, set_permission_mode control requests), login (relay claude auth login: start → URL, code → result), rename (custom session title), wake (Wake-on-LAN + sleep-proxy nudge for a peer), sessions (past transcripts for a workspace or machine), kill (terminate an observed session's process), probe, addpeer, removepeer, invite, upgrade (chunked daemon binary, see Staying up to date), version
join {token, machineId, listen} / joined {cert, key, peers} joiner→inviter (no client cert) one-shot enrolment while an invite is active

Managed vs observed sessions

Observed (Claude extension, terminal) Managed (started or resumed from Vineyard)
How state is read transcript tail + registry, polled 1/s while watched (stat-cached) same, plus control events from the process
Send a prompt cross-session messaging socket stdin (stream-json)
Permission prompts shown; answer in the originating UI Allow / Allow-and-remember / Deny cards
AskUserQuestion shown; answer in the originating UI option buttons + free text
Interrupt / stop no yes
Lifetime independent child of the daemon; ends if the daemon restarts

Known gaps

  • Windows daemon and installer are compiled and reasoned about but not yet tested on a real box; the Claude project-directory encoding on Windows is a best guess.
  • Installing on a Mac over SSH needs the target user to have a GUI login for launchctl bootstrap; the installer falls back to launchctl load -w.
  • No multi-hop relay: a machine you cannot reach directly shows last-known state only.
  • Only Claude Code is detected.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft