Complete the remaining pi-to-companion rename across companion-os, web, vm-orchestrator, docker, and archived fixtures. Verification: - semantic rg sweeps for Pi/piConfig/getPi/.pi runtime references - npm run check in apps/companion-os (fails in this worktree: biome not found) Co-authored-by: Codex <noreply@openai.com>
7.2 KiB
Implementation Plan: Separate Windows Mode for companion-teams
Goal
Implement the ability to open team members (including the team lead) in separate OS windows instead of panes, with window titles set to "team-name: agent-name" format.
Research Summary
Terminal Support Matrix
| Terminal | New Window Support | Window Title Method | Notes |
|---|---|---|---|
| iTerm2 | ✅ AppleScript create window with default profile |
AppleScript set name on session (tab) + escape sequences for window title |
Primary target; window title property is read-only, use escape sequence \033]2;Title\007 |
| WezTerm | ✅ wezterm cli spawn --new-window |
wezterm cli set-window-title or escape sequences |
Full support |
| tmux | ❌ Skipped | N/A | Only creates windows within session, not OS windows |
| Zellij | ❌ Skipped | N/A | Only creates tabs, not OS windows |
Key Technical Findings
-
iTerm2 AppleScript for New Window:
tell application "iTerm" set newWindow to (create window with default profile) tell current session of newWindow write text "printf '\\033]2;Team: Agent\\007'" -- Set window title via escape sequence set name to "tab-title" -- Optional: set tab title end tell end tell -
WezTerm CLI for New Window:
wezterm cli spawn --new-window --cwd /path -- env KEY=val command wezterm cli set-window-title --window-id X "Team: Agent" -
Escape Sequence for Window Title (Universal):
printf '\033]2;Window Title\007'
Implementation Phases
Phase 1: Update Terminal Adapter Interface
Status: pending
Files: src/utils/terminal-adapter.ts
- Add
spawnWindow(options: SpawnOptions): stringmethod toTerminalAdapterinterface - Add
setWindowTitle(windowId: string, title: string): voidmethod toTerminalAdapterinterface - Update
SpawnOptionsto include optionalteamName?: stringfor title formatting
Phase 2: Implement iTerm2 Window Support
Status: pending
Files: src/adapters/iterm2-adapter.ts
- Implement
spawnWindow()using AppleScriptcreate window with default profile - Capture and return window ID from AppleScript
- Implement
setWindowTitle()using escape sequence injection viawrite text - Format title as
{teamName}: {agentName} - Handle window lifecycle (track window IDs)
Phase 3: Implement WezTerm Window Support
Status: pending
Files: src/adapters/wezterm-adapter.ts
- Implement
spawnWindow()usingwezterm cli spawn --new-window - Capture and return window ID from spawn output
- Implement
setWindowTitle()usingwezterm cli set-window-title - Format title as
{teamName}: {agentName}
Phase 4: Update Terminal Registry
Status: pending
Files: src/adapters/terminal-registry.ts
- Add feature detection method
supportsWindows(): boolean - Update registry to expose window capabilities
Phase 5: Update Team Configuration
Status: pending
Files: src/utils/models.ts, src/utils/teams.ts
- Add
separateWindows?: booleantoTeamConfigmodel - Add
windowId?: stringtoMembermodel (for tracking OS window IDs) - Update
createTeam()to accept and storeseparateWindowsoption
Phase 6: Update spawn_teammate Tool
Status: pending
Files: extensions/index.ts
- Add
separate_window?: booleanparameter tospawn_teammatetool - Check team config for global
separateWindowssetting - Use
spawnWindow()instead ofspawn()when separate windows mode is active - Store window ID in member record instead of pane ID
- Set window title immediately after spawn using
setWindowTitle()
Phase 7: Create spawn_lead_window Tool (Optional)
Status: pending
Files: extensions/index.ts
- Create new tool
spawn_lead_windowto move team lead to separate window - Only available if team has
separateWindows: true - Set window title for lead as
{teamName}: team-lead
Phase 8: Update Kill/Lifecycle Management
Status: pending
Files: extensions/index.ts, adapter files
- Update
killTeammate()to handle window IDs (not just pane IDs) - Implement window closing via AppleScript (iTerm2) or CLI (WezTerm)
- Update
isAlive()checks for window-based teammates
Phase 9: Testing & Validation
Status: pending
- Test iTerm2 window creation and title setting
- Test WezTerm window creation and title setting
- Test global
separateWindowsteam setting - Test per-teammate
separate_windowoverride - Test window lifecycle (kill, isAlive)
- Verify title format:
{teamName}: {agentName}
Phase 10: Documentation
Status: pending
Files: README.md, docs/guide.md, docs/reference.md
- Document new
separate_windowparameter - Document global
separateWindowsteam setting - Add iTerm2 and WezTerm window mode examples
- Update terminal requirements section
Design Decisions
-
Window Title Strategy: Use escape sequences (
\033]2;Title\007) for iTerm2 window titles since AppleScript's window title property is read-only. Tab titles will use the sessionnameproperty. -
ID Tracking: Store window IDs in the same
tmuxPaneIdfield (renamed conceptually toterminalId) or add a newwindowIdfield to Member model. Decision: AddwindowIdfield to be explicit. -
Fallback Behavior: If
separate_window: trueis requested but terminal doesn't support it, throw an error with clear message. -
Lead Window: Team lead window is optional and must be explicitly requested via a separate tool call after team creation.
Open Questions
None - all clarified by user.
Errors Encountered
| Error | Attempt | Resolution |
|---|---|---|
| N/A | - | - |
Files to Modify
src/utils/terminal-adapter.ts- Add interface methodssrc/adapters/iterm2-adapter.ts- Implement window supportsrc/adapters/wezterm-adapter.ts- Implement window supportsrc/adapters/terminal-registry.ts- Add capability detectionsrc/utils/models.ts- Update Member and TeamConfig typessrc/utils/teams.ts- Update createTeam signatureextensions/index.ts- Update spawn_teammate, add spawn_lead_windowREADME.md- Document new featuredocs/guide.md- Add usage examplesdocs/reference.md- Update tool documentation