Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… session constructor TDD Red phase: 11 failing tests covering all Task 01 acceptance criteria: - TmuxSession::new() name validation (valid and invalid team names) - TmuxConfig::config_content() branding, keybindings, remain-on-exit - TmuxConfig::path() resolves to ~/.config/botminter/tmux.conf - TmuxConfig::ensure_written() file creation, permissions, atomic write Ref: #5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…structor Implement TmuxConfig (include_str tmux.conf, atomic write via tempfile, 0600 permissions) and TmuxSession::new() with team name validation. All 17 CT-01 tests pass. Uses NamedTempFile for race-safe atomic writes. Ref: #5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract write_to(path) from ensure_written() for testability, write directly to the temp file handle instead of re-opening via fs::write, and isolate tests with temp directories to fix a race condition where concurrent ensure_written() calls left .tmp files visible to other tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sing
12 new tests covering: standard version parsing ("tmux 3.4"),
letter suffix ("tmux 3.3a"), dev prefix ("tmux next-3.4"),
release candidate ("tmux 3.2-rc"), minimum version enforcement,
garbage/empty input rejection, TmuxVersion Display,
tmux_cmd() TMUX_TMPDIR removal, and check_tmux_available() integration.
7 tests fail (awaiting green phase implementation), 5 pass from stubs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement parse_tmux_version() and check_tmux_available() for CT-02 Green.
Handles standard ("tmux 3.4"), letter suffix ("3.3a"), dev prefix ("next-3.4"),
and release candidate ("3.2-rc") formats. Enforces minimum version 3.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract MINIMUM_MAJOR_VERSION constant from hardcoded version check - Reduce parse_tmux_version visibility to fn (only used internally) - Consolidate two impl TmuxSession blocks into one - Move TmuxSession struct before its impl block (was forward-referenced) Ref: #5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement create(), exists(), destroy(), destroy_if_exists() for TmuxSession. All commands use tmux_cmd() helper for TMUX_TMPDIR isolation and -L socket_name for socket isolation. create() ensures config is written before spawning the session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract run_session_cmd() helper to deduplicate create/destroy command execution and error handling - Remove #[allow(dead_code)] from TmuxSession — all fields are actively used - Use tmux_cmd() consistently in tests and TmuxGuard instead of raw Command::new with manual env_remove - Remove redundant TmuxConfig::ensure_written() calls in CT-03 tests — create() handles this internally
Story #6 CT-01: 7 failing tests covering window creation with command, env var security (secrets not in pane_start_command or ps), name validation (valid/invalid), immediate exit detection (non-zero exit and binary not found), and no-session error handling. Scaffolding: create_window() stub (bail!("not yet implemented")), validate_name() shared helper extracted from TmuxSession::new(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements TmuxSession::create_window() with env var passing via tmux -e
flags (secrets never appear in pane_start_command or ps output), name
validation via shared validate_name() helper, PID retrieval via
display-message #{pane_pid}, and immediate exit detection via
#{pane_dead}/#{pane_dead_status} inspection.
Sources the tmux config file on the socket before window creation to
ensure remain-on-exit is active for dead pane retention.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract three helpers from create_window() to reduce duplication: - config_str(): shared config path conversion (was duplicated in create() and create_window()) - source_config(): separates config sourcing concern from window creation - query_pane_format(): deduplicates PID query and dead-pane check display-message pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract require_window() helper to deduplicate the window existence guard and target formatting pattern shared by is_pane_dead() and pane_pid().
9 tests for kill_window_process, remove_window, remove_dead_window, session_info, attach, and full lifecycle integration. 8 fail against stubs, 1 passes (remove non-existent expects Err). Ref: #23 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract allocate_pty() helper from attach() to isolate unsafe libc::openpty block. Reorder create_window() to logical position after session lifecycle methods (before window queries).
6 failing tests covering all acceptance criteria for story #7 CT-01: - launch_ralph creates tmux window with valid PID - launch_brain creates window with stderr log - agent output visible in tmux pane (polling) - daemon PID not in any tmux window - credentials not in pane_start_command or ps - TMUX_TMPDIR isolation for launched agents Scaffolding: launch_ralph() and launch_brain() gain tmux/member_name params with bail!("not yet implemented") stubs. TmuxSession gets public session_name() accessor. Callers updated to compile. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite launch_ralph() and launch_brain() to use TmuxSession::create_window() instead of Command::spawn(). Credentials are written to a temporary file and sourced by a bash wrapper (setenv, not execve), keeping secrets out of /proc/pid/environ and ps auxe. Brain stderr is teed to brain-stderr.log via bash process substitution while remaining visible in the tmux pane. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…start_local_members Red phase for CT-02 Story #7: 4 tests covering session creation on full start, destroy-and-recreate of previous sessions, single-member start preserving existing sessions, and stop preserving tmux windows with scrollback. All fail via prepare_tmux_session() stub. Ref: #7 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement prepare_tmux_session() to manage tmux session lifecycle: - Full start: checks prerequisites, destroys existing session, creates fresh - Single-member start: checks prerequisites, creates only if not existing Fix flaky scrollback test by polling for echo output and using full history capture (-S -) instead of visible-area-only capture-pane. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The tmux session lifecycle (create/destroy) is a one-time setup concern, not a per-member concern. Hoisting it before the loop ensures destroy-on- full-start runs exactly once and prevents re-destroying the session (and its windows) on each subsequent member iteration. Ref: #7
6 tests for CT-03 single-start guard logic:
- fresh_single_start: no session → create + launch
- additive_single_start: add window, preserve existing
- skip_if_live: live window → Skip with PID
- dead_window_restart: dead pane → remove + Launch
- stop_then_start_cycle: kill → dead → remove + Launch
- toctou_race: concurrent starts → clear error, not corruption
Stubs: SingleStartAction enum and single_start_guard() with
bail!("not yet implemented").
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement single_start_guard() which checks tmux window state before
launching a member: returns Launch when no window exists, Skip{pid}
when the window is alive, and Launch after cleaning up dead windows.
Fix CT-03 Red test command to survive create_window's 100ms pane-dead check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Import TmuxSession directly to eliminate verbose formation::local::tmux::TmuxSession paths in prepare_tmux_session and single_start_guard. Remove unused launches counter from TOCTOU race test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract with_path() helper that serializes PATH mutations via a static mutex, preventing parallel test interference between prerequisite check tests and other tests that depend on a stable PATH (e.g., config tests). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CT-02 Red phase for Story #8. Breaking trait change: Formation::shell() now accepts member: Option<String> for per-member window targeting. All implementors updated with stubs. CLI Attach command gains optional positional member argument. 6 failing tests: - shell_no_session_returns_start_hint (no session → error with "bm start" hint) - shell_attaches_to_existing_session (session exists → attach, not stub) - shell_with_member_targets_window (bob window → target it) - shell_with_nonexistent_member_lists_available_windows (alice → list bob, cos) - shell_nested_tmux_warns_but_proceeds ($TMUX set → warn then proceed) - attach_cheat_sheet_displayed_on_stderr (Ctrl-b hints on stderr) Plus 1 compile-time test (shell_trait_compatibility_all_implementors_compile). Ref: #8 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ref: Story #8 CT-03 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…_info Replace hardcoded "botminter" socket name with info.socket_name and use info.session_name consistently instead of mixing info and session sources. Extract raw_attach_command computation before struct init for clarity. Ref: #29 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CT-04 Red phase — write failing tests for branded config verification, E2E tmux lifecycle, and exploratory test updates. Integration tests (3): - tmux_branding_status_left_contains_botminter (PASS — scaffolding) - tmux_branding_list_windows_shows_member_names (PASS — scaffolding) - tmux_keybinding_hints_all_four_visible_in_status_right (FAIL — C-b d:detach missing) E2E tests (3 case functions, registered in both journey passes): - tmux_verify_after_start: AC1/AC2/AC3/AC5 (session, branding, keybindings, status) - tmux_attach_succeeds_while_running: AC4/AC7 (attach works, raw command functional) - tmux_windows_preserved_after_stop: AC6 (remain-on-exit preserves windows) Exploratory tests (5 assertions in phase-h.sh): - H25b: has-session after start - H25c: list-windows shows member names - H25d: bm status shows tmux info - H25e: bm attach shows cheat sheet - H37b/H37c: windows preserved + capture-pane after stop Ref: #8 #30 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ref: #30 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract shared TmuxTestGuard and setup_tmux_session() helper in integration tests, replacing 4 inline Guard struct definitions. Remove duplicate SESSION_NAME assignment in phase-h.sh.
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
Implements the Tmux Agent Sessions epic (stories #5–#8). Adds complete tmux integration for BotMinter:
formation/local/tmux/): Config management, version detection, session/window lifecycle withbotmintersocket isolationTmuxSession): create/query/kill/remove/attach windows with pane capture supportprepare_tmux_session()creates session before member loop,start_member_tmux_window()launches each member in a named window with single-start guardbm attach [member]: Attaches to tmux session, optional member window targeting, nested-session warning, cheat sheet on stderrbm statustmux info: Shows session name, window count,bm attachand rawtmux attachcommandscheck_prerequisites()validates tmux presence and version (≥3.0) with actionable install suggestionstmux.confwith BotMinter status bar, keybinding hints (C-b n/p/[/d), remain-on-exit for dead pane inspectionStories
Test Plan
Closes devguyio-bot-squad/may-team-team#5
Closes devguyio-bot-squad/may-team-team#6
Closes devguyio-bot-squad/may-team-team#7
Closes devguyio-bot-squad/may-team-team#8