Skip to content

Conversation

@nocksock
Copy link

@nocksock nocksock commented Dec 14, 2025

Makes it possible to run arbitrary launchers for the selected task. Will offer to add defaults if none are configured.

This could prove quite powerful when paired with custom scripts, eg: a launcher bash script, that creates a worktree, new tmux session with coding agent open and useful prompt to get things going immediately.

Note: not yet properly code-reviewed or cleaned up. Thus this is still a draft. But it's working.

Can be configured like this:

launchers:
  # Simple single-line launcher
  - name: opencode
    exec: opencode -p "Work on task $BEANS_ID"
    description: "Open task in OpenCode"
  
  # Git worktree + tmux launcher
  - name: worktree-tmux
    description: "Create git worktree and open in new tmux pane"
    exec: |
      #!/bin/bash
      set -euo pipefail
      
      WORKTREE_DIR=".worktrees/$BEANS_ID"
      
      # Create worktree if it doesn't exist
      if [ ! -d "$WORKTREE_DIR" ]; then
        git worktree add "$WORKTREE_DIR" -b "task/$BEANS_ID"
      fi
      
      # Open in new tmux pane
      tmux split-window -h -c "$BEANS_ROOT/$WORKTREE_DIR"
      tmux send-keys "opencode -p 'Work on task $BEANS_ID'" Enter

I'm unsure about using env-vars vs. template-vars (eg {{.Title}}).

So that `l` can be used for h/l to browse between tasks.
- Pass multi-line scripts via stdin to interpreter instead of temp files
- Eliminates temp file lifecycle issues and race conditions
- Capture stderr output to provide detailed error messages
- Set working directory to project root instead of .beans/ directory
- Add BEANS_DIR environment variable for .beans/ path
- Clarify BEANS_ROOT is project root (working directory)
- Document new BEANS_DIR variable for .beans/ directory
- Add worktree-kitty launcher with multiple: true
- Handle existing branches and stale worktree registrations
- Demonstrate multi-bean parallel launcher pattern
…aunchers

- Consolidated duplicate createExecCommand logic between TUI and launcher package
- TUI now uses launcher.CreateExecCommand for consistency
- Single-bean launchers now receive BEANS_DIR environment variable
- Added comprehensive tests for environment variable consistency
- Updated documentation to reflect all available env vars

BREAKING CHANGE: Single-bean launchers now receive BEANS_DIR environment
variable. Launchers that relied on its absence may need updating.
Add comprehensive regression tests to verify that the launch progress view:
- Does NOT dismiss on arbitrary key presses (the bug fix)
- DOES dismiss on q/esc keys (expected behavior)
- Properly handles completion and failure messages
- Processes progress messages without dismissing
- Handles window resize messages
- Cleans up ticker on dismissal

These tests ensure the bug fixed in the previous commit doesn't regress,
where misplaced code was dismissing the progress view on ANY key press.
… view

The viewLaunchProgress case had erroneous code (lines 804-808) that was
dismissing the progress view on ANY key press. This code was likely
copy-pasted from one of the error modal cases and left in by mistake.

This caused the TUI to become stuck showing "Loading..." when using a
launcher with multiple tasks, as the progress view would be dismissed
immediately after any update, preventing the launchProgressMsg from
being processed correctly.

Fixes beans-b1u8
- Remove isCommandAvailable() function and its tests
- Remove resolveCommand() function and its tests
- Remove unused os/exec import
- These functions were legacy code from when discovery filtered by availability
- All launchers are now shown regardless of availability (checked at execution time)
- Replaced custom stripAnsi() function with github.com/charmbracelet/x/ansi.Strip()
- Added comprehensive test coverage for ANSI stripping behavior
- Removed 19 lines of custom code in favor of well-tested library function
- Library handles all escape sequences more robustly

Closes beans-1j65
- Test Launcher.Multiple field defaults to false
- Test TUIConfig.DisableLauncherWarning field defaults to false
- Test config fields persist through save/load cycle
- Test launcher with shebang but empty body (valid)
- Test launcher with Windows line endings (handled by YAML)
- Test multiple launchers with same name (both loaded)
- Test very long launcher scripts (10KB+)
- Test launcher names with special characters
- Test launcher exec with null bytes (YAML handles gracefully)
- Test shebang in middle of script (correctly rejected)

All tests verify existing behavior works correctly.
- Remove separate single-bean code path using tea.ExecProcess
- All launches now go through LaunchManager with progress view
- Remove unused launcherFinishedMsg type and handler
- Provides consistent error handling, duration tracking, and cancellation

BREAKING CHANGE: Single bean launches now show progress view instead of inline execution
- Replace 5 separate query methods with single GetSummary()
- Single lock acquisition for consistent snapshots
- Cleaner API with comprehensive LaunchSummary struct
- Includes LaunchCounts with convenient Total field
- Add LaunchCounts and LaunchSummary types
- Implement GetSummary() method that returns all status info in single call
- Remove old methods: GetStatus, IsComplete, AllSuccessful, GetFirstError, GetCounts
- Update launchprogress.go to use GetSummary()
- Single lock acquisition for consistent snapshots
- All tests passing

Benefits:
- Single lock acquisition instead of 4 separate calls
- Impossible to have inconsistent state between queries
- Clearer API with comprehensive LaunchSummary struct
- LaunchCounts includes convenient Total field
@sotte
Copy link
Contributor

sotte commented Dec 28, 2025

When I just looked at the PR description I did not fully understand what this is. The README was helpful though.

I actually have a similar, albeit more manual workflow. I yank the bean id from the tui and run a script that launches a tmux window with Claude and a prompt "Work on BEAN_ID. Make a plan, update the bean."

This is basically your launcher.

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