Skip to main content
The iTerm2 terminal plugin opens and manages terminal tabs in iTerm2 for attaching to agent sessions. It uses AppleScript to control iTerm2, creating new tabs and connecting them to tmux sessions.

Overview

The iTerm2 terminal plugin provides:
  • Automatic tab creation in iTerm2
  • tmux session attachment
  • Session name-based tab identification
  • Existing tab detection and reuse
  • Window creation if no window exists
  • Bulk tab opening for multiple sessions
  • macOS-only operation
macOS only: This plugin requires macOS and iTerm2. On other platforms, it logs a warning and performs no operations.

Prerequisites

  1. macOS: Required for AppleScript support
  2. iTerm2: Download from https://iterm2.com
  3. tmux: Used by the default runtime plugin
    brew install tmux
    

Configuration

Add the iTerm2 terminal plugin to your agent-orchestrator.yaml:
plugins:
  terminal:
    name: iterm2
    # No config options required

Configuration Options

The iTerm2 plugin has no configuration options. It operates using iTerm2’s default profile and settings.
The plugin uses your iTerm2 default profile settings. Customize your default profile in iTerm2 Preferences → Profiles to affect plugin behavior.

How It Works

Opening a Session

When you run ao open <session-id>, the plugin:
  1. Checks for existing tab: Searches all iTerm2 windows and tabs for a session with matching name
  2. Selects if found: If tab exists, brings it to focus
  3. Creates new tab if needed: Opens new tab with tmux attach command
  4. Sets tab name: Names the tab/session for easy identification

Session Name Resolution

The plugin uses the runtime handle ID (tmux session name) if available, otherwise falls back to the orchestrator session ID:
// Priority order:
1. session.runtimeHandle.id  // e.g., "ao-session-abc-123" (tmux name)
2. session.id                // e.g., "abc-123" (orchestrator ID)

Tab Creation Process

  1. Activates iTerm2
  2. Creates window if none exists
  3. Creates new tab with default profile
  4. Sets session name
  5. Executes tmux attach command:
    printf '\033]0;session-name\007' && tmux attach -t 'session-name'
    
The printf command sets the terminal title before attaching, ensuring the tab name persists even if tmux is disconnected.

AppleScript Security

The plugin uses multiple layers of escaping to prevent injection:
  1. AppleScript escaping: Escapes special characters for AppleScript strings
  2. Shell escaping: Escapes single quotes for shell commands
  3. Double escaping: Shell-escape first, then AppleScript-escape for write commands
// Example: Session name with special characters
const sessionName = "my-session's-name";

// AppleScript escape: "my-session's-name" → "my-session\'s-name"
// Shell escape: "my-session's-name" → "my-session'\''s-name"
Never bypass the plugin’s escaping functions. Always use escapeAppleScript() and internal shellEscape() for user-provided strings.

Usage Examples

Open Single Session

ao open my-session-id
This will:
  • Create/select iTerm2 tab for the session
  • Attach to the tmux session
  • Focus the tab

Open All Sessions

ao open --all
This will:
  • Open tabs for all active sessions
  • 300ms delay between each tab (avoid AppleScript race conditions)
  • Reuse existing tabs where possible

Check if Session is Open

ao list  # Shows which sessions have terminals open
The plugin tracks opened sessions and reports their status.

Advanced Features

Existing Tab Detection

The plugin searches all iTerm2 windows and tabs for matching session names:
tell application "iTerm2"
    repeat with aWindow in windows
        repeat with aTab in tabs of aWindow
            repeat with aSession in sessions of aTab
                if name of aSession is equal to "session-name" then
                    select aWindow
                    select aTab
                    return "FOUND"
                end if
            end repeat
        end repeat
    end repeat
    return "NOT_FOUND"
end tell
Tab detection is not case-sensitive and matches exact session names. Partial matches are not supported.

Query-Only Session Check

The isSessionOpen() method checks for tab existence without selecting it:
const isOpen = await terminal.isSessionOpen(session);
// Returns true/false, does NOT change focus
This is useful for status checks without disrupting the user’s workflow.

Bulk Opening with Delays

When opening multiple sessions, the plugin adds 300ms delays between operations:
for (const session of sessions) {
  await openTab(session);
  await new Promise(resolve => setTimeout(resolve, 300));
}
The delay prevents AppleScript race conditions where rapid tab creation can cause tabs to be created in the wrong window or order.

Troubleshooting

Check iTerm2 is installed:
which osascript  # Should show /usr/bin/osascript
open -a iTerm     # Should open iTerm2
Check plugin is configured:
plugins:
  terminal:
    name: iterm2
Check logs:
ao logs
# Look for: [terminal-iterm2] warnings
Grant iTerm2 automation permissions:
  1. System Preferences → Security & Privacy → Privacy
  2. Select “Automation” in left sidebar
  3. Find your terminal app (Terminal.app, iTerm2, etc.)
  4. Enable checkbox for “iTerm.app”
Test AppleScript manually:
osascript -e 'tell application "iTerm2" to activate'
This can happen with rapid tab creation. Solutions:
  1. Close extra iTerm2 windows
  2. Use ao open for individual sessions (not --all)
  3. Wait a moment between manual ao open commands
The 300ms delay in openAll() helps, but can’t prevent all race conditions.
The plugin sets both:
  • iTerm2 session name (persists)
  • Terminal title (via printf escape sequence)
If the name is wrong:
  1. Check session.runtimeHandle.id in metadata
  2. Verify tmux session name matches
  3. Check for shell profile overrides (PS1, etc.)
error connecting to /tmp/tmux-501/default (No such file or directory)
Solutions:
  1. Verify tmux session exists:
tmux ls
  1. Check runtime plugin created session:
ao list  # Should show RUNNING status
  1. Recreate session:
ao destroy <session-id>
ao create <project-id>
Your OS is not macOS. The iTerm2 plugin only works on macOS.Solution: Use a different terminal plugin:
plugins:
  terminal:
    name: web  # Use web-based terminal instead

Integration with tmux Runtime

The iTerm2 plugin is designed to work with the tmux runtime plugin: Runtime creates session:
tmux new-session -d -s ao-session-abc-123
Terminal attaches to session:
tmux attach -t ao-session-abc-123
Lifecycle:
  1. Runtime creates tmux session
  2. Runtime stores session ID in runtimeHandle.id
  3. Terminal reads runtimeHandle.id for session name
  4. Terminal runs tmux attach with that name
If using a different runtime plugin, ensure it sets runtimeHandle.id to a value the terminal can use for attachment.

macOS Catalina+ Permissions

On macOS Catalina (10.15) and later, you may need to grant additional permissions:
  1. System Events access: Required for AppleScript
  2. Automation access: Required to control iTerm2
  3. Accessibility access: May be required for window focus
If iTerm2 prompts for permissions during first use, grant them immediately. Denying permissions will break the plugin until you manually grant them in System Preferences.

Comparison with Web Terminal

FeatureiTerm2Web
PlatformmacOS onlyAny
SetupiTerm2 requiredBrowser required
Tab managementNative OS tabsBrowser tabs
Keyboard shortcutsiTerm2 shortcutsxterm.js shortcuts
Copy/pasteNativeBrowser-dependent
CustomizationiTerm2 profilesCSS/config
Remote accessLocal onlyCan be remote
PerformanceNativeJavaScript

Source Code

View the plugin source:
  • Package: @composio/ao-plugin-terminal-iterm2
  • Location: packages/plugins/terminal-iterm2/src/index.ts
  • Functions:
    • runAppleScript() - Execute AppleScript snippets
    • shellEscape() - Escape strings for shell
    • escapeAppleScript() - Escape strings for AppleScript (from core)
    • findAndSelectExistingTab() - Search and focus existing tab
    • openNewTab() - Create new tab with tmux attach

Build docs developers (and LLMs) love