Skip to content
| Marketplace
Sign in
Visual Studio Code>AI>VSHermesNew to Visual Studio Code? Get it now.
VSHermes

VSHermes

synapticity

|
32 installs
| (1) | Free
Hermes Agent chat for VS Code — full agent UI (multiline input, image paste, slash commands, history, tool activity, approvals) over the Hermes API Server.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

VSHermes — Hermes Agent chat for VS Code

One product, current build 2.0.13 — each build re-verified against the pinned Hermes API surface. This README describes current functionality, not history (see CHANGELOG.md for the change log).

A Claude-Code-style chat panel for Hermes Agent, running over the Hermes API Server — not a terminal wrapper. The chat lives in a webview panel in the sidebar: real multiline input, image paste, a slash-command picker, session history, live tool activity, approvals, and model switching.

Screenshots

VSHermes chat connected to a Hermes server — the tab title shows the active server (Chat (Local)), the compatibility banner sits above the transcript, the History tree lists sessions, and the Endpoints tab holds the connection forms

Features

Chat panel

  • Multiline input: Enter sends, Shift+Enter inserts a newline; the input auto-grows with its content (long absolute paths wrap instead of scrolling) and resets to one line after send
  • Streaming markdown rendering; thinking shown in a collapsible block; tool calls rendered as live cards (tool.started / tool.progress / tool.completed)
  • Stop — the send button doubles as Stop while streaming (aborts the stream and calls POST /v1/runs/{id}/stop); /stop works identically. Intentional aborts end cleanly with no spurious error
  • Approval dialogs for agent actions that require it (POST /v1/runs/{id}/approval — deny / once / session / always)
  • Copy buttons (hover, one click): every message bubble, thinking block, code block and tool output can be copied — clipboard handled in the webview, no host round-trip
  • /new, /clear and deleting the current session reset the chat window — the view always shows the current session's messages
  • @ file references — type @ anywhere in the message and a workspace file picker opens (@CHAN lists every file whose path contains "CHAN", live as you type); selecting one inserts @<absolute path> — a plain reference (files or folders), never copied. A Browse… entry at the bottom of the picker opens the OS dialog for anything outside the workspace. Hermes reads the content itself via its own tools when it needs it, so the prompt stays lean
  • Attach files (@file <path>, paperclip button, or drag & drop anywhere on the panel) — the file is copied into $HERMES_HOME/attachments/ (deterministic name, no duplicates on re-send) and sent as @file <copy path>: the message stays a small path per file, the session owns a durable copy (survives the original moving or being deleted), and the LLM decides whether/when to load the content. No size limit — zips, PDFs, datasets and binaries all work. Drag & drop works from the OS file manager (local windows) and from the Explorer/tree views. One caveat — devcontainers / remote workspaces: VS Code does not deliver host-filesystem (Finder) drops to webviews there, which is correct VS Code behavior (microsoft/vscode#193558, #158150), not a VSHermes bug; use the paperclip (container file picker) in that case, or drop the file into the Explorer first (uploads it into the container), then drag it from there

Images

  • Paste or drag-drop into the chat; chips show pending attachments
  • Default file mode: images are saved to $HERMES_HOME/attachments/ and sent as a path reference, so text-only main models still work via Hermes' own vision fallback chain. vsh.hermes.imageTransfer: auto | inline | file (auto = inline only when the model advertises vision capability)
  • vsh.hermes.maxImageBytes / vsh.hermes.maxImageDimension downscale oversized pastes before sending
  • Pasted images render as thumbnails in history — stored [Image pasted: …] path references are mapped to webview-loadable URIs on render (attachments directory registered in the webview resource roots)

Slash commands (/ opens the picker — working actions only)

  • Working actions (executed client-side against the API): /new /clear /model /stop /history /sessions /resume /title /steer /status /skills /fork /branch /help (/title My Session sets the session title via PATCH /api/sessions/{id}; /status shows session info in chat)
  • /steer <note> injects guidance into the running agent via POST /v1/runs/{id}/steer (Hermes 0.20.4+; a ✎ Steer button appears beside Send while a run is streaming). Accepted steers are recorded in the chat as persistent "✎ steer: — accepted" rows that flip to "delivered" when the run completes (client-side only — the server has no steer persistence). On older servers /steer degrades to the TUI-only block below — it is never sent as text.
  • TUI-only commands (/compact /compress /goal /learn /undo /yolo /rollback /diff …) have no API equivalent — the REST surface has no compress endpoint, no goal judge loop, so sending them as text just burns a model turn that explains what the TUI command would have done. They are never offered in the picker and typed invocations are blocked with a "only available in the Hermes TUI — nothing was sent" note; /help lists the full catalog as reference.

Endpoints (sidebar tab in the VSHermes section, or the $(server) chat title-bar icon / "VSHermes: Endpoints…" — both reveal the tab)

  • A built-in Local connection row is always present (legacy resolution: baseUrl setting → $HERMES_HOME/.env → http://127.0.0.1:8642) — click Activate to return to it; it has none of the remote constraints
  • Named endpoint profiles (name + URL), each with its own API key stored in VS Code SecretStorage (never settings.json) — e.g. your local container and a Hermes API server on another machine. A profile's key is the API_SERVER_KEY from that server's Hermes .env — the gateway's bearer credential. It is unrelated to model/provider keys (DeepSeek, OpenAI, …), which Hermes holds in its own config
  • Remote endpoints require a key — a non-loopback profile without an API key is refused at connect ("Remote endpoints require the server's API_SERVER_KEY — set it via "VSHermes: Set Endpoint API Key""), the row shows a key required warning, and activation is refused too — a keyless remote endpoint never becomes active (tree Activate and auto-switch on session open both fail with a clear note). Keyless connections are only possible to loopback (local) servers
  • Test probes reachability and validates the key (an authenticated probe after /health), so a missing or wrong key is reported explicitly instead of a false "OK"; Activate switches and reconnects. With no profiles configured, behaviour is unchanged
  • Remote endpoints (any non-loopback host) disable file attach — the gateway can't receive files, so @file, the paperclip and drag & drop are hard-restricted with clear messages; @path references stay allowed (plain text). Pasted images are sent inline over HTTP, so image paste keeps working with a vision-capable model
  • Switching endpoints resets the current chat session (ids are server-scoped); the abandoned session stays on its server. Reconnects are deduped per server (a switch never reuses an in-flight connection to a different server) and the "/help" welcome posts once per activation, not per switch

Sessions

  • History tree view grouped per server: one collapsible section per server (Local, profile names), keyed by canonical URL — two profiles pointing at the same machine collapse into a single section — with an attach-enabled/disabled badge; cached across reloads. A background refresh that outlives an endpoint switch is stored under the server it actually queried, so sessions can never be mis-filed under another server
  • Opening a session auto-switches to the server it lives on — you continue where you left off, on the right machine; fork/delete do the same. An unreachable server surfaces a clear error and the chat stays put
  • Terminal (CLI) sessions open with full history — one pool of sessions

Actions & navigation

  • Chat header icons: New Chat, Compatibility Check, Switch Model, Show History (opens the History tab), Export as Markdown, Copy Conversation, Endpoints (opens the Endpoints tab) — plus Refresh History on the History tab's header
  • Every action also in the command palette (VSHermes: …), incl. Set API Key and Search History (filters the history tree by title / id / model / source; empty input clears)
  • Status bar: connected / offline / sync-warning + current model
  • The chat tab shows which server you're on: title "Chat (profile name)" (or "Chat (Local)" for the local connection — hostname only for a profile-less remote), the header badge shows host:port, and the status-bar tooltip the full URL
  • Model switching per session (provider + model pickers, model lock)
  • Health polling: /health is checked every 30s; gateway restarts flip the connection state automatically, and reconnect refreshes capabilities, sync state and history without user action

Sync flagging

  • The plugin ships a pinned manifest (minimum Hermes version, required features, required endpoints) and diffs it against GET /health + GET /v1/capabilities on connect. Verdicts — ok / outdated / ahead — are always visible (banner + status bar + toast), so drift is flagged instead of silently breaking.

Architecture & design decisions

HARD RULE — NO SERVER-SIDE CHANGES, EVER

VSHermes is a client-only extension. It must work against a stock, unmodified Hermes server that the user runs themselves. The user has stated this repeatedly; it is not negotiable and must not require repeating.

  • NEVER modify, patch, fork, or fix hermes-agent server code (gateway, api_server.py, run.py, tools/, agent/, or anything server-side) as part of VSHermes work.
  • NEVER fix a server bug by requiring plugin users to change their server (config, code, environment, or otherwise). Forcing users to modify their Hermes server to use the plugin is not appropriate — full stop.
  • NEVER offer or draft a "server-side patch" as an option — not even as an alternative. The answer to a server gap is: (1) make the plugin behave honestly in the gap (visible errors, stall notes, capability checks, graceful degradation — never pretend a feature works), and (2) if a real server capability is missing, report it upstream (NousResearch/hermes-agent) as the deliverable. Server-side needs go upstream FIRST; the plugin can only build on a capability after the upstream change exists.
  • Plugin users must be able to install VSHermes and use it against a stock Hermes gateway with zero server configuration beyond what Hermes itself ships.
┌─────────────────────────── VS Code ───────────────────────────┐
│  Webview (chat panel)            Tree view (history)          │
│  src/views/media/chat.ts         src/views/historyProvider.ts │
│        │ postMessage (protocol.ts)                            │
│  Extension host                                                  │
│  src/extension.ts — orchestrator, session + stream state       │
│  src/api/client.ts — HermesClient (fetch + SSE parser)          │
│  src/api/sync.ts   — capability diff engine                     │
└───────────────────────────────┬────────────────────────────────┘
                                │ HTTP (Bearer API_SERVER_KEY)
                    Hermes Gateway — platform api_server (:8642)
                    /api/sessions, /chat[/stream], /v1/runs,
                    /v1/runs/{id}/events|approval|stop,
                    /v1/capabilities, /api/model/options, …
  • Transport = the API Server (Surface A), not the TUI WebSocket. It is the surface Hermes intends for external UIs — self-describing via /v1/capabilities, and a stable contract.
  • Webview panel, not a terminal wrapper. VS Code's integrated terminal can't deliver Shift+Enter (a decade-old upstream limitation), and terminal image paste needs protocol hacks. A webview textarea gives multiline input, paste/drag-drop and a real command picker natively.
  • Slash commands are implemented client-side. The API server is OpenAI-compatible and does not interpret / text (verified against 0.20.0; only session /model overrides exist as an endpoint). The catalog maps commands to endpoints; TUI-only commands are kept as reference and blocked locally with a note — never sent as text, which would just burn a model turn. If Hermes later exposes a slash RPC over the API, the catalog's kind flags switch entries to action without UI changes.
  • Images default to file mode. Text-only main models reject inline image_url parts with a 400; saving to $HERMES_HOME/attachments/ and referencing the path lets Hermes' vision fallback chain do the analysis, and the image persists on disk.
  • Attach = copy + reference, never inline. @<path> is a plain reference (the LLM reads the file or folder in place when it wants); @file <path> — from the picker's attach form, the paperclip button, drag & drop, or typed — copies the file into $HERMES_HOME/attachments/ (deterministic name__<hash>.ext, so re-sends never duplicate) and the token points at the copy. The message stays a path per file, the session owns a durable copy, and the LLM decides when to load the content — so there are no size limits and no prompt bloat. Content is never inlined.
  • Sync manifest instead of silent drift. The plugin pins the API surface it was built against and diffs the live server's self-description against it, so a Hermes upgrade can't break the plugin unnoticed.
  • Zero-config connection. The API key and base URL are auto-discovered (SecretStorage → VSHERMES_API_KEY → $HERMES_HOME/.env, mirroring Hermes' own resolution order); a stale ~/.hermes can't shadow the live config. Fallback: VSHermes: Set API Key (stored in SecretStorage, never in settings.json).
  • The webview never holds the API key. All API traffic runs in the extension host.
  • The chat window shows the current session's messages only. The webview resets its message list whenever the host's state reports a different session id — one rule covering /new, /clear, delete-current and any future session switch, instead of per-action clear calls.
  • File-mode images are mapped to webview URIs on render. The webview sandbox can't read $HERMES_HOME/attachments/ paths directly, so the host rewrites stored [Image pasted: …] references to asWebviewUri-mapped markdown images before posting messages.
  • Copy is webview-native. Copy buttons use navigator.clipboard with an execCommand fallback — copying a message, thinking block, code block or tool output never round-trips through the extension host.
  • Activity-bar icon: VS Code renders container icons as monochrome masks tinted by the theme, so the mark must read at 24px with real negative space. Note: the container icon is cached client-side keyed to the extension install path — any icon change requires a version bump to reach the running UI.

Requirements

  • VS Code ≥ 1.85 (same extension API works in Cursor/Windsurf)

  • Hermes with the gateway api_server platform enabled:

    .env:

    API_SERVER_ENABLED=true
    API_SERVER_KEY=<your-secret-key-min-8-chars>
    API_SERVER_HOST=127.0.0.1
    API_SERVER_PORT=8642
    

    then hermes gateway run (or hermes gateway install for a background service). Restart after config changes: hermes gateway run --replace.

Install

From GitHub Releases: download vsh-hermes-<version>.vsix from the latest release, then Extensions → Install from VSIX.

From the Marketplace (extension ID synapticity.vsh-hermes): search "VSHermes" in the Extensions view.

First launch: the API key is auto-discovered from the Hermes .env (see Requirements); only prompted for if none is found anywhere. Clients connecting to a remote server need that server's API_SERVER_KEY value — the same string from its .env — stored for the profile (Endpoints → Save key); remote connections without a key are refused.

Build & install from source (development)

npm install
npm run compile          # tsc + esbuild → dist/extension.js + dist/media/chat.js
npm test                 # unit + contract-mock tests (no gateway needed)
npm run test:live        # live integration against a real API server
                         # (key auto-read from $HERMES_HOME/.env)

Package and install into a remote/dev-container extension host (no F5 — there is no desktop GUI in this environment):

npx @vscode/vsce package          # dist/vsh-hermes-<version>.vsix
code --install-extension dist/vsh-hermes-<version>.vsix --force
# then: Command Palette → Developer: Reload Window

Settings: vsh.hermes.baseUrl (default http://127.0.0.1:8642), vsh.hermes.endpoints, vsh.hermes.activeEndpoint, vsh.hermes.checkSyncOnStartup, vsh.hermes.maxImageBytes, vsh.hermes.maxImageDimension, vsh.hermes.imageTransfer.

Compatibility verdicts

Verdict Meaning Action
ok every feature/endpoint VSHermes needs is present, version ≥ the minimum — (green)
ahead Hermes has extra capabilities VSHermes doesn't use — (green; extras are logged, not flagged)
untested version below the minimum but nothing missing — (green; note in the status-bar tooltip)
outdated a required feature/endpoint is missing upgrade Hermes to the minimum version
unknown server unreachable / bad key fix the connection

Green = the plugin works fully. Only outdated is a warning, and it says exactly what's missing and what to upgrade to — the report is about the server's capabilities, never "the plugin is incompatible".

Re-check anytime via the header icon, the VSHermes: Compatibility Check command, or npm run check-sync (standalone script).

Releasing

Each release is a version bump + CHANGELOG entry + tag + GitHub release, kept in sync by scripts/release.sh (run on a clean tree, after the version commit):

  1. Bump version in package.json, add the matching ## X.Y.Z (date) section to CHANGELOG.md, and update the "current build" line at the top of this README.
  2. Commit and push.
  3. ./scripts/release.sh — fetches origin first, rebases onto origin/main if the remote has drifted (aborting cleanly on conflict), rebuilds the vsix when the drift touched vsix inputs, then tags vX.Y.Z, pushes, creates the GitHub release with the CHANGELOG section as notes, and attaches dist/vsh-hermes-X.Y.Z.vsix. GitHub auth comes from the system git credential helper (no token stored in the repo).

Roadmap

  • Multiple chat panes (side-by-side sessions in editor tabs) — a WebviewPanel adapter over the existing chat surface (the webview is already a thin client; sessions are server-side durable and independent), with commands targeting the focused pane
  • Diff/checkpoint review for file changes (Hermes checkpoints integration)
  • AGENTS.md context injection per workspace
  • Runs/SSE activity feed for standalone /v1/runs submissions
  • Webview terminal output rendering for tool results

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft