hermes - ✅(Solved) Fix TUI v2 feature-parity audit vs v1 CLI: missing overlays, slash commands, @ refs, and curses-command degradation [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#12130Fetched 2026-04-19 15:25:37
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Author
Timeline (top)
mentioned ×2subscribed ×2commented ×1cross-referenced ×1

The --tui v2 Ink TUI is missing ~23 of v1's 48 slash commands locally, has zero @file: / @diff / @staged / @git:N / @url: context references, no quick_commands shortcuts, no Skills Hub / Tools Config / Cron / Rollback / Snapshot / Plugins / Insights / Agents / Browser / Platforms overlays (even though backend RPCs exist for most), no MCP status on boot, no Ctrl+Z suspend, and degrades-or-breaks for any v1 command that relies on curses (e.g. /skills browse). A handful of items are also unreachable due to a registry collision on /model. Tagging @OutThisLife since you're the primary TUI v2 contributor.

This issue is a feature-parity audit — not a bug report. v2 has legitimately better UX in several places (virtual history, mouse support, Ctrl+G editor handoff, subagent accordion, sticky prompt tracker, queue-edit mode, face/verb ticker) and we don't want to lose any of that. The goal is a punch-list of what a v1 user would notice going missing when they type --tui, plus a few things v2 does that v1 users may not realize.

Methodology: audited cli.py + hermes_cli/ (v1) and ui-tui/src/ + tui_gateway/server.py (v2) end-to-end. Cross-referenced 56 backend RPCs against frontend call sites.


Error Message

13. Error handling

  • v1 distinguishes tool failure suffixes: [exit N], [error], [full] (memory). v2's tool tree marks errors but the distinction between exit-code vs exception vs context-overflow may be lost.

Root Cause

The --tui v2 Ink TUI is missing ~23 of v1's 48 slash commands locally, has zero @file: / @diff / @staged / @git:N / @url: context references, no quick_commands shortcuts, no Skills Hub / Tools Config / Cron / Rollback / Snapshot / Plugins / Insights / Agents / Browser / Platforms overlays (even though backend RPCs exist for most), no MCP status on boot, no Ctrl+Z suspend, and degrades-or-breaks for any v1 command that relies on curses (e.g. /skills browse). A handful of items are also unreachable due to a registry collision on /model. Tagging @OutThisLife since you're the primary TUI v2 contributor.

This issue is a feature-parity audit — not a bug report. v2 has legitimately better UX in several places (virtual history, mouse support, Ctrl+G editor handoff, subagent accordion, sticky prompt tracker, queue-edit mode, face/verb ticker) and we don't want to lose any of that. The goal is a punch-list of what a v1 user would notice going missing when they type --tui, plus a few things v2 does that v1 users may not realize.

Methodology: audited cli.py + hermes_cli/ (v1) and ui-tui/src/ + tui_gateway/server.py (v2) end-to-end. Cross-referenced 56 backend RPCs against frontend call sites.


Fix Action

Fix / Workaround

v1 has 48 canonical CommandDef entries in hermes_cli/commands.py. v2 registers 25 locally in ui-tui/src/app/slash/. Everything else falls through to slash.exec (captures Rich stdout as plain text) or command.dispatch (typed payloads).

  • Banner: v1 shows Available Tools grouped by toolset, Available Skills grouped by category, per-MCP-server connection status (transport + tool count or failed). v2 shows tools + skills but no MCP server boot status. MCP errors surface only via stderr events into the activity trail, which is easy to miss.

  • Profile row (non-default profile): v1 highlights it in the banner. v2 doesn't surface it anywhere.

  • Response Box: v1 wraps assistant output in a skin-styled border ╭─⚕ Hermes─────────╮ … ╰────╯. v2 renders messages inline with no box delimiter. Subjective, but several users identify Hermes by this chrome.

  • Tips-of-the-day: v1 rotates through ~100 hand-written tips in hermes_cli/tips.py (slash commands, keybindings, @ refs, CLI flags). v2 has fortunes.ts — short zen-style strings, different tone, doesn't teach features.

  • Markdown: v2's markdown.tsx covers CommonMark + GFM tables + task lists, but per-language syntax highlighting is missing (only diff gets colored). v1 gets full Rich syntax highlighting on non-streaming renders. Code-heavy transcripts look better in v1.

  • Inline diffs: v1 renders write_file/patch/skill_manage diffs with skin-adapted colors, 6-file / 80-line caps. v2 wires inline_diff through tool.complete — parity, good.

  • Reasoning box: v1 has a dedicated dim bordered box for streaming reasoning, deferred final content until it closes. v2's Thinking component covers this — parity.

  • Status bar: v2 is actually richer — face/verb ticker, voice label, bg task count, ctx bar color thresholds, duration. v1 has 3 adaptive widths but less content. Keep this.

  • Virtual-windowed history (v1 can't do this under prompt_toolkit at all).

  • Mouse support — wheel, click-to-position in composer, scrollbar drag, chevron toggle.

  • Ctrl+G → $EDITOR with alt-screen handoff.

  • Sticky prompt tracker (↳ <previous user message> chip when scrolled back).

  • Queue-edit mode (↑/↓ to navigate queued messages, Ctrl+K to dispatch head).

  • Subagent accordion tree with Shift+click expand-all.

  • Face + verb ticker every 2.5s in the status line.

  • GoodVibes heart on "thanks" / "good bot" — small but charming.

  • Live skin hot-swap via skin.changed without restart.

  • Config mtime polling → auto MCP reload (v1 also has this now, but TUI's behavior is cleaner).

  • Bracketed-paste tokenization [[paste:label]] for large pastes — reads better than v1's file-path placeholder inline.

  • Typed command.dispatch payloads (alias / skill / exec / plugin) — cleaner than v1's subprocess stdout scraping.

PR fix notes

PR #12263: fix(tui): TUI v2 audit follow-up — registry, overlays, paste, reasoning, hyperlinks

Description (problem / solution / changelog)

What does this PR do?

Follow-up to #12130 (TUI v2 feature-parity audit). Closes Tier-1 items and a handful of real bugs surfaced during testing against the consolidated branch.

The audit framed some items as missing in v2 that actually work server-side — those are scoped-down in commits / release notes rather than re-implemented. Actual gaps are shipped as fix(tui) / feat(tui) commits.

Related Issue

Related to #12130

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

Fixes (real bugs found during testing)

  • fix(tui): split /model picker from /provider wizard to resolve registry collisionsetup.ts's name: 'model' shadowed session.ts's picker handler because the registry is a Map (last-wins). /model never opened the picker. Split into /model (picker + direct switch) and /provider (external setup wizard).
  • fix(tui): route /skills subcommands through skills.manage instead of curses slash.exec/skills install, /skills inspect, /skills search, /skills browse, /skills list fell through to slash.exec which invokes v1's curses code path and hangs inside the Ink worker. Now call the typed skills.manage RPC and render via transcript.panel / transcript.page. Audit §2.
  • fix(tui): cap approval prompt command preview at 10 lines — giant inline scripts (Python code_execution bodies) pushed Allow/Deny options off the viewport. Preview is capped with wrap="truncate-end" per line + dim … +N more lines indicator. Full text remains in transcript above.
  • fix(tui): wrap markdown links in Link so Ghostty/iTerm/kitty get real OSC 8 hyperlinksrenderLink dropped the href entirely, making Cmd+Click inert in every terminal (Ghostty's URL auto-detect only saw bare-URL text, which Alt+Click workaround-ed the easier half). Links now emit OSC 8 via @hermes/ink's Link component.
  • fix(tui): Ctrl+C on in-input selection copies to clipboard instead of clearingtextInput explicitly ignored Ctrl+C, so the app-level handler ran clearIn() whenever input had text, obliterating what you typed. Now copies the selection via OSC 52 and clears the selection only.
  • fix(tui): strip <think>…</think> tags from assistant content and route to reasoning panel — models that emit inline <think>/<reasoning>/<thinking>/<thought>/<REASONING_SCRATCHPAD> tags were showing the tags in the body AND the same content dimmed in the thinking panel. Ported v1's tag set to lib/reasoning.ts and applied in scheduleStreaming, flushStreamingSegment, and recordMessageComplete.

Feature-parity (audit items)

  • fix(tui): split /model picker from /provider wizard to resolve registry collision — audit §7.
  • feat(tui): accept raw Ctrl+V as clipboard image paste fallback — audit §6. \x16 now triggers the same hotkey-paste path as Alt+V.
  • feat(tui-gateway): surface config.quick_commands in commands.catalog — audit §4. Execution was already live via command.dispatch; catalog now surfaces them under a "User commands" bucket with auto-generated exec: <cmd> / alias → <target> descriptions (explicit description wins).
  • feat(tui): persist large pastes to ~/.hermes/pastes/ via paste.collapse — audit §5. handleTextPaste fires paste.collapse alongside the in-memory [[paste:label]] token so v1's grep-after-exit workflow works. Client-side token format kept.
  • feat(tui): read display.streaming / show_reasoning / show_cost / inline_diffs from config + feat(tui): honor display.* flags in turn renderer, status bar, and event handler — audit §10. useConfigSync.applyDisplay reads the four flags; turnController gates streaming / reasoning, createGatewayEventHandler gates inline_diff rendering, StatusRule renders $X.XXXX when show_cost is on.
  • feat(tui-gateway): include per-MCP-server status in session.info payload + feat(tui): render per-MCP-server status block in SessionPanel — audit §8 / §11. Server adds mcp_servers: [{name, transport, tools, connected}] via tools.mcp_tool.get_mcp_status; banner renders a new block after Skills with per-server rows and a failed label for disconnected servers. Footer summary shows · N MCP.
  • feat(tui): add skillsHub overlay state wiring + feat(tui): add two-step SkillsHub overlay component + feat(tui): register /skills slash command to open Skills Hub — audit §2 / §9. Bare /skills opens a two-step modal mirroring ModelPicker (category → skill → actions). Inspect on entry; i re-inspects, x reinstalls. Enter/Esc back.
  • feat(tui): per-language syntax highlighting in markdown code fences — audit §8. Hand-rolled minimal highlighter in lib/syntax.ts for ts/js/jsx/tsx, py/python, sh/bash/shell/zsh, go, rust/rs, json, yaml/yml, sql. No library dependency; unknown langs fall through to plain render; existing diff colorization preserved.

Tests

  • test(tui-gateway): assert quick_commands appear in commands.catalog output
  • test(tui-gateway): cover mcp_servers field in _session_info output
  • New vitest coverage: syntax.test.ts, reasoning.test.ts, useConfigSync.test.ts, and expanded createSlashHandler.test.ts.

Not in this PR (audit items scoped out)

  • @file: / @diff / @staged / @git:N / @url: / @folder: — already expand server-side via prompt.submitagent.context_references.preprocess_context_references. Audit §3's "zero references" conclusion was a frontend-only grep; feature works end-to-end. No code change needed.
  • Overlays for /rollback, /cron, /plugins, /agents, /insights, /browser, /snapshot, Tools Config multi-select — audit §9 backlog. Left for follow-up PRs.
  • Response Box chrome around assistant messages — audit §8 subjective call; v2's clean inline design is intentional.
  • Ctrl+Z suspend-to-shell — audit §5. textInput already binds Ctrl+Z to undo; reframed as "no SIGTSTP" rather than re-mapped.

How to Test

Automated

# TS
cd ui-tui && npm run fix && npm run type-check && npm run test
# 73 tests pass

# Python
.venv/bin/pytest tests/test_tui_gateway_server.py -q
# 27 tests pass

Manual

  1. hermes --tui from a fresh terminal.
  2. /model picker: type /model with no args → two-step picker opens. Type /provider → external wizard.
  3. Skills Hub: type /skills → category → skill → actions overlay; /skills inspect <name> renders a panel instead of crashing; /skills browse 1 renders a paginated panel.
  4. Ctrl+V fallback: copy an image; Ctrl+V inside composer attaches it (same behavior as Alt+V).
  5. quick_commands: add
    quick_commands:
      gs:
        type: exec
        command: git status
    to ~/.hermes/config.yaml, restart TUI, type /gs → autocomplete shows it under "User commands".
  6. Paste-to-file: paste a 10+ line block into the composer; check ls -t ~/.hermes/pastes/ — new file appears.
  7. MCP banner: if you have MCP servers configured, boot shows MCP Servers block with name [transport]: N tools rows.
  8. Syntax highlighting: ask the model a question that returns ts/py/sh code fences; keywords render bronze, strings amber, numbers cornsilk, comments dim.
  9. display.show_cost: set display: { show_cost: true } in config → status bar shows · $X.XXXX.
  10. Approval prompt cap: ask the model to run a ≥50-line Python script; approval box shows 10-line preview + … +N more lines; Allow/Deny rows always visible.
  11. Ctrl+C on selection: type text, shift+arrow-select part of it, Ctrl+C → selection copies to clipboard, input stays.
  12. OSC 8 hyperlinks: ask for a response with a markdown link; Cmd+Click (or Ctrl+Click on WSL) in Ghostty opens the URL.
  13. <think> stripping: ask deepseek-r1 / qwen3-thinking / similar → inline <think>…</think> content goes to thinking panel, not body.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(tui):, feat(tui-gateway):, test(tui-gateway):)
  • I searched for existing PRs to make sure this isn't a duplicate (overlaps with #12141's /plan + skill dispatch fixes, which are complementary and merge cleanly)
  • My PR contains only changes related to the audit follow-up
  • I've run npm run test (TS) and pytest tests/test_tui_gateway_server.py — both pass
  • I've added tests for my changes
  • I've tested on: Ubuntu / WSL2 + Ghostty

Documentation & Housekeeping

  • I've updated relevant documentation — N/A (no user-facing config schema change; display.* flags already documented in cli-config.yaml.example)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact — paste.collapse uses ~/.hermes/pastes/ via _hermes_home (profile-safe); Ctrl+V raw byte \x16 is universal; OSC 8 / OSC 52 gated on terminal detection via supports-hyperlinks + env fallbacks
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Before / After: /skills subcommands

Before (slash.exec → curses hang):

/skills browse
(hangs, no output)

After:

/skills browse
(paginated panel opens with remote skills list)

Before / After: approval prompt with huge Python body

Before: ~200 lines of code fill the viewport, Allow/Deny rows below are off-screen.

After:

⚠ approval required · execute python code
 line_0 = …
 line_1 = …
  … (through line 9)
 … +50 more lines (full text above)

▸ 1. Allow once
  2. Allow this session
  3. Always allow
  4. Deny
↑/↓ select · Enter confirm · 1-4 quick pick · Ctrl+C deny

MCP banner

Available Tools
  browser: browser_back, browser_click, …

Available Skills
  creative: architecture-diagram, ascii-art, …

MCP Servers
  github [http]: 14 tools
  filesystem [stdio]: 4 tools
  broken [stdio]: failed

31 tools · 98 skills · 3 MCP · /help for commands

Diffstat

30 files changed, +1118 / −36. No modifications outside ui-tui/, tui_gateway/, tests/test_tui_gateway_server.py.

Changed files

  • tests/test_tui_gateway_server.py (modified, +37/-0)
  • tui_gateway/server.py (modified, +33/-1)
  • ui-tui/src/__tests__/createGatewayEventHandler.test.ts (modified, +2/-1)
  • ui-tui/src/__tests__/createSlashHandler.test.ts (modified, +58/-0)
  • ui-tui/src/__tests__/reasoning.test.ts (added, +50/-0)
  • ui-tui/src/__tests__/syntax.test.ts (added, +45/-0)
  • ui-tui/src/__tests__/useConfigSync.test.ts (added, +67/-0)
  • ui-tui/src/app/createGatewayEventHandler.ts (modified, +1/-1)
  • ui-tui/src/app/inputSelectionStore.ts (added, +14/-0)
  • ui-tui/src/app/interfaces.ts (modified, +6/-0)
  • ui-tui/src/app/overlayStore.ts (modified, +5/-2)
  • ui-tui/src/app/slash/commands/core.ts (modified, +24/-11)
  • ui-tui/src/app/slash/commands/ops.ts (modified, +202/-0)
  • ui-tui/src/app/slash/commands/setup.ts (modified, +2/-3)
  • ui-tui/src/app/turnController.ts (modified, +40/-10)
  • ui-tui/src/app/uiStore.ts (modified, +4/-0)
  • ui-tui/src/app/useComposerState.ts (modified, +14/-1)
  • ui-tui/src/app/useConfigSync.ts (modified, +6/-2)
  • ui-tui/src/app/useInputHandlers.ts (modified, +16/-0)
  • ui-tui/src/components/appChrome.tsx (modified, +5/-0)
  • ui-tui/src/components/appLayout.tsx (modified, +1/-0)
  • ui-tui/src/components/appOverlays.tsx (modified, +8/-1)
  • ui-tui/src/components/branding.tsx (modified, +25/-0)
  • ui-tui/src/components/markdown.tsx (modified, +29/-7)
  • ui-tui/src/components/messageLine.tsx (modified, +3/-1)
  • ui-tui/src/components/prompts.tsx (modified, +19/-1)
  • ui-tui/src/components/skillsHub.tsx (added, +296/-0)
  • ui-tui/src/components/textInput.tsx (modified, +25/-1)
  • ui-tui/src/gatewayTypes.ts (modified, +4/-0)
  • ui-tui/src/lib/reasoning.ts (added, +50/-0)
  • ui-tui/src/lib/syntax.ts (added, +117/-0)
  • ui-tui/src/types.ts (modified, +9/-0)
  • ui-tui/src/types/hermes-ink.d.ts (modified, +5/-1)
RAW_BUFFERClick to expand / collapse

Summary

The --tui v2 Ink TUI is missing ~23 of v1's 48 slash commands locally, has zero @file: / @diff / @staged / @git:N / @url: context references, no quick_commands shortcuts, no Skills Hub / Tools Config / Cron / Rollback / Snapshot / Plugins / Insights / Agents / Browser / Platforms overlays (even though backend RPCs exist for most), no MCP status on boot, no Ctrl+Z suspend, and degrades-or-breaks for any v1 command that relies on curses (e.g. /skills browse). A handful of items are also unreachable due to a registry collision on /model. Tagging @OutThisLife since you're the primary TUI v2 contributor.

This issue is a feature-parity audit — not a bug report. v2 has legitimately better UX in several places (virtual history, mouse support, Ctrl+G editor handoff, subagent accordion, sticky prompt tracker, queue-edit mode, face/verb ticker) and we don't want to lose any of that. The goal is a punch-list of what a v1 user would notice going missing when they type --tui, plus a few things v2 does that v1 users may not realize.

Methodology: audited cli.py + hermes_cli/ (v1) and ui-tui/src/ + tui_gateway/server.py (v2) end-to-end. Cross-referenced 56 backend RPCs against frontend call sites.


1. Slash commands — local registry gap

v1 has 48 canonical CommandDef entries in hermes_cli/commands.py. v2 registers 25 locally in ui-tui/src/app/slash/. Everything else falls through to slash.exec (captures Rich stdout as plain text) or command.dispatch (typed payloads).

Missing from v2 local registry (either degraded via slash.exec, or genuinely non-functional):

Commandv1 behaviorv2 status
/historyRich-rendered conversationfalls through → pager text
/saveMarkdown export w/ path confirmationfalls through
/title [name]Set session title (persists via SessionDB)falls through
/statusSession info panelfalls through
/configFull config dumpfalls through
/providerProviders + current providercollides with /model setup handler (see §7)
/profileActive profile + home dirfalls through
/platforms / /gatewayMessaging platform status tablefalls through
/agents / /tasksActive subagents + running tasksagents.list RPC exists, no UI
/insights [days]Usage analyticsinsights.get RPC exists, no UI
/pluginsInstalled pluginsplugins.list RPC exists, no UI
/tools (list)hermes tools curses picker, inline listtext-only via /tools enable/disable
/toolsetsToolset listingtoolsets.list RPC exists, no UI
/skillsCurses browse/inspect/installskills.manage RPC exists, no UI — curses fallback breaks in Ink
/cronlist/add/edit/pause/resume/run/removecron.manage RPC exists, no UI
/rollbacklist/diff/restore/N <file>rollback.list/.restore/.diff RPCs exist, no UI
/snapshot / /snapHermes config/state create/restore/pruneno backend, no UI
/browserCDP connect/disconnect/statusbrowser.manage RPC exists, no UI
/reloadReload .envfalls through
/reload-mcpHot-reload MCP serversauto-reloads on mtime change (different model)
/stopKill all background processesfalls through
/debugUpload debug bundle, share linksfalls through
/gquotaGoogle Gemini quotafalls through
/updateUpdate in-placegateway_only — banner shows "N commits behind" but no command
/fastPriority processing togglefalls through
/planLaunch bundled planning skillfalls through

22 server RPCs are orphaned — wired on the Python side but never called by the frontend. That's your largest latent UI backlog: skills.manage, rollback.*, cron.manage, plugins.list, agents.list, tools.list/.show, toolsets.list, insights.get, browser.manage, session.title, session.history, session.save, voice.tts, process.stop, cli.exec, command.resolve, paste.collapse, config.show.

2. Curses commands break under slash.exec

tui_gateway/slash_worker.py runs a persistent HermesCLI with sys.stdout / sys.stderr redirected to a StringIO and the Rich console reconstructed over the same buffer. That works for text output. It doesn't work for:

  • /skills browse and /skills inspect — use curses which needs a real TTY. Will hang or crash silently.
  • Any v1 path that calls prompt_toolkit.application.run_in_terminal() — no terminal to hand off to inside the worker.
  • /tools interactive picker (invoked via hermes tools externally by v1, not the slash command) — same curses constraint.

The clean fix is native Ink overlays for skills hub + tools config. The orphaned skills.manage and tools.configure RPCs already give you the data endpoints.

3. @ context references — completely missing

v1 expands these inline at send time before the message hits the model (see cli.py:7849):

  • @file:path[:lines] — inline a file slice
  • @folder:path — inline a recursive listing
  • @diff / @staged — git diff snapshots
  • @git:N — last N commits
  • @url:... — fetched URL content

v2 has zero references to any of these tokens anywhere under ui-tui/src/. For Claude Code / Cursor users this is an expected baseline. Two implementation paths:

  • Client-side expansion in useSubmission before prompt.submit (preserves v1 semantics, works offline).
  • Server-side via a new prompt.expand_refs RPC called before prompt.submit.

4. quick_commands — missing

v1 reads config.quick_commands (user-defined exec shell shortcuts that bypass the LLM entirely) and registers them as completable slash commands. v2 has zero hits on quick_commands. Useful for users who've set up /build, /deploy, etc.

5. Keybindings

Keyv1v2
Ctrl+ZSuspend (Unix), shell prints "run fg to bring Hermes Agent back"Not handled
Ctrl+Gv2-only: opens $EDITOR with buffer, submits on save
Ctrl+KDelete-to-end-of-lineDequeue next queued message (different mapping — may surprise v1 users)
Ctrl+BVoice record toggleSame — OK
Alt+VClipboard image pasteSame — OK
Ctrl+VFallback clipboard image (Linux terms w/o bracketed paste)Not handled
Shift+TabNot distinct from Tab in v1Not handled in v2
BracketedPaste 5+ linesSaves to ~/.hermes/pastes/paste_N_HHMMSS.txt + [Pasted text #N: L lines → path] placeholderCollapses to [[paste:label]] in-memory only (no file)
MouseNonev2-only: wheel scroll, click-to-position, scrollbar drag

The paste-to-file behavior is a real feature difference, not just a reformat — v1 users often grep the paste files later. v2's in-memory snippet vanishes on exit.

6. Attachments

  • v1 /image <path>, /paste, Alt+V, Ctrl+V, bracketed-paste-auto-image — five entry points. v2 has /image, /paste, Alt+V, bracketed-paste — Ctrl+V missing.
  • v1 attaches are staged in _attached_images with persistent [📎 Image #1] badges above input until sent. v2 uses a one-shot image.attach with "attached image: X · Yk tokens" activity line — no persistent badge showing pending attachments.
  • v1 Ctrl+C when idle clears staged attachments. v2 has no staging to clear.

7. /model registry collision (bug)

ui-tui/src/app/slash/commands/session.ts registers name: 'model' (picker overlay handler). ui-tui/src/app/slash/commands/setup.ts registers name: 'model' (external hermes model spawn via withInkSuspended).

Registry construction is a Map so last-registered wins. setup.ts is registered after session.ts, so the picker path in session.ts is dead code/model always goes through the external setup wizard with Ink suspended. The ModelPicker overlay component exists and is wired but only reachable from non-slash code paths.

Probably intended: bare /model → picker overlay, /model [spec] → switch directly, /provider → setup wizard. Currently all of these route through the setup path.

8. Display / rendering

Parity on most things but a few gaps:

  • Banner: v1 shows Available Tools grouped by toolset, Available Skills grouped by category, per-MCP-server connection status (transport + tool count or failed). v2 shows tools + skills but no MCP server boot status. MCP errors surface only via stderr events into the activity trail, which is easy to miss.
  • Profile row (non-default profile): v1 highlights it in the banner. v2 doesn't surface it anywhere.
  • Response Box: v1 wraps assistant output in a skin-styled border ╭─⚕ Hermes─────────╮ … ╰────╯. v2 renders messages inline with no box delimiter. Subjective, but several users identify Hermes by this chrome.
  • Tips-of-the-day: v1 rotates through ~100 hand-written tips in hermes_cli/tips.py (slash commands, keybindings, @ refs, CLI flags). v2 has fortunes.ts — short zen-style strings, different tone, doesn't teach features.
  • Markdown: v2's markdown.tsx covers CommonMark + GFM tables + task lists, but per-language syntax highlighting is missing (only diff gets colored). v1 gets full Rich syntax highlighting on non-streaming renders. Code-heavy transcripts look better in v1.
  • Inline diffs: v1 renders write_file/patch/skill_manage diffs with skin-adapted colors, 6-file / 80-line caps. v2 wires inline_diff through tool.complete — parity, good.
  • Reasoning box: v1 has a dedicated dim bordered box for streaming reasoning, deferred final content until it closes. v2's Thinking component covers this — parity.
  • Status bar: v2 is actually richer — face/verb ticker, voice label, bg task count, ctx bar color thresholds, duration. v1 has 3 adaptive widths but less content. Keep this.

9. Modals / overlays inventory

Overlayv1v2
Approval
Clarify
Sudo prompt
Secret capture
Model picker✅ (2-stage)✅ (2-stage, with g global toggle)
Session picker✅ (curses)✅ (native Ink, 20 recent, 1-9 quick pick)
Pager✅ (v2-only for long slash.exec output)
Skills hub✅ (curses)
Tools config✅ (curses multi-select)
Cron manager✅ (text wizard)
Rollback browser✅ (text)
Snapshot manager✅ (text)
Plugins listing✅ (text)
Agents/tasks listing✅ (text)
Insights dashboard✅ (text)
Browser control✅ (text)
Platforms status✅ (Rich table)

10. Configuration surface

v1 CLI reads ~35 config sections at startup from DEFAULT_CONFIG. v2's useConfigSync.ts polls config.get {key:"full"} every 5s and reacts to:

  • display.bell_on_complete, display.tui_compact, display.tui_statusbar, display.details_mode, display.thinking_mode

Things v1 honors at load that v2's config sync does not read (or reads indirectly via config.set):

  • display.streaming — stream assistant tokens vs batch
  • display.show_reasoning — reveal reasoning deltas
  • display.show_cost — surface $ in status bar
  • display.inline_diffs — render diffs after write tools
  • display.tool_progress / tool_preview_length / tool_progress_overrides
  • display.personality — global personality default
  • approvals.timeout / clarify.timeout — modal countdown defaults
  • voice.auto_tts / voice.silence_* — continuous voice mode tuning
  • quick_commands (see §4)
  • personalities (user-defined, not just the 14 built-ins)
  • skills.external_dirs

Several of these affect rendering choices the TUI makes. display.streaming in particular is semantically important: v1 renders assistant tokens inside the response box live; v2 seems to always accumulate until message.complete — confirm?

11. Startup / boot

  • v1 banner shows per-MCP connect status + profile row + plugin discovery summary. v2 shows logo + tool/skill counts + "N commits behind" if applicable. MCP status is silent unless it errors.
  • v1 background update-check via prefetch_update_check. v2 surfaces the result in the SessionPanel — slightly better UX, good.
  • v1 rotates 100+ tips. v2 has fortunes (shorter, zen-style). Consider importing hermes_cli/tips.py for at least the "feature discovery" subset.
  • v1 resume-display: hermes -c replays history with display.resume_display=full|compact tuning. v2 has HERMES_TUI_RESUME env which resumes by id but the replay fidelity vs display.resume_display is worth verifying.
  • v1 activated-skills line shown at startup when skills are preloaded via -s name1,name2. v2: not surfaced.

12. Info / introspection

  • /usage: both have it, v2's panel covers model + tokens + cost + context % + compressions — parity.
  • /help: v1 has categorized Rich-bordered tables per category. v2 has a Panel with category sections — functional, slightly less structured.
  • /commands (paginated browser): v1 gateway-only. v2 no equivalent.

13. Error handling

  • v1 surfaces rate limits via format_rate_limit_display on /usage. v2 shows tokens/cost but no rate-limit awareness in session.usage output.
  • v1 distinguishes tool failure suffixes: [exit N], [error], [full] (memory). v2's tool tree marks errors but the distinction between exit-code vs exception vs context-overflow may be lost.
  • v1 "double Ctrl+C within 2s" force-exit on idle. v2 has a single Ctrl+C chain that eventually exits — check timing parity.

14. What v2 does better than v1 (don't regress these)

So this doesn't read as pure v1-worship:

  • Virtual-windowed history (v1 can't do this under prompt_toolkit at all).
  • Mouse support — wheel, click-to-position in composer, scrollbar drag, chevron toggle.
  • Ctrl+G → $EDITOR with alt-screen handoff.
  • Sticky prompt tracker (↳ <previous user message> chip when scrolled back).
  • Queue-edit mode (↑/↓ to navigate queued messages, Ctrl+K to dispatch head).
  • Subagent accordion tree with Shift+click expand-all.
  • Face + verb ticker every 2.5s in the status line.
  • GoodVibes heart on "thanks" / "good bot" — small but charming.
  • Live skin hot-swap via skin.changed without restart.
  • Config mtime polling → auto MCP reload (v1 also has this now, but TUI's behavior is cleaner).
  • Bracketed-paste tokenization [[paste:label]] for large pastes — reads better than v1's file-path placeholder inline.
  • Typed command.dispatch payloads (alias / skill / exec / plugin) — cleaner than v1's subprocess stdout scraping.

15. Proposed prioritization

Tier 1 — user-visible daily friction:

  1. Native Skills Hub overlay (/skills is the most-hit config surface in v1).
  2. Native Tools Config overlay (/tools picker, not just enable/disable text).
  3. @file: / @diff / @staged / @git:N / @url: context refs.
  4. Fix /model registry collision so bare /model opens the picker.
  5. MCP status surfaced on boot and on /status / banner.
  6. quick_commands honored.

Tier 2 — feature gaps that break workflows: 7. /rollback overlay (checkpoint browser + diff + restore). 8. /cron manager overlay. 9. /platforms + /profile + /status + /history rendered natively. 10. Per-language syntax highlighting in markdown code blocks. 11. Ctrl+Z suspend + Ctrl+V fallback paste. 12. Paste-to-file behavior for 5+ line pastes (v1 ~/.hermes/pastes/ convention).

Tier 3 — polish: 13. Response Box chrome around assistant messages (skin-styled). 14. Import hermes_cli/tips.py rotation for boot tips. 15. /plugins, /agents, /insights, /browser, /snapshot, /debug, /fast, /gquota, /update native surfaces. 16. Resume-display fidelity parity with display.resume_display. 17. Profile row in banner. 18. Rate-limit display in /usage.


/cc @OutThisLife — raw materials for the audit are in cli.py, hermes_cli/commands.py (v1 side) and ui-tui/src/app/slash/registry.ts + tui_gateway/server.py @method decorators (v2 side). Happy to split this into sub-issues per overlay if that's easier to work against.

extent analysis

TL;DR

Implement native Ink overlays for missing features, fix registry collisions, and add support for context references and quick commands to achieve feature parity between v1 and v2.

Guidance

  1. Implement native Ink overlays: Create overlays for Skills Hub, Tools Config, and other missing features to replace curses-based implementations.
  2. Fix /model registry collision: Update the registry to allow bare /model to open the picker overlay and /model [spec] to switch directly.
  3. Add support for context references: Implement client-side or server-side expansion for @file:, @diff, @staged, @git:N, and @url: context references.
  4. Honor quick commands: Read config.quick_commands and register them as completable slash commands.
  5. Verify and prioritize fixes: Focus on Tier 1 issues (user-visible daily friction) and then address Tier 2 (feature gaps) and Tier 3 (polish) issues.

Example

To fix the /model registry collision, update the ui-tui/src/app/slash/commands/session.ts and ui-tui/src/app/slash/commands/setup.ts files to use distinct names or implement a routing mechanism to handle both cases.

Notes

The provided issue is a comprehensive feature-parity audit, and addressing all the mentioned points will require significant development effort. Prioritizing the fixes based on the proposed tiers will help focus on the most critical issues first.

Recommendation

Apply the workaround by implementing native Ink overlays and fixing registry collisions, and then prioritize the remaining fixes based on the proposed tiers. This approach will help achieve feature parity between v1 and v2 while minimizing disruptions to users.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING