---
title: "WezTerm: Passing Data from a Pane to Lua"
aliases: [wezterm-user-vars, wezterm-osc, wezterm-pane-data]
tags: [wezterm, lua, terminal, osc, pane, shell-integration]
sources: [raw/Passing Data from a pane to Lua - Wez's Terminal Emulator.md]
created: 2026-04-17
updated: 2026-04-17
---

## Overview

WezTerm cannot directly inspect what's running inside a pane (especially remote/SSH panes). The PTY interface only provides input/output streams and screen size. Instead, you signal data *into* WezTerm via escape sequences or OS APIs.

## Methods

### 1. User Vars (OSC 1337) — Most Powerful

Key/value pairs scoped to a terminal pane. Written by the shell, read-only from within the pane, readable by Lua.

**Set a user var from shell:**
```bash
printf "\033]1337;SetUserVar=%s=%s\007" foo `echo -n bar | base64`
```
Value must be **base64 encoded**.

**Read in Lua:**
```lua
pane:get_user_vars()           -- returns all vars as a table
tab.active_pane.user_vars.FOO  -- direct field access in event handlers
```

**Events triggered on var change:**
- `user-var-changed` — act immediately on a set/change
- `update-status` — refresh left/right status bar items
- Tab bar / title events fire as well

Propagates across multiplexer clients. Works through **tmux** if you use tmux passthrough:
```bash
printf "\033Ptmux;\033\033]1337;SetUserVar=%s=%s\007\033\\" "$1" `echo -n "$2" | base64`
```
(Also requires `set -g allow-passthrough on` in `tmux.conf`.)

**Shell alias pattern — set PROG on command run:**
```bash
__wezterm_set_user_var() {
  if hash base64 2>/dev/null; then
    if [[ -z "${TMUX}" ]]; then
      printf "\033]1337;SetUserVar=%s=%s\007" "$1" `echo -n "$2" | base64`
    else
      printf "\033Ptmux;\033\033]1337;SetUserVar=%s=%s\007\033\\" "$1" `echo -n "$2" | base64`
    fi
  fi
}

function _run_prog() {
    __wezterm_set_user_var "PROG" "$1"
    trap '__wezterm_set_user_var PROG ""' EXIT
    command "$@"
}

alias vim="_run_prog vim"
alias nvim="_run_prog nvim"
alias tmux="_run_prog tmux"
```

**Use PROG in tab title:**
```lua
local wezterm = require 'wezterm'

wezterm.on('format-tab-title', function(tab)
  local prog = tab.active_pane.user_vars.PROG
  return tab.active_pane.title .. ' [' .. (prog or '') .. ']'
end)

return {}
```

### 2. OSC 0 / 1 / 2 — Window & Tab Title

| OSC | Effect | Example |
|-----|--------|---------|
| `0` | Clears Icon Name, sets Window Title | `\x1b]0;title\x1b\\` |
| `1` | Sets Icon Name (used as Tab title if non-empty) | `\x1b]1;tab-title\x1b\\` |
| `2` | Sets Window Title | `\x1b]2;window-title\x1b\\` |

Read back via `pane:get_title()` or `PaneInformation.title`.

Many distro shells emit OSC 2 before each command. WezTerm will substitute the foreground process title if no OSC title is set (local panes only).

### 3. OSC 7 — Current Working Directory

```bash
printf "\033]7;file://HOSTNAME/CURRENT/DIR\033\\"
# or:
wezterm set-working-directory
```

Read back via `pane:get_current_working_dir()` or `PaneInformation.current_working_dir`.

Wezterm shell integration auto-sets OSC 7 for bash/zsh.

### 4. Local Process State

Works **only for local panes** (no SSH/multiplexer):

- `pane:get_foreground_process_info()` — process hierarchy info
- `wezterm.procinfo.get_info_for_pid(pid)` — info for a given PID

Convenient since no shell config changes required, but:
- Fails for remote panes
- Less reliable on Windows for determining foreground process

## Comparison

| Method | Remote/SSH | Requires shell config | Use case |
|--------|------------|----------------------|----------|
| User Vars (OSC 1337) | ✅ | Yes (aliases/integration) | Arbitrary key/value signaling |
| OSC 0/1/2 | ✅ | Often automatic | Tab/window titles |
| OSC 7 | ✅ | Shell integration | CWD tracking |
| Local process info | ❌ | No | Quick local introspection |

## Key Takeaways

- **User Vars** are the most flexible mechanism — arbitrary key/value, works over SSH and tmux
- Values must be **base64 encoded** when sending via OSC 1337
- The `user-var-changed` event fires immediately; use it to react dynamically in Lua
- **OSC 7** is the standard way to track CWD; shell integration handles it automatically
- **Local process APIs** are zero-config but only work locally
- Install [wezterm shell integration](https://wezterm.org/shell-integration.html) to get User Vars, OSC 7, and more out of the box

## Related

- [[wiki/dotfiles/wezterm-config|WezTerm Config]] — Lua config structure and live reload
- [[wiki/dotfiles/wezterm-key-tables|WezTerm Key Tables]] — modal keybinding layers
- [[wiki/dotfiles/wezterm-launching-programs|WezTerm Launching Programs]] — shell resolution and env vars
- [[wiki/dotfiles/wezterm-cli-reference|WezTerm CLI Reference]] — CLI subcommands and scripting

## Sources

- [wezterm.org/recipes/passing-data.html](https://wezterm.org/recipes/passing-data.html)
