Hermes Agent for VS CodeA native VS Code interface for the Hermes Agent CLI
(Nous Research). It does not reimplement the agent: it speaks ACP (JSON-RPC over stdio) to
Status: milestones M1–M8 done (ACP connection, streaming chat, reasoning, tool calls, native
diff, approvals, pickers, context meter, chips, parallel sessions, prompt queue, Manage panel, plan,
working set and the CLI escape hatches). M9 (visual pass across the 4 themes, keyboard/screen reader
and Remote) is partial — see MIT licensed · 4 languages (en, pt-BR, ru, zh-CN) · no hardcoded colors.
Requirements
Installation
Then open the folder in VS Code and press F5 (Extension Development Host), or package it:
Usage
Commands
The Command Palette holds the full list — the table above is the day-to-day subset. Settings (
|
| Key | Default | What it is for |
|---|---|---|
hermes.cliPath |
hermes |
executable; accepts an environment prefix (wsl hermes) |
hermes.agents |
{"Hermes": {"command":"hermes","args":["acp"]}} |
agents: command, args, profile, cwd, env, model |
hermes.defaultAgent |
Hermes |
agent selected when the view opens |
hermes.defaultWorkingDirectory |
empty | session cwd; empty = workspace folder |
hermes.skipConfiguredMcp |
true |
exports HERMES_ACP_SKIP_CONFIGURED_MCP=1 (keeps global MCP servers from slowing initialize down) |
hermes.permissions |
ask |
default policy for approval responses |
hermes.showReasoning |
collapsed |
always | collapsed | hidden |
hermes.queue.enabled |
true |
composer prompt queue |
hermes.queue.defaultAction |
queue |
send action during an active turn: queue | steer |
hermes.context.warnAt |
80 |
warn when context usage passes this percentage |
hermes.worktreeRoot |
empty | where Hermes: New Worktree and Session creates git worktrees; empty = sibling <repo>-worktrees |
hermes.notifications |
windowNotFocused |
when to notify about background session events |
hermes.logTraffic |
false |
raw JSON-RPC in the Hermes Traffic channel (secrets redacted) |
Icon
The Hermes art is one file, media/hermes-agent-for-vscode.svg, used on both themes:
- Activity Bar: the manifest points at it in
contributes.viewsContainers.activitybar[0].icon. The VS Code schema requiresiconto be a string (the{light, dark}pair is not accepted: the whole container is dropped and its views fall back toExplorer). VS Code also does not recolor view container icons — the color comes from the file, so a single color has to work on both backgrounds. - Marketplace:
media/icon.png, 128×128 RGBA with a transparent background, exported frommedia/icon-source.svg.vscerefuses to publish an SVGicon("the icon provided inpackage.jsonmay not be an SVG"), hence the PNG — the SVG is still valid for the Activity Bar, which is manifest-driven.
Measured contrast (WCAG for non-text elements, 3:1 minimum):
| File | Color | Where | Contrast |
|---|---|---|---|
hermes-agent-for-vscode.svg |
#2B8AD9 |
Activity Bar, light and dark themes | 3.66:1 on white · 3.45:1 on #333 · 4.51:1 on #1F1F1F |
icon.png (icon-source.svg) |
#1E88E5 |
marketplace card, both themes | 3.68:1 light · 3.43:1 dark |
The original pair of blues (#007ACC for light, #3B9EFF for dark) does not survive the schema: one
color has to serve both backgrounds, and #007ACC measured 2.80:1 on the #333 Activity Bar.
Hence #2B8AD9, same family, above 3:1 on both — and 4.5:1 on the darkest background, since the bar
draws the inactive item at reduced opacity.
Honest note on size: the art carries fine detail, and at the Activity Bar's real size (16–24px) the
inner strokes land around 0.2px and it reads as a silhouette. That is a legitimate brand choice; if
you want more definition there, the agent glyph from @vscode/codicons is the immediate
alternative.
To regenerate the PNG: export media/icon-source.svg at 128×128, RGBA, transparent background.
vsce refuses SVG and requires a PNG in icon.
Publishing to the Marketplace
npx vsce package # produces the .vsix (no warnings)
npx vsce publish # needs a publisher + PAT (or Entra ID)
What still depends on you:
publisher— currentlyDanil0ws; it must match your Marketplace publisher id exactly.- Token — an Azure DevOps PAT with the Marketplace → Manage scope, or Entra ID authentication
(
vsce publish --azure-credential). Global Azure DevOps PATs are retired on 2026-12-01, so Entra ID is Microsoft's own recommendation.
repository is already in the manifest (github.com/Danil0ws/hermes-agent-for-vscode), and it is what
lets vsce resolve the local art in this README: with the field present, vsce package rewrites the
image to the absolute GitHub URL and passes; without it, packaging fails (not a warning). The
store icon comes from package.json > icon (media/icon.png) and is independent of that.
Checked: hermes-agent.hermes-agent-for-vscode is still free on the Marketplace (name and display
name have to be unique; if it were taken, publishing would fail with "already exists").
Auto-approve (YOLO)
By default Hermes asks before running commands and editing files. The policy lives in
hermes.permissions and takes three values: ask (default), allowSession (repeats, for this
session, what you already approved once) and allowAll (never asks).
// settings.json — same as the palette command
{ "hermes.permissions": "allowAll" }
The extension answers with the options the agent offered — it never invents a permission — and
never picks a deny option. While YOLO is on, an item sits in the status bar (Hermes: approving everything, warning background) and clicking it turns it off. A restricted workspace (Workspace
Trust) still wins: nothing runs.
Languages
Every user-visible string in the extension host goes through tr() and the three dictionaries
(src/l10n.en.ts, src/l10n.ru.ts, src/l10n.zh-cn.ts) must cover every key — a test fails on a
pt-BR literal left outside tr() and another checks the key parity, so a new string cannot ship
untranslated by accident.
The extension language follows the VS Code display language (there is no picker of its own):
change it in Ctrl+Shift+P → Configure Display Language and reload the window.
| Language | Manifest / Command Palette | Webview UI | Host (notices, pickers, status bar) |
|---|---|---|---|
English (en) |
default | ✅ | ✅ |
Português (pt-BR) |
✅ | ✅ (source language) | ✅ (source language) |
Русский (ru) |
✅ | ✅ | ✅ |
简体中文 (zh-CN) |
✅ | ✅ | ✅ |
How it works: the manifest uses package.nls.*.json (VS Code's native mechanism, one entry per
command/setting string) and the runtime uses two dictionaries — webview/*/i18n.<locale>.ts (typed
by Strings, so the compiler enforces key parity) and src/l10n.<locale>.ts (a pt-BR text →
translation map).
pt-BR is the source language: it holds the original strings, and a string with no translation
falls back to it instead of showing a raw key. This is not vscode.l10n plus a language pack: the
language comes from vscode.env.language, which reflects the installed language packs without
shipping bundle.l10n.*.json files (docs/ARCHITECTURE.md §11.18 explains the choice).
Contributing
See CONTRIBUTING.md (environment, mandatory gates, one-screen architecture, the parallel-lanes
pattern and the documentation rules). MIT licensed — see LICENSE.
Development
npm run compile # tsc --noEmit (the type gate)
npm run build # everything
npm test # unit + integration; the integration ones spawn the real `hermes acp`
npm run watch # esbuild in watch mode (extension host)
The integration tests use the real Hermes and are skipped when hermes is not on the PATH —
they never pretend to pass. Test and command counts are deliberately absent here: they drift, and
npm test counts itself.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| "The connection to Hermes dropped" | hermes exited (PATH, credentials, WSL) |
hermes acp --check, hermes doctor; check the Hermes channel |
| No models in the list | provider without credentials in Hermes | hermes model (or the "Run CLI Command…" menu) |
| Mode/model picker empty | the agent announced no modes and no catalog | in this build the Start button creates the session; without a session there is nothing to announce |
| Windows | Hermes does not run natively | use WSL2 with hermes.cliPath = "wsl hermes" |
npm install installs nothing |
NODE_ENV=production in the shell skips devDeps |
export NODE_ENV=development |
Cannot find module .../dist/extension.js |
dist/ was empty: the build starts by cleaning, so a failed (or interrupted) build leaves nothing behind |
run npm run build; on F5 the preLaunchTask builds first. The typecheck runs before clean, so a type error no longer wipes dist/ |
| The UI is in a language I do not want | the language follows VS Code | Configure Display Language → pick one → reload the window |
| A string has no translation | a new string without a dictionary entry | it falls back to pt-BR on purpose; add the entry in src/l10n.<locale>.ts or webview/*/i18n.<locale>.ts |
command 'hermes.x' not found |
a command declared in the manifest that nobody registered (usually a duplicate registration throwing and being swallowed) | the Hermes channel logs comandos: N/M registrados on activation; npm test enforces the manifest invariant |
| The extension cannot find Hermes | wrong hermes.cliPath, CLI off the PATH, or a WSL install |
Hermes: Check / install Hermes; on Windows the value must be wsl hermes — the first token is the executable |
| YOLO is on and you forgot | hermes.permissions = allowAll |
the Hermes: approving everything status bar item; click to turn it off |
Documentation
docs/ARCHITECTURE.md— transport, capability→UI map, turn flow, security, milestones and the verified gaps (modes, queue, skills, MCP, effort, cost, checkpoints). (pt-BR)docs/ROADMAP.md— what to do about each verified gap: ordered by value over cost, with the proof that closes it, who owns it (this repo × a human at the editor × upstream) and the items deliberately left undone, with the reason. (pt-BR)docs/UX.md— wireframes for the composer, pickers, context meter, Manage panel and sessions, each element mapped to its data source, plus the degraded states. (pt-BR)