Skip to content

feat: session detach & reconnect — tabs detach, only exit kills#84

Merged
datasciencemonkey merged 13 commits into
mainfrom
feat/session-detach-reconnect
Mar 28, 2026
Merged

feat: session detach & reconnect — tabs detach, only exit kills#84
datasciencemonkey merged 13 commits into
mainfrom
feat/session-detach-reconnect

Conversation

@datasciencemonkey
Copy link
Copy Markdown
Owner

@datasciencemonkey datasciencemonkey commented Mar 28, 2026

Summary

Sessions now survive tab closure. Closing a tab detaches the frontend — the PTY process keeps running. Only typing exit in the shell kills a session. Users can reconnect to existing sessions on return visits via session picker.

What Changed

Area Before After
Tab/pane close sendBeacon kills PTY immediately Frontend detaches, PTY stays alive
Process exit (exit) Marks exited=True, lingers in dict Calls terminate_session() — immediate cleanup
Return visit (PAT valid) Always creates new session Checks for existing sessions first
1 existing session N/A Auto-reattaches with buffer replay
N existing sessions N/A Interactive picker (keyboard)
Session list API N/A GET /api/sessions with process detection + label
Session attach API N/A POST /api/session/attach with buffer replay
Split pane / new tab N/A Always creates fresh session (no picker)
Reattach display N/A Skips CoDA splash, replays buffer, sends resize
Session management N/A ☰ toolbar button, Ctrl+Shift+S hotkey, d{N} to kill
Session naming N/A Tab label stored on create, shown in picker
Duplicate guard N/A Already-open sessions show (open), can't attach twice

Session Picker

  Existing sessions:

  1  Shell 1        (7m ago)        [claude] (open)
  2  Shell 2        (7m ago)        [node]
  3  My Agent       (6m ago, idle 5m) [bash]

  n  New session
  dN Kill session N (e.g. d2)
  x  Kill all and start fresh

  Select: _

Access via: ☰ toolbar button, Ctrl+Shift+S, or on page load with existing sessions.

Test Plan

Automated (122 tests, all passing)

uv run pytest tests/ -v --ignore=tests/test_npm_version_pinning.py

Manual Testing on Databricks Apps (test-coda on 9cefok)

1. Detach — tab close no longer kills session

  • Open app, create terminal sessions
  • Close the browser tab
  • Reopen the app — sessions still alive (confirmed across all deployments 03:46-04:34)
  • No POST /api/session/close in logs after tab close (only WS disconnect)

2. Auto-reattach (1 session)

  • With 1 existing session, auto-reattaches via POST /api/session/attach
  • Buffer replayed (1.5KB-128KB payloads confirmed)
  • Joins WS room after attach
  • See "── reattached to ──" message visually
  • Terminal redraws correctly without manual resize

3. Session picker (multiple sessions)

  • With 2+ sessions, picker shown (GET /api/sessions at 04:11:48, 04:33:21, 04:34:27)
  • User selected session from picker → attached (04:11:53, 04:12:02)
  • ☰ / Ctrl+Shift+S opens picker mid-session (04:11:58, 04:33:21, 04:34:27 — GET /api/sessions + leave WS room)
  • d{N} kills individual session from picker (Terminating 22ff502b at 04:33:36 + POST /api/session/close at 04:33:39)
  • Killed session not in subsequent picker (04:34:27 — 578 bytes, one fewer session)
  • Type n → creates new session
  • Type x → kills all, creates fresh

4. Fresh deploy — PAT flow then new session

  • After restart, no existing sessions
  • PAT prompt → configured → setup → new session created (confirmed 04:31-04:32)

5. Split pane / new tab — always fresh

  • Split pane creates fresh session (no picker)
  • New tab creates fresh session — POST /api/session at 04:33:04, 04:33:19, 04:34:17 (no /api/sessions call)

6. Exit — kills session immediately

  • exitSession process exitedTerminatingForce killed (04:12:32)
  • Session removed from dict — not in next GET /api/sessions response

7. Process detection

  • GET /api/sessions returns process names (confirmed in all responses)
  • Verify claude shows correctly in picker

8. Buffer replay on reattach

  • Attach returns buffer (confirmed multiple payloads 1.5KB-128KB)
  • Terminal shows prior output after reattach visually

9. Reattach skips CoDA splash

  • Reattach shows replayed buffer instead of splash screen

10. Session labels

  • Picker shows tab name instead of just process name
  • Process name shown in brackets as secondary info

11. Already-open guard

  • Open sessions show (open) tag in picker
  • Typing number for open session shows "Already open" message

12. PAT rotation continues

  • Rotation with ELIMINATED confirmation (04:02:19, 04:13:55)

This pull request was AI-assisted by Claude Code.

@datasciencemonkey datasciencemonkey self-assigned this Mar 28, 2026
Three fixes:
- Reattach skips CoDA splash and duplicate resize (root cause of blank
  screen after picker selection — splash was clearing the replayed buffer)
- Picker supports d{N} to kill individual sessions (e.g. d2 kills #2)
- Sessions button (☰) in toolbar opens picker in active pane anytime
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.

1 participant