feat: Session naming with unique titles, auto-lineage & rich listing#720
Merged
feat: Session naming with unique titles, auto-lineage & rich listing#720
Conversation
…resume by name - Schema v4: unique title index, migration from v2/v3 - set/get/resolve session titles with uniqueness enforcement - Auto-lineage: context compression auto-numbers titles (Task -> Task #2 -> Task #3) - resolve_session_by_title: auto-latest finds most recent continuation - list_sessions_rich: preview (first 60 chars) + last_active timestamp - CLI: -c accepts optional name arg (hermes -c 'my project') - CLI: /title command with deferred mode (set before session exists) - CLI: sessions list shows Title, Preview, Last Active, ID - 27 new tests (1844 total passing)
- Empty string titles normalized to None (prevents uncaught IntegrityError when two sessions both get empty-string titles via the unique index) - Escape SQL LIKE wildcards (%, _) in resolve_session_by_title and get_next_title_in_lineage to prevent false matches on titles like 'test_project' matching 'testXproject #2' - Optimize list_sessions_rich from N+2 queries to a single query with correlated subqueries (preview + last_active computed in SQL) - Add /title slash command to gateway (Telegram, Discord, Slack, WhatsApp) with set and show modes, uniqueness conflict handling - Add /title to gateway /help text and _known_commands - 12 new tests: empty string normalization, multi-empty-title safety, SQL wildcard edge cases, gateway /title set/show/conflict/cross-platform
…pping - Add SessionDB.sanitize_title() static method: - Strips ASCII control chars (null, bell, ESC, etc.) except whitespace - Strips problematic Unicode controls (zero-width, RTL override, BOM) - Collapses whitespace runs, strips edges - Normalizes empty/whitespace-only to None - Enforces 100 char max length (raises ValueError) - set_session_title() now calls sanitize_title() internally, so all call sites (CLI, gateway, auto-lineage) are protected - CLI /title handler sanitizes early to show correct feedback - Gateway /title handler sanitizes early to show correct feedback - 24 new tests: sanitize_title (17 cases covering control chars, zero-width, RTL, BOM, emoji, CJK, length, integration), gateway validation (too long, control chars, only-control-chars)
- website/docs/user-guide/sessions.md: New 'Session Naming' section with /title usage, title rules, auto-lineage, gateway support. Updated 'Resume by Name' section, 'Rename a Session' subsection, updated sessions list output format, updated DB schema description. - website/docs/reference/cli-commands.md: Added -c "name" and --resume by title to Core Commands, sessions rename to Sessions table, /title to slash commands. - website/docs/user-guide/cli.md: Added -c "name" and --resume by title to resume options. - AGENTS.md: Added -c, --resume, sessions list/rename to CLI commands table. Added hermes_state.py to project structure. - CONTRIBUTING.md: Updated hermes_state.py and session persistence descriptions to mention titles. - hermes_cli/main.py: Fixed sessions help string to include 'rename'.
This was referenced Mar 8, 2026
teknium1
added a commit
that referenced
this pull request
Mar 9, 2026
Messaging users can now switch back to previously-named sessions: - /resume My Project — resolves the title (with auto-lineage) and restores that session's conversation history - /resume (no args) — lists recent titled sessions to choose from Adds SessionStore.switch_session() which ends the current session and points the session entry at the target session ID so the old transcript is loaded on the next message. Running agents are cleared on switch. Completes the session naming feature from PR #720 for gateway users. 8 new tests covering: name resolution, lineage auto-latest, already-on- session check, nonexistent names, agent cleanup, no-DB fallback, and listing titled sessions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a full session naming and management system to Hermes Agent. Session titles act as unique identifiers (like git branch names) with automatic lineage numbering when context compression creates continuation sessions.
What This Enables
/title my projectin CLI or gateway to tag a session with a human-readable namehermes -c "my project"orhermes --resume "my project"— no more hunting for session IDshermes sessions listnow shows Title, Preview (first 60 chars of first user message), Last Active (relative time), and IDhermes sessions rename <id> My New TitleChanges
Core — hermes_state.py
set_session_title()— enforces uniqueness, raisesValueErroron conflictsanitize_title()— strips control chars (ASCII + problematic Unicode like zero-width, RTL overrides, BOM), collapses whitespace, enforces 100-char max lengthget_session_title()/get_session_by_title()— title lookup helpersresolve_session_by_title()— auto-latest: asking for "my project" finds the highest-numbered variant ("my project Architecture planning #3")get_next_title_in_lineage()— auto-numbering for context compression continuationslist_sessions_rich()— returns preview (first 60 chars of first user message, newlines collapsed) + last_active timestampCLI — cli.py, hermes_cli/main.py
-c/--continuenow accepts optional name:hermes -c(latest) orhermes -c "my project"--resumeaccepts session ID or title:hermes --resume "my project"/titleslash command with deferred mode — can set title before session is created in DB (queued and applied on first message)/titlewith no args shows the current title_resolve_session_by_name_or_id()— tries exact session ID first, then title resolutionsessions listshows Title, Preview, Last Active (relative), ID in a formatted tablesessions rename <id> <title>with uniqueness error handling↻ Resumed session <id> "my title"Gateway — gateway/run.py
/titlecommand added for all messaging platforms (Telegram, Discord, Slack, WhatsApp)/helpoutputAgent — run_agent.py
parent_session_idset for lineage trackingCommands — hermes_cli/commands.py
/titleregistered as a known slash command with autocompleteDocumentation
AGENTS.md,CONTRIBUTING.md, CLI reference docs, sessions guide, and website docsTests
72 new tests across 3 files:
tests/test_hermes_state.py— Title CRUD, uniqueness enforcement, lineage resolution, rich listing, previews, migration from v2, sanitization (control chars, Unicode, edge cases), SQL injection safety for LIKE wildcardstests/gateway/test_title_command.py— Gateway/titlecommand: set, show, conflict, no-DB fallback, control char sanitization, cross-platform, help outputtests/hermes_cli/test_commands.py— Updated expected commands listAll tests passing (2338 at time of merge).
Files Changed
hermes_state.pycli.py/title, resume by name, title display on resumerun_agent.pygateway/run.py/titlecommand for all platformshermes_cli/main.py-c name,--resume name, sessions list/renamehermes_cli/commands.py/titlecommand registrationtests/test_hermes_state.pytests/gateway/test_title_command.pytests/hermes_cli/test_commands.pywebsite/docs/AGENTS.md,CONTRIBUTING.md