Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hermes Console

A native Windows desktop client for a locally installed Hermes agent, with layout by Clay and an 80s-cyberpunk terminal aesthetic.

No Electron and no browser shell. One native executable talks to the locally installed Hermes Agent through its supported JSON-RPC gateway.


Build

Requires TDM-GCC (or any MinGW GCC) on PATH. There is nothing to fetch — Clay is vendored in vendor/.

build.bat

That produces HermesConsole.exe in the project root. It is a unity build: src/main.c includes everything, which keeps the GDI renderer's file-scope inline definitions linkable under GCC's C99 rules.

Run

HermesConsole.exe

The console finds your Hermes install automatically at %LOCALAPPDATA%\hermes\hermes-agent and launches its JSON-RPC gateway as a child process. Nothing needs to be running beforehand; quitting the console shuts the gateway down with it.

Environment

Variable Effect
HERMES_CWD Working directory for new sessions. Unset, terminal.cwd from Hermes's own config.yaml governs
HERMES_AGENT_DIR Point at a different hermes-agent folder
HERMES_NO_CRT=1 Disable the scanline overlay
HERMES_TRACE=1 Append every inbound gateway frame to %TEMP%\hermes-console-frames.log

Point the session cwd at real work, not at Hermes. Hermes injects the AGENTS.md chain from git root down to the session cwd into every single turn. Hermes's stock terminal.cwd: . resolves to its own source repo, whose AGENTS.md is 79 KB of contributor documentation. Measured on the same prompt:

Session cwd Input tokens/turn Time
Hermes's stock default (its own repo) 39,556 21.6s
A directory with no AGENTS.md 19,606 7.8s

Fix it once in %LOCALAPPDATA%\hermes\config.yaml under terminal.cwd and every Hermes client benefits. This console deliberately does not override that — it only sends a cwd when HERMES_CWD is set explicitly.

The gateway's own stderr is always captured to %TEMP%\hermes-console-gateway.log — check there first when something misbehaves.

Keys

Key Action
Enter Send
Shift+Enter New line
Esc Interrupt the running turn
Ctrl+N New session
Ctrl+L Clear the transcript view
Ctrl+V Paste
↑ ↓ PgUp PgDn Scroll the transcript
14 Answer a permission prompt
F1 Keyboard help
F12 Clay's layout debugger

Clarification requests open a blocking card with up to four choices and a free-form answer field. Sudo and secret requests use a masked volatile field: the value is sent only in the matching gateway response, never added to the transcript/activity log, and scrubbed on submit, cancel, replacement, or expiry.

Click a session in the sidebar to resume it, and click a REASONING block to unfold it. The transcript follows new output automatically and stops following the moment you scroll up — scroll back to the bottom to re-arm it.


Models and providers

The model picker is populated from the gateway's live model.options response and shows authenticated provider/model choices only. Opening the picker is read-only. Changing the configured model requires an explicit click and is committed only after the tracked config.set response succeeds; errors leave the prior selection active.

Hermes Console does not install providers, invent fallback models, or silently change routing policy. Provider credentials, retry policy, timeout policy, and fallback chains remain owned by Hermes itself. Adding or switching a model/provider should be an explicit user decision made after reviewing cost, privacy, speed, and reliability trade-offs.

How it connects

Hermes exposes a JSON-RPC gateway over stdio — the same dispatcher its own TUI and desktop clients use, so anything they can do is reachable from here.

HermesConsole.exe
  └── python -u -m tui_gateway.entry        (child process)
        stdin  ← newline-delimited JSON-RPC requests
        stdout → newline-delimited responses + events
        stderr → %TEMP%\hermes-console-gateway.log

A dedicated reader thread drains stdout and hands complete lines to the UI thread through a locked ring buffer, so the UI never blocks on the pipe.

Requests used: session.create, session.list, session.resume, session.interrupt, prompt.submit, approval.respond, model.options, config.get, config.set, clarify.respond, sudo.respond, secret.respond, agents.list, skills.manage, skills.reload, plugins.list, plugins.manage, cron.manage, and setup.status.

Events handled: gateway.ready, session.info, session.title, sessions.changed, message.start/delta/complete, reasoning.delta, reasoning.available, thinking.delta, tool.start/progress/generating/complete, approval.request, clarify.request/expire, sudo.request/expire, secret.request/expire, turn.error, turn.end, plus subagent lifecycle events.

Verification

Run the non-destructive release gates from the project root:

python verify_release.py

This runs static/runtime contract tests, the read-only gateway smoke test, secure interactive-prompt tests, and the canonical native build. It stops only a running HermesConsole.exe before linking; it never broadly terminates Python/Hermes processes and never changes the selected model/provider. --full additionally runs RED-first contracts for parity work that is not complete yet.

The authoritative implementation/verification status for every gateway surface is maintained in docs/FEATURE_PARITY.md. A rendered control is not counted as complete until its real gateway contract has been exercised.

Layout

src/
  main.c      WinMain, window, fonts, input, CRT overlay
  ui.h        the whole interface, declared with Clay
  app.h       application state + Hermes protocol handling
  gateway.h   child process, pipes, reader thread
  json.h      dependency-free JSON parser and writer
  theme.h     palette, metrics, font slots
vendor/
  clay.h                  Clay 0.14, unmodified
  clay_renderer_gdi.c     Clay's Win32 GDI renderer, patched (see below)

Changes to the vendored renderer

Three deliberate edits, each marked [hermes] in the source:

  1. UTF-8 text. Upstream draws with DrawTextA and measures with GetTextExtentPoint32, which reinterpret Clay's UTF-8 bytes in the system codepage and mangle anything non-ASCII the agent emits. Both now convert to UTF-16 and use the wide APIs.
  2. DC leak. The measurement path returned early without releasing the screen DC, leaking one per call. Now released on every path.
  3. Post-render hook. A nullable callback fires just before the final BitBlt, which is where the scanline pass composites.

Notes

The CRT overlay composites a full-size premultiplied DIB at 1:1. An earlier version stored a single-pixel-wide column and let AlphaBlend stretch it — far cheaper, but GDI does not blend a stretched per-pixel-alpha source faithfully and it crushed every colour to roughly a sixth of its value. Blitting at 1:1 is the only reliable form.

License

Hermes Console is released under the MIT License.

The vendored Clay 0.14 layout library uses the zlib/libpng license, not MIT. Its complete license is preserved in vendor/CLAY-LICENSE.md, and bundled components and local modifications are summarized in THIRD_PARTY_NOTICES.md.

About

Native Win32 desktop console for Hermes Agent, built in C with Clay and an 80s green-phosphor CRT interface.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages