Skip to content

/branch (fork) sessions vanish from session listings after parent is closed #20856

@ddiall

Description

@ddiall

Bug Description

After running /branch (aka /fork) to create a forked session, the branched session disappears from hermes sessions list and the TUI resume list once the parent session is closed via TUI shutdown.

Reproduction Steps

  1. Start a session in the TUI
  2. Run /branch my-experiment
  3. Verify the fork is visible (hermes sessions list works because parent still has end_reason="branched")
  4. Close the TUI (ctrl+d or /quit)
  5. Restart the TUI — the forked session does not appear in any listing
  6. hermes sessions list --limit 20 — fork is absent
  7. But it is in the DB: SELECT id, title FROM sessions WHERE parent_session_id IS NOT NULL shows it with 188 messages and a valid title

Root Cause

Two interacting conditions in list_sessions_rich() (hermes_state.py lines 997–1003):

where_clauses.append(
    "(s.parent_session_id IS NULL"
    " OR EXISTS (SELECT 1 FROM sessions p"
    "            WHERE p.id = s.parent_session_id"
    "            AND p.end_reason = 'branched'"
    "            AND s.started_at >= p.ended_at))"
)

Issue 1: p.end_reason = 'branched' gets overwritten

When /branch runs, cli.py:_handle_branch_command() calls end_session(parent_id, "branched"), setting end_reason="branched". But if the user later resumes the parent session via the TUI, tui_gateway/server.py:2119 calls reopen_session(), which clears ended_at and end_reason. When the TUI eventually shuts down, _finalize_session() calls end_session(session_key, "tui_shutdown"), overwriting to "tui_shutdown". Now the filter fails.

Issue 2: s.started_at >= p.ended_at is wrong for /branch semantics

/branch forks the session while the parent is still live — the agent continues running in the new branch immediately. So child.started_at < parent.ended_at (child starts before parent ends). The filter requires child.started_at >= parent.ended_at, which fails for all /branch-created sessions.

Evidence from DB

Parent session: 20260506_173149_af6684
  end_reason:  tui_shutdown  (was "branched", overwritten on TUI close)
  ended_at:    18:59:08       (parent re-ended after being resumed)

Fork session:  20260506_182718_932e89  (188 messages, titled "Hermes In-Process Cron Architecture #2")
  started_at:  18:27:18       (child starts BEFORE parent ends — expected for /branch)
  ended_at:    18:58:12

Filter check:
  p.end_reason = 'branched'?  →  'tui_shutdown' ≠ 'branched'  ✗
  s.started_at >= p.ended_at?         →  18:27:18 >= 18:59:08?  ✗

Both conditions fail, so the fork is excluded from ALL session listings.

Impact

  • Forked/branched sessions become completely invisible through normal UX
  • Users cannot find or resume their branched work
  • Data is not lost (still in SQLite) but unreachable without direct DB queries or --resume <session_id>
  • Particularly harmful for long troubleshooting sessions where forking is the intended pattern

Suggested Fix Approaches

Option A — The filter needs to recognise /branch children independently of the parent's end_reason. The cleanest fix: change the include_children filter to track branches via a separate mechanism (e.g. an explicit branch_of column or a branched flag on the child session), rather than relying on fragile heuristics over the parent's end_reason and timestamps.

Option B — A simpler band-aid: change the condition from p.end_reason = 'branched' to p.end_reason IN ('branched', 'tui_shutdown') and remove the s.started_at >= p.ended_at requirement. This would be more permissive but carries risk of surfacing compression-continuation and subagent sessions that the original filter was designed to hide. Better to add a session provenance field.

Option C — In _handle_branch_command(), mark the child session (not the parent) with a provenance flag (e.g. a session_meta key {"branched_from": "parent_id"}), and add that to the default-include list in list_sessions_rich.

Environment

  • Hermes Agent (git-installed, latest)
  • TUI mode (hermes --tui)
  • DeepSeek V4 Flash provider
  • WSL2 (Ubuntu 24.04)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardcomp/tuiTerminal UI (ui-tui/ + tui_gateway/)type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions