fix: ensure base tmux session exists at startup (v0.2.45)#132
Merged
Conversation
The base agentboard session was never created in production code paths. `tmux has-session -t agentboard` returns success whenever any session in the `agentboard` group exists (e.g. per-connection `-ws-` sessions), so `ensureSession()` was a silent no-op. Listings (`SessionManager.listWindows`, `sessionRefreshWorker.listAllWindows`) skip every `-ws-` session as a proxy artifact, leaving an empty window set. Wake operations would then create a window, the orphan check would see an empty set, and the just- created window would be killed (`session_orphaned` followed by `window_killed` within ~10ms). Fix: always ensure the base session exists at startup. Tmux requires every session to contain at least one window, so we use a known-named placeholder window (`__agentboard_root__` running `tail -f /dev/null`) and filter that window out of listings. `has-session` now uses the `=` exact-match prefix so a session-group match doesn't satisfy the existence check. Errors observed in the wild: `tmux list-windows failed: no server running on /private/tmp/tmux-501/default` followed by `windowSetSize=0` and immediate kill of every freshly-woken window.
When a session's tmux window vanishes unexpectedly (server restart, tmux kill-server, refresh-worker detection), the session row now auto-promotes to Hibernating instead of falling to History. Deliberate kills are unaffected because handleKill explicitly clears is_pinned in the same write that nulls current_window — they still land in History. Reverses the "never-hibernated active session falls to History" decision from the cdefa78 hibernation refactor: in practice, losing recent unstarred work to History was the bigger surprise than picking up extra Hibernating rows.
Claude Code marks harness-injected entries (system-reminders, recap notices, compaction summaries) with isMeta:true. The normalizer wasn't filtering them, so they surfaced as the displayed "last user message" instead of the user's actual prior turn.
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
Live wakes were silently killing the freshly-created window. The base `agentboard` session was never created in production code paths — `tmux has-session -t agentboard` returns success on a session group match, so `ensureSession()` was a silent no-op whenever any per-connection `agentboard-ws-*` session existed. Listings (`SessionManager.listWindowsForSession`, `sessionRefreshWorker.listAllWindows`) skip every `-ws-` session as a proxy artifact, leaving an empty windowSet → orphan check kills the just-woken window within ~10ms.
Symptom in the wild:
```
session_wake_success tmuxWindow=agentboard:@1 durationMs=66
session_orphaned currentWindow=agentboard:@1 windowSetSize=0 windowSetSample=[]
window_killed tmuxWindow=agentboard:@1
ERR_INVALID_WINDOW
```
Fix
Bumps version to 0.2.45.
Test plan
Why "create the base session" rather than "make the worker tolerate -ws- views"?
Considered both. Creating the base makes the invariant uniform: `agentboard:@N` is always a real addressable target. The worker-fallback alternative would couple multiple code paths to the group-resolution semantic and rewrite `tmuxWindow` strings under the hood — robust now, footgun later. The placeholder cost is one named window plus a 1-line filter.