hermes - ✅(Solved) Fix [Bug]: TUI `/resume` slash command does not open session picker [2 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#14467Fetched 2026-04-24 06:17:02
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Author
Participants
Timeline (top)
labeled ×3cross-referenced ×2closed ×1commented ×1

In TUI mode, typing /resume (without arguments) does not open the session picker overlay. No error is shown, and nothing happens.

Error Message

In TUI mode, typing /resume (without arguments) does not open the session picker overlay. No error is shown, and nothing happens.

Additional Logs / Traceback (optional)

Root Cause

File: ui-tui/src/app/overlayStore.ts, line 21-24

The $isBlocked computed value includes picker in its boolean check:

// Before (buggy)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, picker, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || picker || secret || skillsHub || sudo)
)

When /resume is executed, it calls patchOverlayState({ picker: true }). This sets picker: true, which makes $isBlocked evaluate to true.

In appLayout.tsx line 188, FloatingOverlays (which contains SessionPicker) is conditionally rendered:

{!isBlocked && (
  <FloatingOverlays ... />
)}

Since isBlocked is true, the entire overlay container — including SessionPicker — is never mounted. The picker cannot appear.

This is a circular dependency: picker sets isBlocked = true, and isBlocked = true prevents picker from rendering.

Fix Action

Fix

Remove picker from the $isBlocked computed boolean. picker is a user-initiated interactive component, not a blocking flow state (like approval/clarify/confirm):

// After (fixed)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || secret || skillsHub || sudo)
)

PR fix notes

PR #14509: fix(tui): remove picker from $isBlocked to fix /resume command - closes #14467

Description (problem / solution / changelog)

Fix: Remove circular dependency in TUI overlay $isBlocked

Bug

Closes #14467

In TUI mode, typing /resume (without arguments) does not open the session picker overlay. No error is shown, and nothing happens.

Root Cause

In ui-tui/src/app/overlayStore.ts, the $isBlocked computed value includes picker in its boolean check:

export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, picker, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || picker || secret || skillsHub || sudo)
)

When /resume is executed, it calls patchOverlayState({ picker: true }). This sets picker: true, which makes $isBlocked evaluate to true. Since FloatingOverlays (which contains SessionPicker) is conditionally rendered with {!isBlocked && ...}, the picker can never appear.

This is a circular dependency: picker sets isBlocked = true, and isBlocked = true prevents picker from rendering.

Fix

Remove picker from the $isBlocked computed boolean. picker is a user-initiated interactive component, not a blocking flow state (like approval/clarify/confirm):

export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || secret || skillsHub || sudo)
)

Verification

After applying the fix and rebuilding (npm run build in ui-tui/), /resume correctly opens the session picker overlay in TUI mode.

Changed files

  • ui-tui/.gitignore (added, +4/-0)
  • ui-tui/.prettierrc (added, +11/-0)
  • ui-tui/README.md (added, +347/-0)
  • ui-tui/eslint.config.mjs (added, +107/-0)
  • ui-tui/package-lock.json (added, +7271/-0)
  • ui-tui/package.json (added, +43/-0)
  • ui-tui/packages/hermes-ink/ambient.d.ts (added, +83/-0)
  • ui-tui/packages/hermes-ink/index.d.ts (added, +35/-0)
  • ui-tui/packages/hermes-ink/index.js (added, +1/-0)
  • ui-tui/packages/hermes-ink/package-lock.json (added, +819/-0)
  • ui-tui/packages/hermes-ink/package.json (added, +54/-0)
  • ui-tui/packages/hermes-ink/src/bootstrap/state.ts (added, +9/-0)
  • ui-tui/packages/hermes-ink/src/entry-exports.ts (added, +26/-0)
  • ui-tui/packages/hermes-ink/src/hooks/use-stderr.ts (added, +15/-0)
  • ui-tui/packages/hermes-ink/src/hooks/use-stdout.ts (added, +15/-0)
  • ui-tui/packages/hermes-ink/src/ink/Ansi.tsx (added, +435/-0)
  • ui-tui/packages/hermes-ink/src/ink/bidi.ts (added, +145/-0)
  • ui-tui/packages/hermes-ink/src/ink/clearTerminal.ts (added, +68/-0)
  • ui-tui/packages/hermes-ink/src/ink/colorize.ts (added, +226/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/AlternateScreen.tsx (added, +96/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/App.tsx (added, +781/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/AppContext.ts (added, +20/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Box.tsx (added, +294/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Button.tsx (added, +236/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/ClockContext.tsx (added, +133/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/CursorDeclarationContext.ts (added, +28/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/ErrorOverview.tsx (added, +130/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Link.tsx (added, +53/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Newline.tsx (added, +43/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/NoSelect.tsx (added, +73/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/RawAnsi.tsx (added, +61/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/ScrollBox.tsx (added, +285/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Spacer.tsx (added, +23/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/StdinContext.ts (added, +25/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/TerminalFocusContext.tsx (added, +63/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/TerminalSizeContext.tsx (added, +7/-0)
  • ui-tui/packages/hermes-ink/src/ink/components/Text.tsx (added, +302/-0)
  • ui-tui/packages/hermes-ink/src/ink/constants.ts (added, +6/-0)
  • ui-tui/packages/hermes-ink/src/ink/cursor.ts (added, +5/-0)
  • ui-tui/packages/hermes-ink/src/ink/devtools.ts (added, +2/-0)
  • ui-tui/packages/hermes-ink/src/ink/dom.ts (added, +438/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/click-event.ts (added, +38/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/cmd-shortcuts.test.ts (added, +38/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/dispatcher.ts (added, +242/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/emitter.ts (added, +40/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/event-handlers.ts (added, +84/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/event.ts (added, +11/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/focus-event.ts (added, +18/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/input-event.ts (added, +184/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/keyboard-event.ts (added, +57/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/mouse-event.ts (added, +18/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/paste-event.ts (added, +10/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/resize-event.ts (added, +12/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/terminal-event.ts (added, +107/-0)
  • ui-tui/packages/hermes-ink/src/ink/events/terminal-focus-event.ts (added, +19/-0)
  • ui-tui/packages/hermes-ink/src/ink/focus.ts (added, +219/-0)
  • ui-tui/packages/hermes-ink/src/ink/frame.ts (added, +116/-0)
  • ui-tui/packages/hermes-ink/src/ink/get-max-width.ts (added, +27/-0)
  • ui-tui/packages/hermes-ink/src/ink/global.d.ts (added, +1/-0)
  • ui-tui/packages/hermes-ink/src/ink/hit-test.ts (added, +192/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-animation-frame.ts (added, +62/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-app.ts (added, +9/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-declared-cursor.ts (added, +75/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-external-process.ts (added, +27/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-input.ts (added, +95/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-interval.ts (added, +71/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-search-highlight.ts (added, +56/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-selection.ts (added, +97/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-stdin.ts (added, +9/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-tab-status.ts (added, +71/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-focus.ts (added, +18/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-title.ts (added, +34/-0)
  • ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-viewport.ts (added, +100/-0)
  • ui-tui/packages/hermes-ink/src/ink/ink.tsx (added, +2201/-0)
  • ui-tui/packages/hermes-ink/src/ink/instances.ts (added, +10/-0)
  • ui-tui/packages/hermes-ink/src/ink/layout/engine.ts (added, +6/-0)
  • ui-tui/packages/hermes-ink/src/ink/layout/geometry.ts (added, +98/-0)
  • ui-tui/packages/hermes-ink/src/ink/layout/node.ts (added, +145/-0)
  • ui-tui/packages/hermes-ink/src/ink/layout/yoga.ts (added, +313/-0)
  • ui-tui/packages/hermes-ink/src/ink/line-width-cache.ts (added, +28/-0)
  • ui-tui/packages/hermes-ink/src/ink/log-update.ts (added, +738/-0)
  • ui-tui/packages/hermes-ink/src/ink/measure-element.ts (added, +23/-0)
  • ui-tui/packages/hermes-ink/src/ink/measure-text.ts (added, +50/-0)
  • ui-tui/packages/hermes-ink/src/ink/node-cache.ts (added, +53/-0)
  • ui-tui/packages/hermes-ink/src/ink/optimizer.ts (added, +99/-0)
  • ui-tui/packages/hermes-ink/src/ink/output.ts (added, +833/-0)
  • ui-tui/packages/hermes-ink/src/ink/parse-keypress.ts (added, +831/-0)
  • ui-tui/packages/hermes-ink/src/ink/reconciler.ts (added, +382/-0)
  • ui-tui/packages/hermes-ink/src/ink/render-border.ts (added, +206/-0)
  • ui-tui/packages/hermes-ink/src/ink/render-node-to-output.ts (added, +1536/-0)
  • ui-tui/packages/hermes-ink/src/ink/render-to-screen.ts (added, +236/-0)
  • ui-tui/packages/hermes-ink/src/ink/renderer.ts (added, +169/-0)
  • ui-tui/packages/hermes-ink/src/ink/root.ts (added, +174/-0)
  • ui-tui/packages/hermes-ink/src/ink/screen.ts (added, +1551/-0)
  • ui-tui/packages/hermes-ink/src/ink/searchHighlight.ts (added, +91/-0)
  • ui-tui/packages/hermes-ink/src/ink/selection.ts (added, +1070/-0)
  • ui-tui/packages/hermes-ink/src/ink/squash-text-nodes.ts (added, +74/-0)
  • ui-tui/packages/hermes-ink/src/ink/stringWidth.ts (added, +275/-0)
  • ui-tui/packages/hermes-ink/src/ink/styles.ts (added, +750/-0)
  • ui-tui/packages/hermes-ink/src/ink/supports-hyperlinks.ts (added, +51/-0)

PR #14895: fix(tui): keep FloatingOverlays visible when input is blocked

Description (problem / solution / changelog)

What does this PR do?

Fixes a structural regression where FloatingOverlays (SessionPicker, ModelPicker, SkillsHub, pager, completions) was nested inside the !isBlocked guard in ComposerPane. When any overlay opened, $isBlocked became true, which removed the entire composer box from the tree — including the overlay that was trying to render. This made /resume with no args appear to do nothing (the input line vanished and no picker appeared), and also broke /history, /logs, /model, /skills, and the completion dropdown.

Since 99d859ce (feat: refactor by splitting up app and doing proper state), isBlocked gated only the text input lines so that approval/clarify prompts and pickers rendered above a hidden composer. The regression happened in 408fc893 (fix(tui): tighten composer — status sits directly above input, overlays anchor to input) when FloatingOverlays was moved into the input row for anchoring but accidentally kept inside the !isBlocked guard.

This PR restores the original architecture: FloatingOverlays is rendered outside the !isBlocked guard inside the same position:relative Box, so overlays stay visible even when text input is hidden. Only the actual input buffer lines and TextInput remain gated.

this is a better fix than https://github.com/NousResearch/hermes-agent/pull/14509 because if u moved picker out::

• composer completions woukd still trigger underneath the session picker (cause useCompletion gets isBlocked) • typin/enter/arrows in the main handler would still try 2 navigate history or submit messages while the overlay is up • youd have to add special cases in useInputHandlers to ignore keys when overlay.picker is true,, which is just isBlocked with extra steps

Related Issue

<!-- Link the issue this PR addresses. If no issue exists, consider creating one first. -->

Fixes #14467

Type of Change

<!-- Check the one that applies. -->
  • 🐛 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

<!-- List the specific changes. Include file paths for code changes. -->

• ui-tui/src/components/appLayout.tsx: Moved FloatingOverlays outside the !isBlocked conditional so overlays render even when $isBlocked is true. Only composer.inputBuf and TextInput remain gated by !isBlocked.

How to Test

  1. Start the TUI: hermes --tui
  2. Without a session active, type /resume and press Enter
  3. Observe that the SessionPicker overlay appears and the input line does not vanish
  4. Navigate with arrow keys and press Enter to resume a session, or press Esc to cancel

without this PR, you can see /resume just hides the input line and doesn't show the box

Checklist

<!-- Complete these before requesting review. -->

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: NixOS + GhosTTY + fish

Documentation & Housekeeping

<!-- Check all that apply. It's OK to check "N/A" if a category doesn't apply to your change. -->
  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Changed files

  • ui-tui/src/components/appLayout.tsx (modified, +46/-44)

Code Example

// Before (buggy)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, picker, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || picker || secret || skillsHub || sudo)
)

---

{!isBlocked && (
  <FloatingOverlays ... />
)}

---

// After (fixed)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || secret || skillsHub || sudo)
)

---

Debug report uploaded:
  Report     https://paste.rs/bGjBh
  agent.log  https://paste.rs/UPffT

---
RAW_BUFFERClick to expand / collapse

Bug Description

Environment

  • OS: macOS (Apple Silicon)
  • Hermes version: (see debug report)
  • Mode: TUI (hermes --tui)

Description

In TUI mode, typing /resume (without arguments) does not open the session picker overlay. No error is shown, and nothing happens.

Root Cause

File: ui-tui/src/app/overlayStore.ts, line 21-24

The $isBlocked computed value includes picker in its boolean check:

// Before (buggy)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, picker, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || picker || secret || skillsHub || sudo)
)

When /resume is executed, it calls patchOverlayState({ picker: true }). This sets picker: true, which makes $isBlocked evaluate to true.

In appLayout.tsx line 188, FloatingOverlays (which contains SessionPicker) is conditionally rendered:

{!isBlocked && (
  <FloatingOverlays ... />
)}

Since isBlocked is true, the entire overlay container — including SessionPicker — is never mounted. The picker cannot appear.

This is a circular dependency: picker sets isBlocked = true, and isBlocked = true prevents picker from rendering.

Fix

Remove picker from the $isBlocked computed boolean. picker is a user-initiated interactive component, not a blocking flow state (like approval/clarify/confirm):

// After (fixed)
export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || secret || skillsHub || sudo)
)

Verification

After applying the fix and rebuilding (npm run build in ui-tui/), /resume correctly opens the session picker overlay in TUI mode.

Steps to Reproduce

1.Run hermes --tui 2./resume

Expected Behavior

Open session picker

Actual Behavior

Nothing

Affected Component

CLI (interactive chat)

Messaging Platform (if gateway-related)

No response

Debug Report

Debug report uploaded:
  Report     https://paste.rs/bGjBh
  agent.log  https://paste.rs/UPffT

Operating System

macOS 26.4.1

Python Version

No response

Hermes Version

Hermes Agent v0.10.0 (2026.4.16)

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

extent analysis

TL;DR

Remove picker from the $isBlocked computed boolean in ui-tui/src/app/overlayStore.ts to fix the issue with the session picker overlay not appearing in TUI mode.

Guidance

  • Verify that the issue is indeed caused by the circular dependency between picker and isBlocked by checking the values of these variables when /resume is executed.
  • Remove picker from the $isBlocked computed boolean as shown in the proposed fix.
  • Rebuild the project using npm run build in ui-tui/ after applying the fix.
  • Test the fix by running hermes --tui and executing /resume to check if the session picker overlay appears as expected.

Example

The corrected code for the $isBlocked computed boolean would be:

export const $isBlocked = computed(
  $overlayState,
  ({ agents, approval, clarify, confirm, modelPicker, pager, secret, skillsHub, sudo }) =>
    Boolean(agents || approval || clarify || confirm || modelPicker || pager || secret || skillsHub || sudo)
)

Notes

This fix assumes that the issue is solely caused by the circular dependency between picker and isBlocked. If the issue persists after applying this fix, further debugging may be necessary.

Recommendation

Apply the proposed workaround by removing picker from the $isBlocked computed boolean, as this directly addresses the identified root cause of the issue.

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