it2 Plugin Development Guide

This guide covers developing plugins for the it2 command-line interface for iTerm2 automation.

Overview

it2 supports extensibility through an executable plugin system that can:

  1. Enrich session information - Add metadata to session, tab, and window listings
  2. Monitor and respond to events - Automate responses based on patterns
  3. Filter and categorize - Apply tool-specific logic for better organization

Plugin Architecture

it2 (core)
  ↓ Discovery
Plugin Registry (internal/plugins/)
  ↓ Execution
External Executables (it2-*)
  ↓ Integration
Enhanced Output

Plugin Types

it2 recognizes three types of plugins based on executable naming:

  1. Session Enrichers (it2-session-*) - Add data to session listings
  2. Tab Enrichers (it2-tab-*) - Add data to tab listings
  3. Window Enrichers (it2-window-*) - Add data to window listings
  4. Generic Plugins (it2-*) - Apply to all entity types

Quick Start

1. Create a Simple Session Plugin

Create an executable named it2-session-example:

#!/bin/bash
# File: it2-session-example

SESSION_ID="$1"
SESSION_NAME="$2"

# Example: Show if session is running a specific tool
if pgrep -f "vim.*$SESSION_ID" >/dev/null; then
    echo "vim-active"
elif pgrep -f "git.*$SESSION_ID" >/dev/null; then
    echo "git-active"
else
    echo "shell"
fi

Make it executable:

chmod +x it2-session-example

Add to PATH:

export PATH="$PATH:$(pwd)"

2. Test Your Plugin

it2 session list

Your plugin output will appear in the session listing as additional metadata.

Plugin Interface

Session Enrichers

Input Arguments:

  • $1: Session ID (required)
  • $2: Session Name (optional, empty if not set)

Expected Output:

  • Single line string describing the session state
  • Empty output is ignored
  • Exit code 0 for success (non-zero ignored, not treated as error)

Example:

#!/bin/bash
SESSION_ID="$1"
SESSION_NAME="$2"

# Check if this is a Claude Code session
if [ "$SESSION_NAME" = "Claude Code" ] || echo "$SESSION_NAME" | grep -q "claude"; then
    echo "claude-session"
fi

Tab Enrichers

Input Arguments:

  • $1: Tab ID (required)
  • $2: Window ID (required)
  • $3: Tab Title (optional)

Expected Output:

  • Single line string describing tab state
  • Empty output is ignored

Window Enrichers

Input Arguments:

  • $1: Window ID (required)
  • $2: Window Title (optional)

Expected Output:

  • Single line string describing window state
  • Empty output is ignored

Advanced Examples

Multi-Purpose Plugin

Create it2-dev-tools that works across all entity types:

#!/bin/bash
# Universal development tool detector

if [ $# -eq 1 ]; then
    # Window enricher mode (1 arg = window ID)
    WINDOW_ID="$1"
    # Check if any session in this window is running dev tools
    if it2 session list --format json | jq -r ".[] | select(.window_id == \"$WINDOW_ID\") | .session_name" | grep -E "(vim|code|git)" >/dev/null; then
        echo "development-window"
    fi
elif [ $# -eq 2 ]; then
    # Tab enricher mode (2 args = tab ID, window ID)
    TAB_ID="$1"
    WINDOW_ID="$2"
    # Check sessions in this specific tab
    if it2 session list --format json | jq -r ".[] | select(.tab_id == \"$TAB_ID\") | .session_name" | grep -E "(vim|code)" >/dev/null; then
        echo "coding-tab"
    fi
elif [ $# -ge 2 ]; then
    # Session enricher mode (2+ args = session ID, session name, ...)
    SESSION_ID="$1"
    SESSION_NAME="$2"

    # Detailed session analysis
    if echo "$SESSION_NAME" | grep -q "vim"; then
        echo "vim-session"
    elif echo "$SESSION_NAME" | grep -q "git"; then
        echo "git-session"
    elif pgrep -f "node.*$SESSION_ID" >/dev/null; then
        echo "node-dev"
    fi
fi

Configuration-Based Plugin

Create it2-session-classifier that reads from config:

#!/bin/bash
CONFIG_FILE="$HOME/.it2/plugins/classifier.yaml"

SESSION_ID="$1"
SESSION_NAME="$2"

if [ ! -f "$CONFIG_FILE" ]; then
    exit 0
fi

# Parse YAML config (requires yq or similar)
if command -v yq >/dev/null; then
    PATTERNS=$(yq eval '.patterns[]' "$CONFIG_FILE" 2>/dev/null)
    while IFS= read -r pattern; do
        if echo "$SESSION_NAME" | grep -qE "$pattern"; then
            LABEL=$(yq eval ".patterns | to_entries | .[] | select(.value == \"$pattern\") | .key" "$CONFIG_FILE")
            echo "$LABEL"
            exit 0
        fi
    done <<< "$PATTERNS"
fi

With config file ~/.it2/plugins/classifier.yaml:

patterns:
  development: "(vim|code|emacs|nvim)"
  git: "(git|gh|hub)"
  database: "(mysql|postgres|redis|mongo)"
  containers: "(docker|kubectl|k8s)"
  cloud: "(aws|gcp|azure|terraform)"

Plugin Discovery

it2 discovers plugins by:

  1. Scanning all directories in $PATH
  2. Looking for executable files with names starting with it2-
  3. Determining type based on naming pattern:
    • it2-session-* → Session enricher
    • it2-tab-* → Tab enricher
    • it2-window-* → Window enricher
    • it2-* → Generic (applies to all types)

Integration Points

Session Listings

Plugins add data to the PluginData field in session listings:

{
  "session_id": "sess123",
  "session_name": "vim-work",
  "plugin_data": {
    "example": "vim-active",
    "dev-tools": "vim-session"
  }
}

Tab Listings

Similar integration for tab metadata:

{
  "tab_id": "tab456",
  "sessions": [...],
  "plugin_data": {
    "dev-tools": "coding-tab"
  }
}

Best Practices

Performance

  • Plugins have a 5-second timeout - keep them fast
  • Cache expensive operations when possible
  • Exit early for irrelevant sessions/tabs/windows

Error Handling

  • Non-zero exit codes are ignored, not treated as errors
  • Empty output is ignored
  • Use stderr for debugging (visible with ITERM2_DEBUG=1)

Naming Conventions

  • Use descriptive plugin names: it2-session-git-status not it2-git
  • Use hyphens for multi-word names: it2-session-docker-status
  • Be specific about what the plugin does

Output Formatting

  • Keep output concise (single line preferred)
  • Use consistent terminology
  • Consider localization if relevant

Configuration

  • Store config in ~/.it2/plugins/
  • Use standard formats (YAML, JSON, TOML)
  • Provide sensible defaults
  • Document configuration options

Debugging

Enable Debug Mode

export ITERM2_DEBUG=1
it2 session list

Test Plugin Directly

./it2-session-example "session-id" "session-name"
echo $?  # Should be 0

Common Issues

  1. Plugin not discovered: Check it's in PATH and executable
  2. No output: Verify plugin returns non-empty string
  3. Timeout: Plugin takes longer than 5 seconds
  4. Wrong arguments: Check argument handling for your plugin type

Distribution

Packaging

  • Create a directory with your plugin and README
  • Include configuration examples
  • Add installation script if needed

Example Structure

my-plugin/
├── it2-session-mystatus
├── it2-tab-mystatus
├── README.md
├── config.yaml.example
└── install.sh

Installation Methods

Method 1: PATH Installation

cp it2-session-mystatus /usr/local/bin/
chmod +x /usr/local/bin/it2-session-mystatus

Method 2: Plugin Directory

mkdir -p ~/.it2/plugins/mystatus
cp it2-session-mystatus ~/.it2/plugins/mystatus/
export PATH="$PATH:$HOME/.it2/plugins/mystatus"

Examples Repository

See the examples/ directory for working plugin implementations:

  • claude-monitoring/: Complete Claude Code session monitoring
  • vim-monitoring/: Advanced vim session detection and assistance
  • tmux-monitoring/: tmux session integration
  • shell-monitoring/: Shell state detection

Plugin Registry (Future)

Future versions may include:

  • Plugin registry with it2 plugin install <name>
  • Automatic updates
  • Plugin marketplace
  • Dependency management

Contributing

To contribute plugins or improvements:

  1. Test thoroughly with various session types
  2. Follow naming conventions
  3. Include comprehensive documentation
  4. Add examples to the examples directory
  5. Submit pull requests with test cases

For complex plugins, consider:

  • Unit tests for plugin logic
  • Integration tests with it2
  • Performance benchmarks
  • Cross-platform compatibility