Skip to content

feat(sessions): workspace binding — capture git remote/branch, group + filter, restore cwd on resume (#48190)#48591

Open
professorpalmer wants to merge 1 commit into
NousResearch:mainfrom
professorpalmer:feat/session-workspace-binding
Open

feat(sessions): workspace binding — capture git remote/branch, group + filter, restore cwd on resume (#48190)#48591
professorpalmer wants to merge 1 commit into
NousResearch:mainfrom
professorpalmer:feat/session-workspace-binding

Conversation

@professorpalmer

Copy link
Copy Markdown

Summary

Implements session ↔ workspace binding (closes #48190). Sessions already
recorded cwd; this adds git_remote + git_branch, derives a workspace
grouping key, surfaces it in sessions list, lets you filter by it, and
restores the recorded cwd on resume.

Incorporates the design refinement from the issue thread (@Ben-Home): grouping
is derived automatically from (cwd, git_remote) rather than user-organized,
and branch is a per-session attribute, not part of the grouping key — so
checking out a new branch doesn't fragment a workspace's session history.

What changed

hermes_state.py

  • New git_remote / git_branch columns on sessions, added to SCHEMA_SQL
    so they auto-migrate via the existing declarative _reconcile_columns
    no version-gated migration block, no breaking change.
  • Best-effort git capture in create_session() derived from the cwd callers
    already pass (every frontend gets it for free; no call-site changes). Never
    fatal — any git failure yields NULL. Skipped for child sessions
    (subagents/compression) so worktree byproduct doesn't get a workspace identity.
  • _normalize_git_remote() collapses SSH and HTTPS clones of the same repo to
    one key (github.com/owner/repo), credentials stripped.
  • workspace_key(row) — grouping derivation: git remote first, cwd fallback,
    branch deliberately excluded from the key.
  • list_sessions_rich(workspace=...) filter (matches remote exact/substring or cwd).

hermes_cli/main.py

  • sessions list shows a Workspace column (repo@branch, when unbound)
    and accepts --workspace <remote-or-dir>.
  • Resume (chat -r / --continue) cds back into the session's recorded cwd;
    warns and stays put if the dir is gone (never fails the resume).

hermes_cli/_parser.py

  • --no-restore-cwd flag on both chat parsers to opt out of cwd restore.

tests/test_session_workspace_binding.py

  • 7 E2E tests against a temp HERMES_HOME (real SessionDB, real git repos,
    no mocks): column migration, git capture, SSH==HTTPS normalization, non-git
    cwd fallback, child-not-bound, --workspace filter, backwards-compat unbound.

Design constraints honored

  • Cache-safe: workspace metadata is captured once at session creation and
    never mutated mid-conversation — no system-prompt churn, no per-turn token cost.
  • Narrow waist: session-store + CLI surface only; no new model tool.
  • Additive / backwards-compatible: pre-existing sessions have NULL
    workspace fields and render as unbound; sessions list falls back to the
    prior Preview column layout when nothing in the page is workspace-bound.

Test plan

HERMES_HOME=$(mktemp -d) python -m unittest tests.test_session_workspace_binding -v
# 7 passed

CLI smoke: hermes sessions list --help shows --workspace; hermes chat --help
shows --no-restore-cwd.

Not included (noted as follow-ups in #48190)

  • Desktop GUI sidebar grouping (stretch) — backed by the same workspace_key.
  • Worktree-per-session reattach (stretch).

Closes #48190

…+ filter, restore cwd on resume

Implements session<->workspace binding (NousResearch#48190). Sessions already recorded
cwd; this adds git_remote + git_branch (auto-migrated via declarative column
reconciliation) and derives a workspace grouping key.

- hermes_state: new git_remote/git_branch columns; best-effort capture at
  create_session() from the cwd callers already pass; skipped for child
  sessions (subagents/compression). workspace_key() groups by remote (cwd
  fallback) with branch as a per-session attribute, NOT part of the key, so
  switching branches doesn't fragment a workspace's history. SSH and HTTPS
  remotes normalize to one key. list_sessions_rich() gains a workspace= filter.
- CLI: 'sessions list' shows a Workspace column + accepts --workspace; resume
  (chat -r/--continue) cd's back into the recorded cwd, with --no-restore-cwd
  to opt out and a graceful warn-and-stay fallback when the dir is gone.
- Additive + backwards-compatible: pre-existing sessions render as unbound.
- Tests: 7 E2E cases against a temp HERMES_HOME (migration, capture, ssh==https,
  non-git fallback, child-not-bound, filter, backwards-compat).
@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have labels Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session ↔ Workspace binding: record cwd + repo, group in list/browse, restore on resume

2 participants