Feature Request: Focus/Activate Tab by WT_SESSION #24000

Open
opened 2026-01-31 08:58:39 +00:00 by claunia · 0 comments
Owner

Originally created by @shanselman on GitHub (Jan 25, 2026).

Feature Request: Focus/Activate Tab by WT_SESSION

The Problem

There's no way for an external process to programmatically switch to a specific Windows Terminal tab.

When a process running inside a terminal tab needs to bring the user back to that exact tab (not just the window), it's currently impossible. The wt.exe CLI can open new tabs and target windows, but cannot activate an existing tab by its session identifier.

Why This Matters Now: The AI Agent Era

2024-2025 has seen an explosion of AI coding agents that run in the terminal:

Agent Vendor Typical Task Duration
Claude Code Anthropic 30 sec - 10+ min
GitHub Copilot CLI GitHub/Microsoft 10 sec - 5 min
Gemini CLI Google 10 sec - 5 min
Aider Open Source 30 sec - 10 min
Cursor Anysphere Variable

These agents run autonomously—refactoring code, running tests, fixing bugs across multiple files. Users naturally alt-tab away while waiting. When the agent finishes:

  1. A notification appears ("Claude finished refactoring")
  2. User clicks the notification
  3. Windows Terminal comes to foreground...
  4. But the user is on the wrong tab and has to hunt for where the agent was running

With 5-10 tabs open across different projects, this is a real friction point.

Prior Art: Every Other Major Terminal Has This

tmux (Gold Standard)

# Direct tab/pane targeting by session ID
tmux select-window -t mysession:2
tmux select-pane -t mysession:2.3

# Query all sessions, windows, panes
tmux list-sessions
tmux list-windows -t <session>
tmux list-panes -t <session:window>

iTerm2 (macOS)

# Full Python API for programmatic control
import iterm2

async def main(connection):
    app = await iterm2.async_get_app(connection)
    window = app.current_terminal_window
    target_tab = window.tabs[2]
    await window.async_select_tab(target_tab)  # ← This is what we need

iterm2.run_until_complete(main)

Also supports AppleScript:

tell application "iTerm2"
    tell current window
        select tab 2
    end tell
end tell

Kitty (Linux/macOS)

# IPC via Unix socket - can focus tabs by index or match criteria
kitty @ focus-tab --match index:2
kitty @ focus-window --match title:myproject

# Query state
kitty @ ls  # Returns JSON of all windows, tabs, panes

Windows Terminal: The Gap

# We can do this:
wt.exe -w 0 nt                    # New tab in MRU window
wt.exe -w 2 split-pane            # Split in window 2

# We cannot do this:
wt.exe --focus-session $env:WT_SESSION   # ❌ Doesn't exist
wt.exe -w 0 focus-tab --index 3          # ❌ Doesn't exist
wt.exe --query-sessions                   # ❌ Doesn't exist

Technical Context

What Already Exists (The Building Blocks)

  1. WT_SESSION environment variable - Already set per tab/pane, unique GUID like 5720ee6d-6474-47b0-88db-fa7e10e60d37

  2. WT_PROFILE_ID environment variable - Profile GUID, useful but not unique per tab

  3. Window targeting via -w - Can target windows by ID or name, just not tabs within them

  4. Shell integration OSC sequences - Terminal already has rich bidirectional communication:

    OSC 133;A ST  - Start of prompt
    OSC 133;B ST  - Start of command input  
    OSC 133;C ST  - Command executed
    OSC 133;D;N ST - Command finished with exit code N
    OSC 9;9;CWD ST - Current working directory
    
  5. Internal tab management - Terminal obviously tracks tabs internally; just not exposed externally

Current Workarounds (All Fragile)

UI Automation - Enumerate TabItem elements, match by title, call SelectionItemPattern.Select():

// This works but is fragile
CComPtr<IUIAutomationElement> tabItem;
automation->CreatePropertyCondition(UIA_NamePropertyId, tabTitle, &condition);
terminalElement->FindFirst(TreeScope_Descendants, condition, &tabItem);
// Problem: Tab titles change, can be duplicated, user can rename

Keyboard simulation - Send Ctrl+Tab repeatedly:

// Extremely fragile, timing-dependent
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(VK_TAB, 0, 0, 0);
// Problem: No way to know when you've reached the right tab

Title matching via console API:

wchar_t title[1024];
GetConsoleTitleW(title, 1024);  
// Problem: Title ≠ Tab identity, changes with CWD, can be duplicated

Proposed Solution

Option A: New focus-tab Subcommand with Session Targeting

# Focus tab by its WT_SESSION GUID (most robust)
wt.exe focus-tab --session 5720ee6d-6474-47b0-88db-fa7e10e60d37

# Focus tab by index in current/specified window  
wt.exe focus-tab --index 2
wt.exe -w 0 focus-tab --index 2

Option B: Extend -w to Accept Session References

# Session becomes a first-class window/tab identifier
wt.exe -w session:5720ee6d-6474-47b0-88db-fa7e10e60d37 focus-tab

This aligns with @zadjii-msft's comment in #17963:

"I do have plans to have -w 0 do The Smart Thing, and figure out the right window ID based on the current WT_SESSION_ID"

Option C: Query Command (Enables Advanced Scenarios)

# Get structured info about sessions
wt.exe query --session 5720ee6d-6474-47b0-88db-fa7e10e60d37
# Output: {"window_id": 2, "tab_index": 3, "title": "pwsh - myproject"}

# List all sessions (tmux-style)
wt.exe query --list-sessions
# Output: [{"session": "5720ee6d-...", "window_id": 2, "tab_index": 3}, ...]

Real-World Use Case: Toasty Notification Tool

I'm building Toasty, a Windows toast notification CLI for AI coding agents. The workflow:

┌─────────────────────────────────────────────────────────────────┐
│  1. Claude Code runs in Tab 3, user alt-tabs to browser        │
│  2. Claude finishes → triggers hook → toasty shows toast       │
│  3. Toasty captures WT_SESSION="5720ee6d-..." at invocation    │
│  4. User clicks toast notification                              │
│  5. Toasty calls: wt.exe focus-tab --session 5720ee6d-...      │
│  6. ✓ User lands exactly in Tab 3 where Claude was running     │
└─────────────────────────────────────────────────────────────────┘

Current broken flow: Step 5 doesn't exist, so users land on whatever tab was last active and have to manually find their agent.

Hook Configuration (Already Supported)

Claude Code (~/.claude/settings.json):

{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "toasty.exe \"Claude finished\" --session %WT_SESSION%"
      }]
    }]
  }
}

GitHub Copilot (.github/hooks/toasty.json):

{
  "hooks": {
    "sessionEnd": [{
      "type": "command",
      "powershell": "toasty.exe 'Copilot finished' --session $env:WT_SESSION"
    }]
  }
}
Reference Status Relevance
#17963 Open Discussion WT_WINDOWID request; @zadjii-msft mentioned plans for session-aware -w 0
#10561 Open -w 0 not finding right window from quake mode
#16568 Open General programmatic API request (iTerm2-style)
#13006 Open WT_SESSION not set when Terminal is default terminal
#10708 Open Ability to identify pane IDs

Implementation Considerations

  1. Session → Window/Tab mapping - Terminal already maintains this internally for tab management

  2. Cross-process communication - Could use existing named pipe/COM infrastructure that wt.exe uses for -w targeting

  3. Focus stealing - Windows has restrictions; but Terminal already handles this for -w commands

  4. Backward compatibility - New subcommand/flag, no breaking changes

Summary

Terminal Focus Specific Tab? Query Sessions? API Maturity
tmux select-window -t list-sessions Production
iTerm2 Python API Full introspection Production
Kitty kitty @ focus-tab kitty @ ls Production
Windows Terminal Gap

Windows Terminal has all the internal machinery (WT_SESSION, window management, shell integration). The missing piece is exposing tab activation to external processes.

This feature would make Windows Terminal a first-class citizen for the emerging AI agent workflow—and close a gap that every other major terminal has already solved.

I'm Happy to Help

I'd be glad to:

  • Test preview builds
  • Provide detailed feedback
  • Contribute to implementation if pointed in the right direction
  • Help document the feature

Environment: Windows 11 24H2, Windows Terminal 1.21+, C++/WinRT

cc @crutkas

Originally created by @shanselman on GitHub (Jan 25, 2026). # Feature Request: Focus/Activate Tab by WT_SESSION ## The Problem **There's no way for an external process to programmatically switch to a specific Windows Terminal tab.** When a process running inside a terminal tab needs to bring the user back to *that exact tab* (not just the window), it's currently impossible. The `wt.exe` CLI can open new tabs and target windows, but cannot activate an existing tab by its session identifier. ## Why This Matters Now: The AI Agent Era 2024-2025 has seen an explosion of **AI coding agents** that run in the terminal: | Agent | Vendor | Typical Task Duration | |-------|--------|----------------------| | **Claude Code** | Anthropic | 30 sec - 10+ min | | **GitHub Copilot CLI** | GitHub/Microsoft | 10 sec - 5 min | | **Gemini CLI** | Google | 10 sec - 5 min | | **Aider** | Open Source | 30 sec - 10 min | | **Cursor** | Anysphere | Variable | These agents run autonomously—refactoring code, running tests, fixing bugs across multiple files. Users naturally **alt-tab away** while waiting. When the agent finishes: 1. A notification appears ("Claude finished refactoring") 2. User clicks the notification 3. Windows Terminal comes to foreground... 4. **❌ But the user is on the wrong tab** and has to hunt for where the agent was running With 5-10 tabs open across different projects, this is a real friction point. ## Prior Art: Every Other Major Terminal Has This ### tmux (Gold Standard) ```bash # Direct tab/pane targeting by session ID tmux select-window -t mysession:2 tmux select-pane -t mysession:2.3 # Query all sessions, windows, panes tmux list-sessions tmux list-windows -t <session> tmux list-panes -t <session:window> ``` ### iTerm2 (macOS) ```python # Full Python API for programmatic control import iterm2 async def main(connection): app = await iterm2.async_get_app(connection) window = app.current_terminal_window target_tab = window.tabs[2] await window.async_select_tab(target_tab) # ← This is what we need iterm2.run_until_complete(main) ``` Also supports AppleScript: ```applescript tell application "iTerm2" tell current window select tab 2 end tell end tell ``` ### Kitty (Linux/macOS) ```bash # IPC via Unix socket - can focus tabs by index or match criteria kitty @ focus-tab --match index:2 kitty @ focus-window --match title:myproject # Query state kitty @ ls # Returns JSON of all windows, tabs, panes ``` ### Windows Terminal: The Gap ```powershell # We can do this: wt.exe -w 0 nt # New tab in MRU window wt.exe -w 2 split-pane # Split in window 2 # We cannot do this: wt.exe --focus-session $env:WT_SESSION # ❌ Doesn't exist wt.exe -w 0 focus-tab --index 3 # ❌ Doesn't exist wt.exe --query-sessions # ❌ Doesn't exist ``` ## Technical Context ### What Already Exists (The Building Blocks) 1. **`WT_SESSION` environment variable** - Already set per tab/pane, unique GUID like `5720ee6d-6474-47b0-88db-fa7e10e60d37` 2. **`WT_PROFILE_ID` environment variable** - Profile GUID, useful but not unique per tab 3. **Window targeting via `-w`** - Can target windows by ID or name, just not tabs within them 4. **Shell integration OSC sequences** - Terminal already has rich bidirectional communication: ``` OSC 133;A ST - Start of prompt OSC 133;B ST - Start of command input OSC 133;C ST - Command executed OSC 133;D;N ST - Command finished with exit code N OSC 9;9;CWD ST - Current working directory ``` 5. **Internal tab management** - Terminal obviously tracks tabs internally; just not exposed externally ### Current Workarounds (All Fragile) **UI Automation** - Enumerate TabItem elements, match by title, call `SelectionItemPattern.Select()`: ```cpp // This works but is fragile CComPtr<IUIAutomationElement> tabItem; automation->CreatePropertyCondition(UIA_NamePropertyId, tabTitle, &condition); terminalElement->FindFirst(TreeScope_Descendants, condition, &tabItem); // Problem: Tab titles change, can be duplicated, user can rename ``` **Keyboard simulation** - Send Ctrl+Tab repeatedly: ```cpp // Extremely fragile, timing-dependent keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_TAB, 0, 0, 0); // Problem: No way to know when you've reached the right tab ``` **Title matching via console API**: ```cpp wchar_t title[1024]; GetConsoleTitleW(title, 1024); // Problem: Title ≠ Tab identity, changes with CWD, can be duplicated ``` ## Proposed Solution ### Option A: New `focus-tab` Subcommand with Session Targeting ```powershell # Focus tab by its WT_SESSION GUID (most robust) wt.exe focus-tab --session 5720ee6d-6474-47b0-88db-fa7e10e60d37 # Focus tab by index in current/specified window wt.exe focus-tab --index 2 wt.exe -w 0 focus-tab --index 2 ``` ### Option B: Extend `-w` to Accept Session References ```powershell # Session becomes a first-class window/tab identifier wt.exe -w session:5720ee6d-6474-47b0-88db-fa7e10e60d37 focus-tab ``` This aligns with @zadjii-msft's comment in #17963: > "I do have plans to have `-w 0` do The Smart Thing, and figure out the right window ID based on the current `WT_SESSION_ID`" ### Option C: Query Command (Enables Advanced Scenarios) ```powershell # Get structured info about sessions wt.exe query --session 5720ee6d-6474-47b0-88db-fa7e10e60d37 # Output: {"window_id": 2, "tab_index": 3, "title": "pwsh - myproject"} # List all sessions (tmux-style) wt.exe query --list-sessions # Output: [{"session": "5720ee6d-...", "window_id": 2, "tab_index": 3}, ...] ``` ## Real-World Use Case: Toasty Notification Tool I'm building [**Toasty**](https://github.com/shanselman/toasty), a Windows toast notification CLI for AI coding agents. The workflow: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. Claude Code runs in Tab 3, user alt-tabs to browser │ │ 2. Claude finishes → triggers hook → toasty shows toast │ │ 3. Toasty captures WT_SESSION="5720ee6d-..." at invocation │ │ 4. User clicks toast notification │ │ 5. Toasty calls: wt.exe focus-tab --session 5720ee6d-... │ │ 6. ✓ User lands exactly in Tab 3 where Claude was running │ └─────────────────────────────────────────────────────────────────┘ ``` **Current broken flow**: Step 5 doesn't exist, so users land on whatever tab was last active and have to manually find their agent. ### Hook Configuration (Already Supported) Claude Code (`~/.claude/settings.json`): ```json { "hooks": { "Stop": [{ "hooks": [{ "type": "command", "command": "toasty.exe \"Claude finished\" --session %WT_SESSION%" }] }] } } ``` GitHub Copilot (`.github/hooks/toasty.json`): ```json { "hooks": { "sessionEnd": [{ "type": "command", "powershell": "toasty.exe 'Copilot finished' --session $env:WT_SESSION" }] } } ``` ## Related Issues & Discussions | Reference | Status | Relevance | |-----------|--------|-----------| | **#17963** | Open Discussion | `WT_WINDOWID` request; @zadjii-msft mentioned plans for session-aware `-w 0` | | **#10561** | Open | `-w 0` not finding right window from quake mode | | **#16568** | Open | General programmatic API request (iTerm2-style) | | **#13006** | Open | `WT_SESSION` not set when Terminal is default terminal | | **#10708** | Open | Ability to identify pane IDs | ## Implementation Considerations 1. **Session → Window/Tab mapping** - Terminal already maintains this internally for tab management 2. **Cross-process communication** - Could use existing named pipe/COM infrastructure that `wt.exe` uses for `-w` targeting 3. **Focus stealing** - Windows has restrictions; but Terminal already handles this for `-w` commands 4. **Backward compatibility** - New subcommand/flag, no breaking changes ## Summary | Terminal | Focus Specific Tab? | Query Sessions? | API Maturity | |----------|:------------------:|:---------------:|:------------:| | tmux | ✅ `select-window -t` | ✅ `list-sessions` | Production | | iTerm2 | ✅ Python API | ✅ Full introspection | Production | | Kitty | ✅ `kitty @ focus-tab` | ✅ `kitty @ ls` | Production | | **Windows Terminal** | ❌ | ❌ | **Gap** | Windows Terminal has all the internal machinery (`WT_SESSION`, window management, shell integration). The missing piece is exposing tab activation to external processes. **This feature would make Windows Terminal a first-class citizen for the emerging AI agent workflow—and close a gap that every other major terminal has already solved.** ## I'm Happy to Help I'd be glad to: - Test preview builds - Provide detailed feedback - Contribute to implementation if pointed in the right direction - Help document the feature --- **Environment**: Windows 11 24H2, Windows Terminal 1.21+, C++/WinRT cc @crutkas
claunia added the Needs-TriageNeeds-Tag-Fix labels 2026-01-31 08:58:39 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#24000