Skip to content

feat: Session naming with unique titles, auto-lineage & rich listing#720

Merged
teknium1 merged 4 commits intomainfrom
feat/session-naming
Mar 8, 2026
Merged

feat: Session naming with unique titles, auto-lineage & rich listing#720
teknium1 merged 4 commits intomainfrom
feat/session-naming

Conversation

@teknium1
Copy link
Copy Markdown
Contributor

@teknium1 teknium1 commented Mar 8, 2026

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

  • Name your sessions: /title my project in CLI or gateway to tag a session with a human-readable name
  • Resume by name: hermes -c "my project" or hermes --resume "my project" — no more hunting for session IDs
  • Auto-lineage: When context compression creates a new session, the title auto-increments ("my project" → "my project Support passing morph snapshot id #2" → "my project Architecture planning #3"). Asking for "my project" auto-resolves to the latest in the lineage.
  • Rich session listing: hermes sessions list now shows Title, Preview (first 60 chars of first user message), Last Active (relative time), and ID
  • Rename sessions: hermes sessions rename <id> My New Title

Changes

Core — hermes_state.py

  • Schema v4 with unique title index + clean migration from v2/v3
  • set_session_title() — enforces uniqueness, raises ValueError on conflict
  • sanitize_title() — strips control chars (ASCII + problematic Unicode like zero-width, RTL overrides, BOM), collapses whitespace, enforces 100-char max length
  • get_session_title() / get_session_by_title() — title lookup helpers
  • resolve_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 continuations
  • list_sessions_rich() — returns preview (first 60 chars of first user message, newlines collapsed) + last_active timestamp

CLI — cli.py, hermes_cli/main.py

  • -c / --continue now accepts optional name: hermes -c (latest) or hermes -c "my project"
  • --resume accepts session ID or title: hermes --resume "my project"
  • /title slash command with deferred mode — can set title before session is created in DB (queued and applied on first message)
  • /title with no args shows the current title
  • _resolve_session_by_name_or_id() — tries exact session ID first, then title resolution
  • sessions list shows Title, Preview, Last Active (relative), ID in a formatted table
  • sessions rename <id> <title> with uniqueness error handling
  • Session title displayed on resume: ↻ Resumed session <id> "my title"

Gateway — gateway/run.py

  • /title command added for all messaging platforms (Telegram, Discord, Slack, WhatsApp)
  • Shows current title with no args, sets title with args
  • Title sanitization and uniqueness validation with user-friendly error messages
  • Added to /help output

Agent — run_agent.py

Commands — hermes_cli/commands.py

  • /title registered as a known slash command with autocomplete

Documentation

  • Updated AGENTS.md, CONTRIBUTING.md, CLI reference docs, sessions guide, and website docs

Tests

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 wildcards
  • tests/gateway/test_title_command.py — Gateway /title command: set, show, conflict, no-DB fallback, control char sanitization, cross-platform, help output
  • tests/hermes_cli/test_commands.py — Updated expected commands list

All tests passing (2338 at time of merge).

Files Changed

File Changes
hermes_state.py Schema v4, title methods, sanitization, rich listing
cli.py Deferred /title, resume by name, title display on resume
run_agent.py Title propagation on context compression
gateway/run.py /title command for all platforms
hermes_cli/main.py -c name, --resume name, sessions list/rename
hermes_cli/commands.py /title command registration
tests/test_hermes_state.py 61 new tests
tests/gateway/test_title_command.py 11 new tests (new file)
tests/hermes_cli/test_commands.py Updated expected commands
website/docs/ Sessions guide, CLI reference, user guide
AGENTS.md, CONTRIBUTING.md Development docs updated
teknium1 added 4 commits March 8, 2026 15:20
…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'.
@teknium1 teknium1 merged commit c5e8166 into main Mar 8, 2026
1 check passed
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant