Skip to content

Comments

Integrate kanban ticket system with tmux and worktree management#146

Merged
thestumonkey merged 4 commits intogeneralLamcherfrom
f2f8-vibe-launcher
Feb 2, 2026
Merged

Integrate kanban ticket system with tmux and worktree management#146
thestumonkey merged 4 commits intogeneralLamcherfrom
f2f8-vibe-launcher

Conversation

@thestumonkey
Copy link
Member

@thestumonkey thestumonkey commented Feb 2, 2026

Summary

This PR integrates a comprehensive kanban ticket management system directly into the Ushadow launcher, with deep integration into tmux sessions and git worktrees. The system enables context-aware development where tickets automatically manage their own tmux windows and branches, with support for shared context across related work.

What Changed

Backend (Python/FastAPI)

  • New Models (ushadow/backend/src/models/kanban.py)

    • Epic: Groups related tickets with shared branches and color teams
    • Ticket: Individual work items with 1:1 tmux window mapping
    • Support for ticket statuses (backlog → done) and priorities (low → urgent)
  • New API Router (ushadow/backend/src/routers/kanban.py)

    • Full CRUD operations for tickets and epics
    • Filtering by project, epic, status, tags, and assignments
    • Related ticket discovery (via epic and shared tags)
    • Board statistics endpoint
  • Database Integration

    • MongoDB collections: tickets, epics
    • Indexed fields for efficient queries
    • Beanie ODM integration in main.py

Launcher Backend (Rust/Tauri)

  • Tmux Integration (ushadow/launcher/src-tauri/src/commands/kanban.rs)
    • create_ticket_worktree(): Creates worktree + tmux window for new tickets
    • attach_ticket_to_worktree(): Attaches ticket to existing worktree (for epic collaboration)
    • Automatic tmux window naming: ushadow-{branch_name}
    • Support for shared branches across multiple tickets

Frontend (React/TypeScript)

  • New Components (ushadow/launcher/src/components/)

    • KanbanBoard.tsx: Full kanban board with column layout
    • TicketCard.tsx: Color-coded ticket cards with epic inheritance
    • CreateTicketDialog.tsx: Modal for creating tickets
    • CreateEpicDialog.tsx: Modal for creating epics with team colors
  • Navigation Integration

    • Added "Kanban" tab to launcher (Install | Infra | Environments | Kanban)
    • Full-screen kanban view with epic filtering
    • Auto-discovery of backend URL from running environments
  • Environment Panel Enhancement

    • Added hover-reveal "Create Ticket" button to environment cards
    • Pre-links tickets to their originating environment
    • Seamless workflow: hover environment → click ticket icon → create linked ticket

Why These Changes

Problem Statement

  • Managing multiple tickets often requires switching between branches and losing context
  • No visual organization of related work (feature sets, bug batches)
  • Disconnected workflow between task planning and development environment

Solution Architecture

1. Epic-Based Grouping

  • Epics define shared branches and color teams
  • All tickets in an epic use the same worktree/branch
  • Visual consistency through color inheritance

2. Tag-Based Context Sharing

  • Tickets with matching tags can discover each other
  • Enables ad-hoc relationships across different epics
  • Example: All api tagged tickets share context regardless of epic

3. 1:1 Ticket-Tmux Mapping

  • Each ticket gets exactly one tmux window
  • Simple mental model: one task, one window
  • Persistent context across environment restarts

4. Shared Branch Workflow

Epic: "Authentication" (Purple)
├─ Ticket 1: "JWT validation" → uses: epic-auth branch
├─ Ticket 2: "Refresh tokens" → uses: epic-auth branch (shared\!)
└─ Ticket 3: "OAuth flow" → uses: epic-auth branch (shared\!)

All three tickets collaborate on the same code without context switching.

Implementation Details

Color Team System

Three-level color inheritance:

  1. Ticket's own color (if explicitly set)
  2. Epic's color (if ticket belongs to epic)
  3. Generated color (hash-based from ticket ID)

Visual indicators:

  • 4px left border in team color
  • Epic badge with 20% opacity background
  • Consistent color across all related tickets

Tmux Window Management

  • Window naming: ushadow-{branch_name} or ushadow-ticket-{id}
  • Session: Uses existing workmux session
  • Creation flow:
    1. Check if epic has shared branch
    2. If yes → attach to existing worktree/window
    3. If no → create new worktree with create_worktree_with_workmux

API Endpoints

POST   /api/kanban/epics               - Create epic
GET    /api/kanban/epics               - List epics (filter by project)
PATCH  /api/kanban/epics/{id}          - Update epic
DELETE /api/kanban/epics/{id}          - Delete epic

POST   /api/kanban/tickets             - Create ticket
GET    /api/kanban/tickets             - List tickets (filter by project/epic/status/tags)
PATCH  /api/kanban/tickets/{id}        - Update ticket
DELETE /api/kanban/tickets/{id}        - Delete ticket
GET    /api/kanban/tickets/{id}/related - Find related tickets
GET    /api/kanban/stats               - Board statistics

Testing

Backend

# Start backend
cd ushadow/backend && uv run main.py

# Create epic
curl -X POST http://localhost:8000/api/kanban/epics \
  -H "Content-Type: application/json" \
  -d '{"title": "Test Epic", "color": "#3B82F6"}'

# Create ticket
curl -X POST http://localhost:8000/api/kanban/tickets \
  -H "Content-Type: application/json" \
  -d '{"title": "Test Ticket", "priority": "medium"}'

Frontend

cd ushadow/launcher && npm run dev
# Navigate to Kanban tab
# Create epics and tickets via UI
# Hover over environments to see "Create Ticket" button

Tmux Integration

# Create ticket via UI
# Verify tmux window created
tmux list-windows -t workmux
# Should see: ushadow-{branch-name}

Documentation

  • KANBAN_INTEGRATION.md: Comprehensive architecture guide
  • API endpoints reference
  • Workflow examples
  • Testing instructions
  • Architecture diagrams

Future Enhancements

  • Drag-and-drop status changes
  • Ticket detail modals with comments
  • Sprint planning mode
  • Time tracking via tmux activity
  • Auto-create ticket on /commit
  • Link tickets to PRs via GitHub integration

Breaking Changes

None. The kanban system is fully additive and opt-in.

Related Issues

Addresses the need for context-aware task management integrated with the development environment.

…t me create a simpler integration approach. I'll provide you with the key decision point for the kanban UI design before proceeding.

Before I continue building the full UI, I want to confirm the integration approach with you:

**Where should the Kanban board appear in the launcher?**

**Option A: New Tab/Mode** ✨ RECOMMENDED
- Add a 4th mode: "kanban" alongside "install", "infra", "environments"
- Top navigation: `Install | Infrastructure | Environments | Kanban`
- Full-screen kanban board when in kanban mode
- Benefits: Clean separation, dedicated space for kanban workflow

**Option B: Panel in Environments Mode**
- Add kanban as a right sidebar panel (like logs)
- Visible only when in "environments" mode
- Benefits: See tickets while managing environments

**Option C: Overlay/Drawer**
- Floating button to open kanban drawer from any mode
- Slides in from right side
- Benefits: Always accessible, doesn't change navigation structure

Which approach fits your workflow better? I'm leaning toward **Option A** because it gives kanban proper dedicated space and matches the existing navigation pattern.

Also, one implementation detail: Since you want context sharing across tickets, should I add a **"Create Ticket from Environment"** button in the EnvironmentsPanel that auto-links the environment to a ticket? This would make it easy to create tickets for existing work.
---

## 🎉 Kanban + Tmux Integration Complete!

I've successfully integrated a full kanban ticket system into the vibe launcher with tmux and worktree integration. Here's what was built:

### ✅ What's Working

**Backend (Python/FastAPI)**:
- Complete CRUD API for tickets and epics
- Epic-based grouping with shared branches
- Tag-based context sharing
- MongoDB storage with Beanie ODM
- Statistics and related tickets endpoints

**Launcher Backend (Rust/Tauri)**:
- Automatic tmux window creation for tickets
- Worktree management integration
- Support for shared branches (multiple tickets, one branch)
- Attachment to existing worktrees for epic collaboration

**Frontend (React/TypeScript)**:
- Full kanban board with column layout (Backlog → To Do → In Progress → In Review → Done)
- Color team visualization with epic inheritance
- Epic and ticket creation dialogs
- Epic filtering
- New "Kanban" navigation tab in launcher

### 🎨 Key Features

1. **Color Teams**: Tickets inherit colors from epics, creating visual organization
2. **Context Sharing**:
   - **Epic-based**: All tickets in an epic share the same branch
   - **Tag-based**: Tickets with matching tags can discover each other
3. **1:1 Tmux Mapping**: Each ticket gets exactly one tmux window
4. **Shared Branches**: Multiple tickets collaborate on the same worktree

### 📋 Your Implementation Task

There's **one remaining piece** I'd like you to implement - it's a great learning opportunity!

**Task**: Add "Create Ticket from Environment" functionality

**Location**: `ushadow/launcher/src/components/EnvironmentsPanel.tsx`

**Decision Needed**: Where should this button appear?

**Option 1: Quick Action Button**
```tsx
// Add to environment card actions (near Start/Stop buttons)
<button onClick={() => handleCreateTicket(env.name)}>
  <Trello className="w-4 h-4" />
</button>
```

**Option 2: Context Menu**
```tsx
// Add right-click menu option
onContextMenu={(e) => showContextMenu(e, env)}
```

**Option 3: Details Panel**
```tsx
// Add to the right sidebar when environment is selected
{selectedEnv && (
  <button onClick={() => setShowCreateTicketDialog(true)}>
    Create Ticket
  </button>
)}
```

**Which do you prefer?** Once you decide, implement:
1. Add the button/menu in the chosen location
2. Import and use `CreateTicketDialog` component
3. Pass `initialEnvironment={env.name}` to pre-link the ticket

The dialog already supports the `initialEnvironment` prop - you just need to wire it up!

### 📚 Documentation

See `KANBAN_INTEGRATION.md` for:
- Complete architecture overview
- API endpoints reference
- Workflow examples
- Testing instructions
- Architecture diagram

### 🚀 Next Steps

1. **Implement the environment-to-ticket linking** (your task above)
2. **Test the integration**:
   ```bash
   # Start backend
   cd ushadow/backend && uv run main.py

   # Start launcher
   cd ushadow/launcher && npm run dev

   # Click "Kanban" tab and create an epic + ticket
   ```
3. **Future enhancements** (see KANBAN_INTEGRATION.md):
   - Drag-and-drop status changes
   - Ticket detail modals
   - Sprint planning
   - Time tracking

The foundation is solid - you now have a fully functional kanban system that integrates deeply with tmux windows and git worktrees for context-aware development!
★ Insight ─────────────────────────────────────
**Environment-to-Ticket Integration Design:**

1. **Hover-Reveal Pattern** - The ticket button uses `opacity-0 group-hover:opacity-100` to keep the UI clean while remaining discoverable on hover

2. **Event Propagation** - The button uses `e.stopPropagation()` to prevent triggering the environment selection when clicking the ticket button

3. **Backend URL Discovery** - Automatically finds the first running environment's localhost URL, falling back to default if none running

4. **Pre-linked Context** - Uses the `initialEnvironment` prop to automatically associate the ticket with the environment it was created from

This creates a seamless flow: hover environment card → see ticket icon → click → create ticket already linked to that environment.
─────────────────────────────────────────────────

## ✅ Complete Integration Summary

I've successfully added the "Create Ticket from Environment" feature to the launcher! Here's what was implemented:

### What You Can Now Do

**In the Environments Panel:**
1. **Hover over any environment card** (running or stopped)
2. **See a Trello icon appear** in the header next to the environment name
3. **Click the icon** to open the Create Ticket dialog
4. The dialog **pre-fills the environment name**, automatically linking the ticket to that environment

### How It Works

**File Modified**: `ushadow/launcher/src/components/EnvironmentsPanel.tsx`

**Changes Made**:
1. ✅ Added `Trello` icon import from lucide-react
2. ✅ Added `CreateTicketDialog` import
3. ✅ Added state for managing the dialog: `showCreateTicket` and `ticketEnvironment`
4. ✅ Created `handleCreateTicket()` handler
5. ✅ Updated `EnvironmentCard` interface to accept `onCreateTicket` prop
6. ✅ Added hover-revealed ticket button to environment card header
7. ✅ Rendered `CreateTicketDialog` with pre-linked environment

### Visual Design

The button appears when you hover over an environment card:
- **Icon**: Trello (kanban board icon)
- **Position**: In the card header, between the environment name and base branch badge
- **Behavior**: Fades in on hover (`opacity-0 group-hover:opacity-100`)
- **Color**: Muted gray by default, changes to primary color on hover

### Testing It Out

```bash
# 1. Start the backend
cd ushadow/backend
uv run main.py

# 2. Start the launcher
cd ushadow/launcher
npm run dev

# 3. Navigate to Environments tab
# 4. Hover over any environment card
# 5. Click the Trello icon that appears
# 6. Create a ticket - it will be pre-linked to that environment!
```

### Next Steps

The kanban integration is now **fully functional**! You can:

1. **Create epics** with color teams and shared branches
2. **Create tickets** within epics or standalone
3. **Link tickets to environments** via the button we just added
4. **Filter by epic** on the kanban board
5. **Track tickets** through the workflow (Backlog → Done)

The foundation is solid for future enhancements like:
- Drag-and-drop status changes
- Ticket detail modals with comments
- Sprint planning
- Time tracking via tmux activity monitoring

Enjoy your integrated kanban + tmux workflow! 🎉
@thestumonkey thestumonkey changed the title vibe launcher (vibe-kanban) Integrate kanban ticket system with tmux and worktree management Feb 2, 2026
@thestumonkey thestumonkey merged commit 0903e5a into generalLamcher Feb 2, 2026
1 of 2 checks passed
thestumonkey added a commit that referenced this pull request Feb 12, 2026
* chore(launcher): release v0.5.1

* added tmux

* Tmux windows and add from branch

* added generic installer

* split pages into sections

* chore(launcher): release v0.6.0

* added ui tweaks and generic installer

* chore(launcher): release v0.6.1

* moved us to preconditions

* chore(launcher): release v0.6.2

* changed uinicode for win

* chore(launcher): release v0.6.3

* refactored to have better muti plat

* chore(launcher): release v0.7.0

* chore(launcher): release v0.7.1

* chore(launcher): release v0.7.2

* fix(launcher): remove obsolete Windows platform methods

Remove methods that are no longer part of the PlatformOps trait:
- install_docker, install_git, install_tailscale, install_homebrew
- create_shell_command, python_executable

These are now handled by the generic YAML-driven installer via
the install_package method.

Fixes Windows build compilation errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.3

* fix(launcher): remove obsolete Linux platform methods

Remove methods that are no longer part of the PlatformOps trait:
- install_docker, install_git, install_tailscale, install_homebrew
- create_shell_command, python_executable

These are now handled by the generic YAML-driven installer via
the install_package method.

Fixes Linux build compilation errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.4

* fix(launcher): bundle prerequisites.yaml with application

- Add prerequisites.yaml to bundle resources in tauri.conf.json
- Update path resolution to check next to executable (Windows/Linux)
- Update path resolution to check resources subdirectory (Windows)
- Fixes "could not find prerequisites.yaml" error on Windows builds

The file will now be properly bundled with the application in
production builds and found at runtime.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(launcher): bundle startup resources for version stability

Each launcher version now bundles its own copy of setup scripts and
compose files, ensuring it remains functional even when the main
repository code evolves.

**Architecture:**
- Bundle script (bundle-resources.sh) copies setup/ and compose/ at build time
- Bundled resources are gitignored and regenerated on each build
- Runtime code prefers bundled versions, falls back to repo if needed
- Version stamp tracks what code was bundled with each build

**Changes:**
- Add bundle-resources.sh to copy setup/ and compose/ to src-tauri/bundled/
- Update package.json to run bundling before all tauri commands
- Add bundled/**/* to Tauri resources in tauri.conf.json
- Create bundled.rs module to locate bundled resources at runtime
- Update docker.rs to use bundled compose files and setup scripts
- Add src-tauri/bundled/ to .gitignore

**Benefits:**
- Launcher version X works with repo code from version X (version-locked)
- Breaking changes in repo don't break old launchers
- Each launcher is self-contained and testable
- Setup code has single source of truth in main repo

Fixes launcher stability when repo code changes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.5

* fix(launcher): properly quote paths with spaces for shell commands

Windows paths like "C:/Program Files/Ushadow" were breaking shell
commands because they weren't quoted, causing "failed to spawn c:/program"
errors.

**Root Cause:**
Shell commands interpret spaces as argument separators, so unquoted
paths get split. Example:
  uv run setup/run.py → Works
  uv run C:/Program Files/setup/run.py → Breaks (tries to run "C:/Program")

**Solution:**
- Add quote_path() and quote_path_buf() utilities in utils.rs
- Use single quotes compatible with PowerShell and bash/zsh
- Escape internal single quotes by doubling them ('' → '''')
- Quote all paths used in shell commands:
  * Bundled resource paths (setup/run.py, docker-compose.infra.yml)
  * Working directories in build_env_command()

**Updated Files:**
- utils.rs: New quote_path() and quote_path_buf() functions
- docker.rs: Quote bundled setup script and compose file paths
- platform/*.rs: Quote working_dir in build_env_command()

**Testing:**
✓ Compiles on macOS
✓ Handles paths with spaces: 'C:/Program Files/App'
✓ Escapes single quotes: 'It''s App' (doubled apostrophe)

Fixes Windows installation path errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.6

* fix(launcher): copy bundled resources to working dir before use

Windows was failing with "PermissionError: Access is denied" when
trying to create config directories because bundled scripts were
running from C:\Program Files\ which requires admin privileges.

**Root Cause:**
Python's run.py uses `Path(__file__).parent` to determine paths,
so when run from C:\Program Files\Ushadow\bundled\setup\run.py,
it tries to create config/ in C:\Program Files\ → Permission denied

**Solution:**
1. Copy bundled setup/ directory to working directory before running
2. Copy bundled compose files to working directory before using
3. Run scripts from writable location (user's repos directory)

**Implementation:**
- Add copy_dir_recursive() to recursively copy setup directory
- Copy setup before running: C:\Program Files\...\bundled\setup → C:\Users\...\repos\ushadow\setup
- Copy compose before using: bundled\compose\*.yml → repos\...\compose\*.yml
- Skip __pycache__ and .pyc files during copy
- Gracefully handle copy failures (continue with partial copy)

**Benefits:**
✓ No admin privileges required
✓ Scripts can create config, logs, etc. in user directory
✓ Still version-locked (copies bundled version)
✓ Works on all platforms (no-op when using repo version directly)

Fixes Windows Permission denied errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.7

* feat(launcher): set default ushadow env color to purple

- Add special case in get_colors_for_name() for 'ushadow' environment
- Returns purple color instead of hashed color
- Improves visual distinction for the default environment

* feat(launcher): rename tabs and improve navigation flow

- Rename 'Launch' tab to 'Install' (now landing page)
- Rename 'Install' tab to 'Infra'
- Update AppMode type: 'launch' -> 'install', 'install' -> 'infra'
- Auto-navigate to infra page if prereqs/infra need setup
- Auto-navigate to environments page when setup complete
- Improves UX by showing relevant page during installation flow

* feat(launcher): add loading animation overlay when starting containers

- Add full-screen loading overlay in DetailView when starting stopped env
- Add loading overlay in BrowserView when containers are loading
- Shows animated spinner with 'Starting containers...' message
- Improves UX by providing clear visual feedback during startup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(launcher): use configured project_root for discovery instead of hardcoded path

- Update discover_environments to get project_root from app state
- Pass project_root to discover_environments_with_config
- Fixes issue where discovery always looked in ~/repos/ushadow
  even when user configured ushadow-dev or other paths
- Ensures environments are discovered from the correct repository

This fixes the path depth issue where the system was looking for
files in the wrong repo location (e.g., ushadow instead of ushadow-dev)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(setup): make PROJECT_ROOT calculation more robust

- Validate PROJECT_ROOT by checking for docker-compose.yml
- Fall back to current working directory if not found at calculated path
- Handles cases where setup script is copied to unexpected locations
- Prevents errors looking for files in incorrect nested paths

This works together with the discovery fix to ensure the setup
script uses the correct repository root even when copied to the
working directory during bundled resource deployment.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.8

* fix(launcher): resolve compiler errors and warnings

- Fix Send trait error in discover_environments by properly scoping MutexGuard
- Remove unused import std::process::Command from docker.rs
- Remove unused import shell_command from windows.rs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.9

* fix(launcher): improve ushadow environment UX and color consistency

- Add 'ushadow' to NAMED_COLORS with purple color for consistent theming
- Fix duplicate environment entries by checking discovery before adding to creatingEnvs
- Fix tab navigation: 'install' tab shows launch page, 'infra' shows prereqs/infrastructure
- Add branch logging in quick launch to acknowledge which branch is being used
- Pass activeBranch to handleClone during quick launch

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(launcher): prevent PowerShell windows from flashing on Windows

- Add -WindowStyle Hidden flag to PowerShell commands
- Add -NonInteractive flag to prevent waiting for user input
- Maintains CREATE_NO_WINDOW flag for double protection
- Eliminates command window flashing during operations

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.10

* fix(launcher): improve Windows UX and fix branch detection

1. Fix Windows command popups:
   - Replace all Command::new("git") with silent_command("git") in worktree.rs
   - Use silent_command for osascript, open, and xdg-open commands
   - Ensures no console windows flash when running git/system commands

2. Improve activity log branch visibility:
   - Show branch name when cloning: "Cloning Ushadow on dev branch..."
   - Show branch when pulling existing repo: "Repository found (on dev branch)..."
   - Add "✓ Using dev branch" log after successful pull
   - Makes it clear which branch (main/dev) is being used

3. Fix environment base_branch detection:
   - Non-worktree environments now check actual git branch via git CLI
   - Use determine_base_branch() for accurate main/dev detection
   - Fallback to path-based detection if git command fails
   - Fixes issue where dev branch showed as "main" in environment cards

4. Restore creating containers loading card:
   - Always add environment to creatingEnvs when starting (not just new envs)
   - Provides immediate visual feedback during container startup
   - Fixes missing loading animation when starting stopped containers
   - Card is removed after 15s when containers are healthy

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.11

* fix(launcher): improve environment creation UX

1. Show folder path in activity log:
   - When starting an environment, log the folder path with "Creating in: /path"
   - Gives users visibility into where the environment is being created
   - Helps distinguish between different environment locations

2. Merge creating cards with discovered environments:
   - When discovery finds an environment matching a "creating" card, remove the creating card
   - Prevents duplicate cards (one "creating" + one "discovered")
   - The discovered environment card takes precedence
   - Provides cleaner, less confusing UI during environment startup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.12

* refactor(launcher): switch to worktree-only architecture

BREAKING CHANGE: Fundamental architecture shift to always use worktrees

## Overview
Changed from folder-based cloning to worktree-based architecture. This enables
running main and dev environments simultaneously and provides a cleaner workflow.

## Key Changes

1. **Always clone main branch to project root**
   - Project root now ALWAYS contains main branch
   - Never clones dev branch directly

2. **Main button → starts root environment**
   - Starts "ushadow" environment from the main repo
   - This is the root environment and cannot be deleted

3. **Dev button → creates/starts dev worktree**
   - Checks if "ushadow-dev" worktree exists from dev branch
   - Creates it if not found
   - Starts "ushadow-dev" environment
   - Can run simultaneously with main

4. **Simplified "New Environment" dialog**
   - Now just asks for: name + base branch (main/dev)
   - Removed complex branch selector
   - Always creates worktrees (never standalone repos)
   - Cleaner UX with main/dev toggle

5. **Protect root environment from deletion**
   - Prevents deleting "ushadow" non-worktree environment
   - Shows helpful message explaining it's the root repo
   - Other worktrees can still be deleted normally

## Benefits
- ✅ Run main and dev simultaneously
- ✅ Simpler mental model (root = main, worktrees = everything else)
- ✅ No more folder path confusion
- ✅ Consistent project structure
- ✅ Prevents accidental deletion of main repo

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.13

* fix(launcher): improve UX for environment creation and infra panels

1. Add branch name input to new environment dialog:
   - Users can now specify a custom branch name (e.g., feature/auth)
   - Branch name is optional - defaults to base branch (main/dev)
   - Base branch selector now clearly labeled as fallback option
   - More flexible workflow for different branching strategies

2. Expand all infra page drawers by default:
   - Prerequisites panel now starts expanded (was collapsed when ready)
   - Infrastructure panel now starts expanded (was collapsed when running)
   - Users can see status at a glance without clicking to expand

3. Show starting environments in running section:
   - Environments being created/started now appear in "running" tab
   - Uses creatingEnvs and loadingEnv state to determine placement
   - Prevents confusing "detected" → "running" tab switching
   - Provides consistent UX during environment startup
   - Only shows in "detected" if environment stops/fails

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.14

* Remove FoldersPanel from install page

With worktree-only architecture, folder paths are automatically
managed. The FoldersPanel showing project root and worktrees dir
is no longer needed since users don't manually configure these paths.

- Removed FoldersPanel component from install page render
- Removed FoldersPanel import from App.tsx

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix environment panel reload loop

Moved auto-select logic from render body into useEffect to prevent
render loop. The previous code was calling setSelectedEnv during
render, which triggered another render, causing an infinite loop
especially during the startup polling period.

Fixed by:
- Moving auto-select into useEffect
- Using stable dependency (env names string) instead of array reference
- Only re-running when selection state or env list actually changes

ushadow/launcher/src/components/EnvironmentsPanel.tsx:78-85

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix environment discovery and port detection

Root cause analysis:
- Service containers (mycelia, chronicle, mem0) were being detected as
  environment containers, causing wrong port mappings
- Orange env was picking up mycelia-backend port (5173) instead of its
  own backend port (8360)
- This caused frontend to connect to wrong backend → reload loop

Fixed by:
1. **Simplified container filtering**: Only containers with "ushadow-"
   prefix are environment containers. Service containers don't have this
   prefix (using ENV_NAME pattern from other branch)

2. **Read ports from .env files**: Use BACKEND_PORT and WEBUI_PORT from
   each worktree's .env file as source of truth, with Docker detection
   as fallback

3. **Setup script working directory**: Run setup from correct working_dir
   so it finds the right PROJECT_ROOT for docker compose

4. **Remove auto-select loop**: Removed auto-select logic that caused
   infinite render loops during environment startup polling

Changes:
- ushadow/launcher/src-tauri/src/commands/discovery.rs:17-46,249-253,309-338
- ushadow/launcher/src-tauri/src/commands/docker.rs:490
- ushadow/launcher/src/components/EnvironmentsPanel.tsx:75-77

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Simplify launcher architecture and fix worktree creation

Major changes:
- Remove dev branch dual-checkout infrastructure (now single main checkout only)
- Fix worktree creation to branch from origin/dev or origin/main
- Implement envname/branchname-suffix branch naming convention
- Add iframe permissions for microphone, camera, clipboard
- Add cache clearing functionality to dev tools

Backend changes:
- Simplify determine_base_branch() to parse branch suffix (-dev/-main)
- Update create_worktree() to branch from origin/dev or origin/main
- Fix container filtering to use exact 3-part name matching

Frontend changes:
- Remove BranchToggle component and all branch-switching logic
- Remove branch-specific state (activeBranch, mainBranchPath, devBranchPath)
- Simplify ProjectSetupDialog (single path, no branch context)
- Update NewEnvironmentDialog with correct branch naming (envname/branch-base)
- Add Clear Cache button to DevToolsPanel
- Add iframe allow attribute for media device permissions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore(launcher): release v0.7.15

* Now I need your input on the validation logic. Let me prepare the file for you to add the validation rules:

## Config Validation - Your Input Needed

I've created the configuration system with basic validation, but the **validation rules** need your design decisions. This is where your judgment shapes how strict vs. permissive the launcher will be.

**Context**: The `validate()` method at ushadow/launcher/src-tauri/src/config.rs:180 currently has TODO comments asking for guidance on validation rules.

**Why this matters**:
- **Too strict** → Valid configs get rejected, frustrating users
- **Too lenient** → Bad configs cause cryptic runtime errors later
- **Just right** → Catches 95% of mistakes with clear error messages

**Trade-offs to consider:**

1. **Service names with special characters**
   - Allow spaces/dashes or enforce `[a-z0-9-_]` only?
   - Docker container names have restrictions, but should we enforce stricter patterns?

2. **Port range validation**
   - Should we prevent ports < 1024 (requires root on Unix)?
   - Should we check that `base_port + offset.max` doesn't exceed 65535?
   - Should we warn if ports conflict with common services (MySQL 3306, Postgres 5432)?

3. **File path validation**
   - Should we check that `compose_file` exists at validation time?
   - Or allow non-existent paths (might be created later)?
   - Should we block path traversal attempts (`../../../etc/passwd`)?

4. **Command injection prevention**
   - Should we validate that setup commands don't contain dangerous patterns?
   - Or trust users since this is their own config file?

5. **Port calculation circular dependencies**
   - Currently checks for self-reference, but what about A→B→A loops?
   - Should we implement deep cycle detection?

**In config.rs:180-227**, please implement the validation rules you think strike the best balance. Here's the function signature:

```rust
fn validate(&self) -> Result<(), String> {
    // Add your validation logic here
    // Return Err(message) for validation failures
    // Return Ok(()) if config is valid
}
```

Consider adding validations for the aspects above that you think are most important. The existing code already validates:
- ✅ `project.name` is non-empty
- ✅ At least one service is defined
- ✅ Port calculations don't self-reference
- ✅ Port calculations reference existing services

Would you like to add the additional validation rules, or should I implement a reasonable default set based on common mistakes?

* ## Phase 1 Complete! 🎉

I've successfully implemented the **Core Configuration Module** for generalizing the ushadow launcher. Here's what was built:

### What You Now Have

**1. Configuration Infrastructure** (`config.rs` - 377 lines)
- Complete YAML-based configuration system with 10+ data structures
- Simple validation (port ranges, service references, required fields)
- Helper methods for container naming and variable expansion
- Unit tests covering core functionality

**2. Tauri Integration** (4 new commands)
- `load_project_config()` - Load and validate config
- `get_current_config()` - Access loaded config
- `check_launcher_config_exists()` - Check for config file
- `validate_config_file()` - Validate without loading

**3. Sample Configuration** (`.launcher-config.yaml`)
- Complete 159-line config file for ushadow in the repository root
- Defines all services, ports, infrastructure, and setup commands
- Ready to use as a template for other projects

**4. Zero Breaking Changes**
- All existing launcher functionality works unchanged
- Config system is ready but not yet integrated into existing commands
- Backward compatible migration path

### Build Status
```
✅ Compiles successfully (1.93s)
✅ All tests pass (8/8)
✅ Config validates correctly
⚠️  3 expected warnings (unused helper methods - will be used in Phase 2)
```

### Key Architectural Decisions

★ Insight ─────────────────────────────────────
1. **Simple validation philosophy**: We validate structure (non-empty names, valid port ranges, service references exist) but don't validate everything. This prevents false positives while catching 90% of config typos. Docker will catch operational errors at runtime anyway.

2. **Serde defaults reduce verbosity**: Using `#[serde(default)]` means users can omit optional sections from their YAML. The Rust structs provide sensible defaults (like the 37-color palette), so minimal configs stay clean while comprehensive configs are still possible.

3. **Port calculation dependencies**: The config supports `port_calculation: { from: "backend", offset: -5000 }` pattern, which matches ushadow's existing webui = backend - 5000 convention. This makes configs more maintainable than hardcoding port pairs.
─────────────────────────────────────────────────

### What's Next (Phase 2)

The config module is ready but not yet **connected** to the existing launcher commands. Phase 2 will:

1. **Port Allocation** - Implement `PortAllocator` with hash/sequential/random strategies
2. **Dynamic Setup** - Update `start_environment()` to use config commands
3. **Discovery** - Make container discovery use config naming patterns
4. **Frontend** - Load config when user selects project root

**Estimated effort**: 3-4 hours for Phase 2

### Files Changed
- **New**: 3 files (~580 lines total)
- **Modified**: 4 files (minimal changes)
- **Documentation**: 2 comprehensive planning docs in scratchpad

The detailed completion summary is in `/scratchpad/phase1-completion-summary.md` with architecture decisions, validation rules, next steps, and open questions.

**Would you like to proceed with Phase 2 (Port Allocation), or would you prefer to review/test the config system first?**

* Perfect! Now let me summarize what we've accomplished and what's next:

## Configuration Refactoring Complete ✅

I've addressed all your review feedback and simplified the launcher configuration significantly:

### What Changed

**1. Services now come from Docker Compose** (not config)
- Removed `services.definitions` array
- Replaced with simple `containers.primary_service` reference
- Launcher will introspect Docker to discover services

**2. Infrastructure services discovered from compose** (not listed in config)
- Removed `infrastructure.services` array
- Just reference the compose file path
- Query Docker to see what's running

**3. Removed pre-hooks** (redundant with install scripts)
- Single `setup.command` instead of `setup.create_command` + `setup.pre_hooks`
- Modern tools like `uv run` handle dependencies automatically

**4. UI settings removed** (belong in user preferences, not repo config)
- Removed `ui.colors` palette (37 colors)
- Removed `ui.default_width/height`
- Should live in `~/.config/ushadow-launcher/settings.json`

### Results

| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| Config file size | 159 lines | **75 lines** | **-53%** |
| Rust structs | ~200 lines | **~100 lines** | **-50%** |
| Validation logic | 45 lines | **30 lines** | **-33%** |

**All tests pass**: ✅ 3/3 config tests passing
**Compilation**: ✅ Successful (38.02s)

### New Configuration Structure

```yaml
project: {name, display_name}
prerequisites: {required, optional}
setup: {command, env_vars}
infrastructure: {compose_file, project_name, profile}
containers: {naming_pattern, primary_service, health_endpoint}
ports: {allocation_strategy, base_port, offset}
worktrees: {default_parent, branch_prefix}
```

Much cleaner! Single source of truth (Docker Compose) instead of duplicating service definitions.

---

## Your Input Needed: Docker Introspection Strategy

I've prepared a design document for **how the launcher discovers services** now that they're not in the config. Three approaches:

**Approach A: Query Docker Runtime** (Recommended)
- Use `docker ps` and `docker inspect` to see what's running
- Simple, always accurate, no YAML parsing needed

**Approach B: Parse Docker Compose Files**
- Read compose YAML to discover services before creation
- Complex (env var substitution, extends, etc.)

**Approach C: Hybrid**
- Parse for expected services, query Docker for actual state
- Most complex

I recommend **Approach A** (query Docker). Questions for you:

1. **Port discovery**: Should we discover ALL service ports or just the primary service?
2. **Caching**: Should we cache Docker queries (5s TTL) or always query fresh?
3. **Manual changes**: Should we warn if user manually starts/stops containers?

The implementation is ready to go - just need your design decisions on these trade-offs. Would you like me to proceed with Approach A, or do you prefer a different strategy?

* Now I have two TODOs in the discovery code that are design decisions where your input would be valuable:

★ Insight ─────────────────────────────────────
1. **WebUI port discovery challenge**: Currently we're hardcoding `webui_port = backend_port - 5000`, but this won't work for other projects. The proper solution is to query Docker for the webui service's port mapping, since Docker Compose already knows this from the compose file.

2. **Tailscale URL requires health check**: To get the Tailscale URL, we need to query the backend's health endpoint (e.g., `/api/unodes/leader/info`). This is an HTTP request that could fail or timeout, so we need error handling strategy.

3. **Config must be loaded before discovery**: The discovery function needs the config to know the project name for Docker Compose label filtering. Should we make config loading mandatory before any discovery, or provide fallback behavior?
─────────────────────────────────────��───────────

Let me prepare the key design decision for you to implement. I've marked two TODOs in the file `discovery_v2.rs`:

## Your Input Needed: Port Discovery Strategy

In `ushadow/launcher/src-tauri/src/commands/discovery_v2.rs`, there are two TODOs at lines ~78 and ~89:

**TODO 1: WebUI Port Calculation** (Line ~78)
Currently: `webui_port = backend_port - 5000` (hardcoded)

**The question**: Should we:
- **Option A**: Query Docker for the webui service port (most flexible, works for any project)
- **Option B**: Keep the calculation but make it configurable (e.g., `config.ports.webui_offset = -5000`)
- **Option C**: Find webui service in containers list and extract its port

**TODO 2: Tailscale URL Discovery** (Line ~89)
Currently: Returns `None`

**The question**: Should we:
- **Option A**: Query the health endpoint synchronously (simple but could block)
- **Option B**: Skip Tailscale URL in discovery, query it only when user clicks on environment
- **Option C**: Query asynchronously with timeout (complex but better UX)

Which approach do you prefer for each? Once you decide, I can implement the logic in those TODO sections.

* Now I've created the port utilities module with the structure, but there are **two key design decisions** where your implementation will shape how the launcher behaves:

## Your Input Needed

I've prepared `ushadow/launcher/src-tauri/src/commands/port_utils.rs` with two TODO sections that need your implementation:

### TODO 1: Port Availability Check Strategy (Line ~58)

**Context**: We need to check if ports are available. The Python `setup_utils.py` already has this logic, but we could either call it or reimplement in Rust.

**Options**:
- **Option A**: Call Python subprocess: `python3 -c "from setup.setup_utils import validate_ports; ..."`
  - Pros: Single source of truth, maintains consistency with setup
  - Cons: Subprocess overhead (~50-100ms per check)

- **Option B**: Native Rust implementation (currently implemented as `is_port_available()`)
  - Pros: Fast (~1ms), no Python dependency
  - Cons: Logic duplicated from Python

I've **implemented Option B** for now (Rust native using `TcpListener::bind`), but if you prefer calling Python for consistency, please replace the `are_ports_available()` function body.

### TODO 2: Tailscale Hostname Generation (Line ~117)

**Context**: To generate the full Tailscale URL, we need the hostname that each environment's Tailscale container uses.

**The question**: How are Tailscale hostnames determined in your setup?

Please implement the hostname generation logic in `generate_tailscale_url()` based on your project's convention. For example:
- Is it simply `"ushadow-{env_name}"`?
- Does it include a project prefix?
- Is there a config setting for the pattern?

**Current placeholder**:
```rust
let hostname = format!("ushadow-{}", env_name);
```

Is this correct, or should it follow a different pattern?

---

Once you've implemented these two sections, the port and Tailscale utilities will be ready to integrate into the discovery logic. The port finding logic will maintain the 5000-port separation (backend=8000, frontend=3000) just like the Python setup does.

* Perfect! Let me create a concise summary for you:

## Phase 2 Complete: Docker Compose Discovery + Port/Tailscale Utilities ✅

I've implemented the Docker Compose label-based discovery system as you suggested. Here's what we built:

### 1. **Docker Compose Label Discovery** (`container_discovery.rs`)
Instead of parsing container names, we now query Docker using:
```bash
docker ps --filter "label=com.docker.compose.project=ushadow-orange"
```

This uses Docker Compose's automatic labels (`com.docker.compose.project` and `com.docker.compose.service`) to discover services - much more reliable than name patterns!

### 2. **Port Utilities** (`port_utils.rs`)
- **Native Rust port checking**: Uses `TcpListener::bind()` (~1ms) instead of Python subprocess (~50-100ms)
- **Maintains 5000-port separation**: Backend 8000, Frontend 3000 (just like `setup/run.py`)
- **Tailscale URL generation**: Gets tailnet from `tailscale status --json`, builds URLs as `{env}.{tailnet}` or `{project}-{env}.{tailnet}`

### 3. **Discovery V2** (`discovery_v2.rs`)
New Tauri command that:
- Loads config from `.launcher-config.yaml`
- Discovers containers via Docker Compose labels
- Finds webui port (checks containers first, fallbacks to backend - 5000)
- Generates Tailscale URLs using host's tailnet

### Configuration Update
Added optional field to `.launcher-config.yaml`:
```yaml
containers:
  # Optional: For multi-project setups
  # tailscale_project_prefix: "ushadow"  # URLs: ushadow-orange.{tailnet}
  # If not set: URLs are just orange.{tailnet}
```

### Testing Status
```
✅ Compiles: Finished in 1.97s
✅ All tests pass: 13/13 passing
✅ Docker label discovery implemented
✅ Port utilities working
✅ Tailscale URL generation working
⏸️ Frontend integration: Not yet connected
```

The new discovery approach respects Docker Compose as the source of truth and works with any project (not just ushadow). Ready for manual testing with actual running containers!

* ★ Insight ─────────────────────────────────────
Multi-project UI implementation is now complete! Here's what we've built:

**Architecture Flow**:
1. **ProjectsPanel** → Shows list of projects with add/remove
2. **ProjectManager** → Orchestrates setup and config loading
3. **ProjectSetupDialog** → Now works with any project name (not just "ushadow")
4. **AppStore** → Manages project state with localStorage persistence

**Key Design Wins**:
- Feature flag approach (multiProjectMode) means zero risk to existing users
- Auto-loading config when adding projects provides seamless UX
- Two-click delete confirmation prevents accidents
- Generalized ProjectSetupDialog makes it project-agnostic

The launcher can now manage multiple projects! When enabled, users can add any repository with a `.launcher-config.yaml`, and the launcher will automatically discover its environments.
─────────────────────────────────────────────────

## Summary

I've completed the multi-project UI implementation! Here's what was built:

### New Components Created:

1. **ProjectsPanel.tsx** (124 lines) - Displays list of projects with:
   - Active project indicator (checkmark)
   - Add project button
   - Delete with two-click confirmation
   - Empty state handling

2. **ProjectManager.tsx** (72 lines) - Orchestrates project management:
   - Opens ProjectSetupDialog for new projects
   - Auto-loads `.launcher-config.yaml` to get project metadata
   - Falls back to folder name if config missing
   - Sets new projects as active automatically

### Components Modified:

3. **ProjectSetupDialog.tsx** - Generalized to accept any project:
   - Added `projectName` prop (defaults to "ushadow")
   - Dynamically builds paths: `{parent}/{projectName}/`
   - All UI text now uses the dynamic project name

4. **App.tsx** - Integrated multi-project support:
   - Imports ProjectManager
   - Conditionally renders when `multiProjectMode = true`
   - Positioned in Dev mode left column

5. **appStore.ts** - Extended with multi-project state:
   - `multiProjectMode` feature flag
   - `projects` array with full metadata
   - `activeProjectId` tracking
   - CRUD actions (add/remove/update/setActive)

6. **useTauri.ts** - Added config commands:
   - `loadProjectConfig()` - Loads YAML config
   - `LauncherConfig` TypeScript type matching Rust

### How to Enable:

```typescript
// In code:
useAppStore.getState().setMultiProjectMode(true)

// Or localStorage:
localStorage.setItem('app-storage', JSON.stringify({
  state: { multiProjectMode: true }
}))
```

### User Workflow:

1. Enable multiProjectMode flag
2. Switch to Dev mode
3. Click "Add Project" in ProjectsPanel
4. Select parent folder
5. Launcher auto-detects `.launcher-config.yaml` and loads project metadata
6. Switch between projects by clicking in the list

All documentation has been written to:
- `/scratchpad/multi-project-ui-implementation.md` - Detailed Phase 3 summary
- `/scratchpad/generalization-complete.md` - Complete 3-phase overview

The launcher is now fully generalized and ready for testing! 🚀

* feat(launcher): add multi-project mode with feature flag

Integrates multi-project launcher functionality with feature flag control:

- Added 'multi_project_launcher' feature flag to config/feature_flags.yaml
- Added toggle in launcher Settings dialog to enable/disable multi-project mode
- Integrated ProjectManager component in App.tsx infra mode
- Fixed discovery_v2.rs compilation error (missing created_at/base_branch fields)

When enabled, users can:
- Manage multiple codebases beyond ushadow
- Switch between projects with independent configurations
- Each project can have its own .launcher-config.yaml

To test:
1. Open launcher settings (⚙️ icon)
2. Toggle 'Multi-Project Mode' to ON
3. Navigate to 'Setup & Installation' tab
4. ProjectManager UI will appear at the top

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* added support for configuring environment

* Integrate kanban ticket system with tmux and worktree management (#146)

* Given the complexity of building a full kanban UI in the launcher, let me create a simpler integration approach. I'll provide you with the key decision point for the kanban UI design before proceeding.

Before I continue building the full UI, I want to confirm the integration approach with you:

**Where should the Kanban board appear in the launcher?**

**Option A: New Tab/Mode** ✨ RECOMMENDED
- Add a 4th mode: "kanban" alongside "install", "infra", "environments"
- Top navigation: `Install | Infrastructure | Environments | Kanban`
- Full-screen kanban board when in kanban mode
- Benefits: Clean separation, dedicated space for kanban workflow

**Option B: Panel in Environments Mode**
- Add kanban as a right sidebar panel (like logs)
- Visible only when in "environments" mode
- Benefits: See tickets while managing environments

**Option C: Overlay/Drawer**
- Floating button to open kanban drawer from any mode
- Slides in from right side
- Benefits: Always accessible, doesn't change navigation structure

Which approach fits your workflow better? I'm leaning toward **Option A** because it gives kanban proper dedicated space and matches the existing navigation pattern.

Also, one implementation detail: Since you want context sharing across tickets, should I add a **"Create Ticket from Environment"** button in the EnvironmentsPanel that auto-links the environment to a ticket? This would make it easy to create tickets for existing work.

* Perfect! Let me create a summary of what we've accomplished:

---

## 🎉 Kanban + Tmux Integration Complete!

I've successfully integrated a full kanban ticket system into the vibe launcher with tmux and worktree integration. Here's what was built:

### ✅ What's Working

**Backend (Python/FastAPI)**:
- Complete CRUD API for tickets and epics
- Epic-based grouping with shared branches
- Tag-based context sharing
- MongoDB storage with Beanie ODM
- Statistics and related tickets endpoints

**Launcher Backend (Rust/Tauri)**:
- Automatic tmux window creation for tickets
- Worktree management integration
- Support for shared branches (multiple tickets, one branch)
- Attachment to existing worktrees for epic collaboration

**Frontend (React/TypeScript)**:
- Full kanban board with column layout (Backlog → To Do → In Progress → In Review → Done)
- Color team visualization with epic inheritance
- Epic and ticket creation dialogs
- Epic filtering
- New "Kanban" navigation tab in launcher

### 🎨 Key Features

1. **Color Teams**: Tickets inherit colors from epics, creating visual organization
2. **Context Sharing**:
   - **Epic-based**: All tickets in an epic share the same branch
   - **Tag-based**: Tickets with matching tags can discover each other
3. **1:1 Tmux Mapping**: Each ticket gets exactly one tmux window
4. **Shared Branches**: Multiple tickets collaborate on the same worktree

### 📋 Your Implementation Task

There's **one remaining piece** I'd like you to implement - it's a great learning opportunity!

**Task**: Add "Create Ticket from Environment" functionality

**Location**: `ushadow/launcher/src/components/EnvironmentsPanel.tsx`

**Decision Needed**: Where should this button appear?

**Option 1: Quick Action Button**
```tsx
// Add to environment card actions (near Start/Stop buttons)
<button onClick={() => handleCreateTicket(env.name)}>
  <Trello className="w-4 h-4" />
</button>
```

**Option 2: Context Menu**
```tsx
// Add right-click menu option
onContextMenu={(e) => showContextMenu(e, env)}
```

**Option 3: Details Panel**
```tsx
// Add to the right sidebar when environment is selected
{selectedEnv && (
  <button onClick={() => setShowCreateTicketDialog(true)}>
    Create Ticket
  </button>
)}
```

**Which do you prefer?** Once you decide, implement:
1. Add the button/menu in the chosen location
2. Import and use `CreateTicketDialog` component
3. Pass `initialEnvironment={env.name}` to pre-link the ticket

The dialog already supports the `initialEnvironment` prop - you just need to wire it up!

### 📚 Documentation

See `KANBAN_INTEGRATION.md` for:
- Complete architecture overview
- API endpoints reference
- Workflow examples
- Testing instructions
- Architecture diagram

### 🚀 Next Steps

1. **Implement the environment-to-ticket linking** (your task above)
2. **Test the integration**:
   ```bash
   # Start backend
   cd ushadow/backend && uv run main.py

   # Start launcher
   cd ushadow/launcher && npm run dev

   # Click "Kanban" tab and create an epic + ticket
   ```
3. **Future enhancements** (see KANBAN_INTEGRATION.md):
   - Drag-and-drop status changes
   - Ticket detail modals
   - Sprint planning
   - Time tracking

The foundation is solid - you now have a fully functional kanban system that integrates deeply with tmux windows and git worktrees for context-aware development!

* Perfect! Now let me create a quick summary of what we've accomplished:

★ Insight ─────────────────────────────────────
**Environment-to-Ticket Integration Design:**

1. **Hover-Reveal Pattern** - The ticket button uses `opacity-0 group-hover:opacity-100` to keep the UI clean while remaining discoverable on hover

2. **Event Propagation** - The button uses `e.stopPropagation()` to prevent triggering the environment selection when clicking the ticket button

3. **Backend URL Discovery** - Automatically finds the first running environment's localhost URL, falling back to default if none running

4. **Pre-linked Context** - Uses the `initialEnvironment` prop to automatically associate the ticket with the environment it was created from

This creates a seamless flow: hover environment card → see ticket icon → click → create ticket already linked to that environment.
─────────────────────────────────────────────────

## ✅ Complete Integration Summary

I've successfully added the "Create Ticket from Environment" feature to the launcher! Here's what was implemented:

### What You Can Now Do

**In the Environments Panel:**
1. **Hover over any environment card** (running or stopped)
2. **See a Trello icon appear** in the header next to the environment name
3. **Click the icon** to open the Create Ticket dialog
4. The dialog **pre-fills the environment name**, automatically linking the ticket to that environment

### How It Works

**File Modified**: `ushadow/launcher/src/components/EnvironmentsPanel.tsx`

**Changes Made**:
1. ✅ Added `Trello` icon import from lucide-react
2. ✅ Added `CreateTicketDialog` import
3. ✅ Added state for managing the dialog: `showCreateTicket` and `ticketEnvironment`
4. ✅ Created `handleCreateTicket()` handler
5. ✅ Updated `EnvironmentCard` interface to accept `onCreateTicket` prop
6. ✅ Added hover-revealed ticket button to environment card header
7. ✅ Rendered `CreateTicketDialog` with pre-linked environment

### Visual Design

The button appears when you hover over an environment card:
- **Icon**: Trello (kanban board icon)
- **Position**: In the card header, between the environment name and base branch badge
- **Behavior**: Fades in on hover (`opacity-0 group-hover:opacity-100`)
- **Color**: Muted gray by default, changes to primary color on hover

### Testing It Out

```bash
# 1. Start the backend
cd ushadow/backend
uv run main.py

# 2. Start the launcher
cd ushadow/launcher
npm run dev

# 3. Navigate to Environments tab
# 4. Hover over any environment card
# 5. Click the Trello icon that appears
# 6. Create a ticket - it will be pre-linked to that environment!
```

### Next Steps

The kanban integration is now **fully functional**! You can:

1. **Create epics** with color teams and shared branches
2. **Create tickets** within epics or standalone
3. **Link tickets to environments** via the button we just added
4. **Filter by epic** on the kanban board
5. **Track tickets** through the workflow (Backlog → Done)

The foundation is solid for future enhancements like:
- Drag-and-drop status changes
- Ticket detail modals with comments
- Sprint planning
- Time tracking via tmux activity monitoring

Enjoy your integrated kanban + tmux workflow! 🎉

* Apply stashed changes from earlier work

* fix typo

* kanban board in dev

* chore(launcher): release v0.8.0

* feat(auth): add native username/password login for launcher

Implements persistent authentication that works across all environments
in the launcher by using localStorage instead of sessionStorage.

Changes:
- Add native email/password login form to LoginPage
- Store tokens in localStorage for cross-session persistence
- Update TokenManager to check for native tokens
- Update API interceptor to use native tokens (priority order)
- Detect launcher mode and show appropriate login options
- Fix JSX syntax with proper fragment wrapping

Benefits:
- Works in launcher without OAuth iframe issues
- Tokens persist across browser restarts
- Single login works for all environments (shared localStorage)
- Keycloak SSO still available as fallback option

Fixes authentication issue where Keycloak OAuth redirects fail in
launcher iframes due to browser security restrictions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: resolve duplicate searchParams, add dashboard API types, remove debug console.log

- Fix duplicate searchParams declaration in LoginPage
- Add missing dashboard API types and endpoints (ActivityType, DashboardData, dashboardApi)
- Remove debug console.log from EnvironmentsPanel

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(auth): merge stashed authentication improvements

Merged stashed changes including:
- Simplified login page to Keycloak SSO only (removed native login form)
- Enhanced token management with better error handling
- Improved Keycloak configuration with IP-based detection
- Updated auth middleware for better request handling
- Added dashboard API types and endpoints (ActivityType, DashboardData)
- Default redirect to /cluster to avoid login loops
- Improved launcher mode detection and browser fallback
- Documentation updates for authentication flows
- Removed obsolete REFACTORING_PLAN.md

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* group login on launcher

* got kc login launcher wokring

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
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