Skip to main content
WezTerm supports advanced shell integration features that enable enhanced user experiences through special escape sequences. When properly configured, your shell can communicate additional context to WezTerm, enabling features like semantic navigation, smart working directory handling, and custom status information.

What is Shell Integration?

Shell integration uses OSC (Operating System Command) escape sequences to communicate between your shell and WezTerm. These sequences provide metadata about:
  • Current working directory
  • Command prompts vs output
  • User and hostname information
  • Custom shell state
Shell integration is automatically activated on Fedora, Debian, and Arch Linux packages for Bash and Zsh. On other systems, you’ll need to configure it manually.

Key Features

1

Working Directory Tracking

New tabs and panes automatically inherit the current working directory from the active pane.
2

Semantic Navigation

Jump through scrollback to the start of previous commands or select complete command output.
3

User Variables

Track custom shell state and trigger events based on shell activity.
4

Prompt Detection

Distinguish between prompts, input, and output for better copy/paste and navigation.

OSC 7: Working Directory

OSC 7 tells WezTerm the current working directory, enabling smart directory inheritance when spawning new tabs or panes.

How it Works

Your shell emits an escape sequence with the current directory as a URL:
printf "\033]7;file://HOSTNAME/CURRENT/DIR\033\\"
When the working directory is set via OSC 7, spawning a new tab will use the current working directory of the active tab, saving you from manually changing directories.

Bash Configuration

Add to your ~/.bashrc:
if [[ -n "$WEZTERM_PANE" ]]; then
  _wezterm_osc7() {
    printf "\033]7;file://%s%s\033\\" \
      "$HOSTNAME" \
      "$(pwd | sed 's/\\(/\\(\%20/g')"
  }
  PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND; }_wezterm_osc7"
fi

Zsh Configuration

Add to your ~/.zshrc:
if [[ -n "$WEZTERM_PANE" ]]; then
  function _wezterm_osc7() {
    printf "\033]7;file://%s%s\033\\" \
      "$HOST" \
      "${PWD/\//%2F}"
  }
  precmd_functions+=(_wezterm_osc7)
fi

Windows cmd.exe

Configure in your .wezterm.lua:
config.set_environment_variables = {
  prompt = '$E]7;file://localhost/$P$E\\$E[32m$T$E[0m $E[35m$P$E[36m$_$G$E[0m ',
}

PowerShell

Add to your PowerShell profile:
function prompt {
    $p = $executionContext.SessionState.Path.CurrentLocation
    $osc7 = ""
    if ($p.Provider.Name -eq "FileSystem") {
        $ansi_escape = [char]27
        $provider_path = $p.ProviderPath -Replace "\\\\", "/"
        $osc7 = "$ansi_escape]7;file://${env:COMPUTERNAME}/${provider_path}${ansi_escape}\"
    }
    "${osc7}PS $p$('>' * ($nestedPromptLevel + 1)) ";
}

PowerShell with Starship

If using Starship:
$prompt = ""
function Invoke-Starship-PreCommand {
    $current_location = $executionContext.SessionState.Path.CurrentLocation
    if ($current_location.Provider.Name -eq "FileSystem") {
        $ansi_escape = [char]27
        $provider_path = $current_location.ProviderPath -replace "\\\\", "/"
        $prompt = "$ansi_escape]7;file://${env:COMPUTERNAME}/${provider_path}$ansi_escape\"
    }
    $host.ui.Write($prompt)
}

OSC 133: Semantic Prompt Markup

OSC 133 marks distinct zones in your terminal output:
  • Prompt - Your shell prompt
  • Input - Commands you type
  • Output - Command results
This enables powerful navigation and selection features.

Benefits

Instantly select all output from a command:
config.keys = {
  {
    key = 'S',
    mods = 'CTRL|SHIFT',
    action = wezterm.action.SelectTextAtMouseCursor 'SemanticZone',
  },
}

Implementation

The complete OSC 133 specification uses these sequences:
  • OSC 133 ; A ST - Mark start of prompt
  • OSC 133 ; B ST - Mark start of input (command)
  • OSC 133 ; C ST - Mark start of output
  • OSC 133 ; D [; exit_code] ST - Mark end of output
Learn more about OSC 133 Semantic Prompts.

OSC 1337: User Variables

User variables are pane-specific variables (similar to environment variables but scoped to a pane rather than a process).

Built-in Variables

When using WezTerm’s shell integration, these variables are automatically maintained:
VariableDescription
WEZTERM_PROGCurrent command being executed
WEZTERM_USERCurrent username (from id -un)
WEZTERM_HOSTHostname (from hostname)
WEZTERM_IN_TMUX1 if inside tmux, 0 otherwise
If using tmux, you must add set -g allow-passthrough on to your tmux.conf for user vars to work.

Setting Custom Variables

Use the __wezterm_set_user_var function provided by shell integration:
# Example: Set a project variable
__wezterm_set_user_var PROJECT "my-awesome-app"

Using Variables in Configuration

User variables trigger events that you can handle in your configuration:
wezterm.on('user-var-changed', function(window, pane, name, value)
  if name == 'PROJECT' then
    window:set_right_status(value)
  end
end)

Accessing Variables

Read user variables from Lua:
wezterm.on('update-status', function(window, pane)
  local vars = pane:get_user_vars()
  local project = vars.PROJECT or 'no-project'
  window:set_right_status(project)
end)

Complete Shell Integration Setup

WezTerm provides shell integration scripts in the wezterm repository.

Installing for Bash/Zsh

1

Download the integration script

curl -fsSL https://raw.githubusercontent.com/wez/wezterm/main/assets/shell-integration/wezterm.sh -o ~/.wezterm.sh
2

Source in your shell config

Add to ~/.bashrc or ~/.zshrc:
if [[ -f ~/.wezterm.sh ]]; then
  source ~/.wezterm.sh
fi
3

Restart your shell

exec $SHELL

System-wide Installation

On most Unix systems, you can install to /etc/profile.d/:
sudo cp wezterm.sh /etc/profile.d/wezterm.sh

Xonsh Support

For Xonsh users, use the term-integrations plugin:
xpip install xontrib-term-integrations
xontrib load term_integrations

Advanced Examples

Dynamic Tab Titles with User Vars

Update tab titles based on the current command:
wezterm.on('format-tab-title', function(tab, tabs, panes, config, hover, max_width)
  local pane = tab.active_pane
  local prog = pane.user_vars.WEZTERM_PROG or pane.title
  return ' ' .. prog .. ' '
end)

Git Branch in Status Bar

In your shell configuration:
update_git_branch() {
  if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    local branch=$(git branch --show-current 2>/dev/null)
    __wezterm_set_user_var GIT_BRANCH "$branch"
  else
    __wezterm_set_user_var GIT_BRANCH ""
  fi
}

# Call before each prompt
PROMPT_COMMAND="update_git_branch; $PROMPT_COMMAND"
In .wezterm.lua:
wezterm.on('update-status', function(window, pane)
  local git_branch = pane:get_user_vars().GIT_BRANCH
  if git_branch and git_branch ~= '' then
    window:set_right_status(wezterm.format({
      { Foreground = { Color = '#00ff00' } },
      { Text = '  ' .. git_branch },
    }))
  else
    window:set_right_status('')
  end
end)

Command Duration Tracking

__wezterm_cmd_start_time=""

__wezterm_record_start() {
  __wezterm_cmd_start_time=$(date +%s)
}

__wezterm_record_duration() {
  if [[ -n "$__wezterm_cmd_start_time" ]]; then
    local end_time=$(date +%s)
    local duration=$((end_time - __wezterm_cmd_start_time))
    __wezterm_set_user_var CMD_DURATION "$duration"
    __wezterm_cmd_start_time=""
  fi
}

preexec_functions+=(__wezterm_record_start)
precmd_functions+=(__wezterm_record_duration)
Clink brings bash-style line editing to Windows cmd.exe.

Configuration

local wezterm = require 'wezterm'
local config = {}

config.set_environment_variables = {}

if wezterm.target_triple == 'x86_64-pc-windows-msvc' then
  -- Use OSC 7
  config.set_environment_variables['prompt'] =
    '$E]7;file://localhost/$P$E\\$E[32m$T$E[0m $E[35m$P$E[36m$_$G$E[0m '
  -- Better dir output
  config.set_environment_variables['DIRCMD'] = '/d'
  -- Inject clink
  config.default_prog =
    { 'cmd.exe', '/s', '/k', 'c:/clink/clink_x64.exe', 'inject', '-q' }
end

return config

Troubleshooting

Verify OSC 7 is being emitted:
# In your terminal, after changing directory:
printf "\033]7;file://%s%s\033\\" "$HOSTNAME" "$PWD"
Check that WEZTERM_PANE environment variable is set.
Ensure your tmux.conf includes:
set -g allow-passthrough on
Restart tmux after updating the configuration.
Verify the integration script is sourced:
type __wezterm_set_user_var
If the function is not found, check that your shell config sources the integration file.

Best Practices

1

Use provided integration scripts

Start with WezTerm’s official shell integration scripts rather than writing your own.
2

Test incrementally

Add features one at a time (OSC 7, then OSC 133, then custom user vars) to isolate issues.
3

Check for conflicts

Some prompt frameworks (like Starship or Oh My Zsh) may conflict. Check their documentation for integration guides.
4

Update regularly

Shell integration improves over time. Periodically update your integration scripts.

Learn More