Skip to content

fix: session resume — scan all workspaces, skip current empty session#3216

Open
TheArchitectit wants to merge 2 commits into
ultraworkers:mainfrom
TheArchitectit:worktree-session-resume-fixes
Open

fix: session resume — scan all workspaces, skip current empty session#3216
TheArchitectit wants to merge 2 commits into
ultraworkers:mainfrom
TheArchitectit:worktree-session-resume-fixes

Conversation

@TheArchitectit
Copy link
Copy Markdown
Contributor

Problem

When a user runs /resume latest from an active REPL session, it returns the most recently created session — which is always the empty session just created on startup. The user expects to resume the previous session with actual conversation history, but gets a blank session instead.

Additionally, the session loading path had two separate code paths: load_session_loose() for cross-workspace alias resume and load_session() for explicit references. This split meant the exclude-id logic (needed to skip the current empty session) would need to be duplicated across both paths.

Solution

Unified the session loading path into a single load_session_excluding() method that:

  1. Accepts an optional exclude_id parameter to skip the current session
  2. Filters out sessions with 0 messages so empty sessions are never returned by /resume latest
  3. Combines cross-workspace alias handling (previously in load_session_loose()) with the exclude logic in one method
  4. Applies the exclude filter consistently across both workspace-local and global session scans

The /resume handler in the CLI now passes the current session ID as the exclude parameter, so /resume latest always skips the current empty session and returns the previous session with actual conversation history.

Changes

  • rust/crates/runtime/src/session_control.rs

    • resolve_reference_excluding(reference, exclude_id) — new method; delegates from resolve_reference(), adds optional exclude_id filtering for alias references
    • latest_session_excluding(exclude_id) — new method; delegates from latest_session(), filters out excluded session IDs and sessions with 0 messages in both local and global scan paths
    • load_session_excluding(reference, exclude_id) — new method; replaces load_session_loose(), combining cross-workspace alias handling with the exclude_id parameter
  • rust/crates/rusty-claude-cli/src/main.rs

    • load_session_reference_excluding(reference, exclude_id) — new function; delegates from load_session_reference(), uses the new store method
    • LiveCli::resume_session() — now passes Some(&self.session.id) as the exclude_id so /resume latest skips the current empty session

Diff verification

rust/crates/runtime/src/session_control.rs | 84 +++++++++++++++++++++++-------
rust/crates/rusty-claude-cli/src/main.rs   | 22 ++++----
2 files changed, 78 insertions(+), 28 deletions(-)

No upstream reverts — all changes are additive with refactored delegations.

Testing

  1. Start claw in a directory with existing sessions
  2. Run /resume latest — should resume the previous session (with messages), not the current empty one
  3. Run /resume latest from a different workspace directory — should still find sessions across all workspaces
  4. Run cargo test -p runtime session_control — all 16 existing session_control tests pass

…ce loading

Three improvements to the /resume command:

1. /resume latest now skips the current empty session
   When a new session is created on startup (with 0 messages), /resume
   latest previously returned that empty session. Now it skips sessions
   with message_count == 0 and excludes the current session ID via the
   new exclude_id parameter, so it finds the previous session with
   actual conversation history.

2. Unified load_session_excluding() replaces load_session_loose()
   The previous load_session_loose() only handled cross-workspace
   resume for aliases. The new load_session_excluding() combines the
   loose workspace validation logic with the exclude_id parameter,
   simplifying the call chain and ensuring all resume paths skip the
   current empty session when appropriate.

3. All existing session scanning paths (global root + project-local
   .claw/sessions/) are already in place from prior commits, and now
   the exclude_id filter is applied consistently across both local
   and global session scans.

Changes:
- session_control.rs: Add resolve_reference_excluding() that delegates
  from resolve_reference(), adding optional exclude_id filtering for
  alias references.
- session_control.rs: Add latest_session_excluding() that delegates
  from latest_session(), filtering out excluded session IDs and
  sessions with 0 messages in both local and global scan paths.
- session_control.rs: Add load_session_excluding() that replaces
  load_session_loose(), combining cross-workspace alias handling with
  the exclude_id parameter.
- main.rs: Add load_session_reference_excluding() that delegates from
  load_session_reference(), using the new store method.
- main.rs: Wire LiveCli::resume_session() to pass the current session
  ID as the exclude_id so /resume latest skips the current empty
  session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@1716775457damn
Copy link
Copy Markdown

The unified session resolution with load_session_excluding() is a clean approach. I notice CI has 2 failing checks (build + cargo test) — worth investigating before merge. One edge case question: what happens when all sessions have 0 messages (fresh install / all deleted)? A clear error message would be better than silently returning nothing.

- Fix latest_session_alias_resolves_most_recent_managed_session test:
  the test created sessions with 0 messages, which are now filtered out
  by the message_count > 0 check in latest_session_excluding(). Updated
  the test to call push_user_text() before saving so sessions have
  at least one message and are findable by /resume latest.

- Add distinct error message when all sessions are empty (0 messages).
  Previously, the same "no managed sessions found" message was returned
  whether there were zero sessions or all sessions had 0 messages. Now:
  - No sessions at all → "no managed sessions found in {path}. Start
    claw to create a session..."
  - Sessions exist but all empty → "all sessions are empty (0 messages)
    in {path}. This usually means a fresh claw session is running but
    no messages have been sent yet. Wait for a response in your other
    session, then try --resume latest again."

- Add test for the all-sessions-empty error path.

  Addresses reviewer feedback on ultraworkers#3216.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants