Documentation

tmuxp has been at this for well over a decade. It has a freeze command that predates glaze save by years, a Python library underneath for the day a YAML file is not enough and a config format that has grown a key for nearly every situation. If it works for you, keep using it. I am not here to convince anyone. But if you want to try a .glaze file, and you already have a directory of workspaces, this page translates one into the other block by block, and it is honest about the places where the two tools simply do not line up.

A typical workspace

A tmuxp workspace with the usual parts:

~/.config/tmuxp/daemon-run.yaml YAML
session_name: daemon-run
start_directory: ~/runs/arasaka
before_script: ./bootstrap.sh
suppress_history: true

environment:
  ICE_TARGET: arasaka-mainframe

options:
  main-pane-height: 30

windows:
  - window_name: editor
    layout: main-vertical
    focus: true
    shell_command_before:
      - nvm use 20
    panes:
      - shell_command:
          - npm install
          - npm run dev
      - nvim .
  - window_name: logs
    layout: even-horizontal
    panes:
      - tail -f logs/dev.log
      - htop

The same workspace as a profile:

.glaze HCL
locals {
  setup = "nvm use 20"
}

session {
  name               = "daemon-run"
  starting_directory = "~/runs/arasaka"

  envs = {
    ICE_TARGET = "arasaka-mainframe"
  }

  options = {
    "main-pane-height" = "30"
  }

  window {
    name   = "editor"
    layout = "main-vertical"
    focus  = true

    pane {
      commands = [local.setup, "npm install", "npm run dev"]
    }

    pane {
      commands = [local.setup, "nvim ."]
    }
  }

  window {
    name   = "logs"
    layout = "even-horizontal"

    pane {
      commands = ["tail -f logs/dev.log"]
    }

    pane {
      commands = ["htop"]
    }
  }
}

before_script is not in the profile. It runs before glaze up instead. See below.

The translation table

tmuxpglazeNotes
session_namesession.nameGlazier replaces ., :, $ and a backslash with - and shows a warning.
start_directorystarting_directoryOn the session or the window, as in tmuxp. ~ expands. A relative path is relative to the directory of the profile.
windows[].window_namewindow.name
layoutwindow.layoutThe same five tmux presets. A raw layout string also works in both tools.
focusfocus = trueOn a window or a pane, as in tmuxp.
panes[] as a stringpane.commandsA list with one command.
panes[].shell_commandpane.commandsA list, in order. Glazier waits for each command except the last.
panes[] as null, pane or blankpane {}An empty pane block.
environmentsession.envsSession only. See below.
optionsoptionsOn the session or the window. Glazier sets each option where tmux keeps it.
global_optionssession.optionsNot the same. See below.
suppress_historynoneGlazier always does this. See below.
shell_command_beforesession.envs, or repeat the commandNot the same. See below.
before_scriptrun it before glaze upNot the same. See below.
options_afternoneSee below.
window_indexnoneGlazier has no index. It creates the windows in file order.
sleep_before, sleep_afternoneGlazier waits for each command to complete. There are no sleeps.
enter: falsenone
tmuxp load daemon-runglaze up
tmuxp freeze daemon-runglaze savesave captures names, directories, focus and layout. It does not capture commands, envs, hooks or options.
tmux kill-session -t daemon-runglaze downA session that is not running causes no error.

The five layout presets are tmux presets in both tools: even-horizontal, even-vertical, main-horizontal, main-vertical and tiled. The default in Glazier is tiled.

What does not map one to one

shell_command_before. tmuxp runs these commands in every pane of the session or the window before the pane’s own commands. Glazier has no such hook. You have two options. When the command sets environment variables, put them in envs on the session: Glazier applies them before it creates any window or pane, so every shell inherits them. When the command does real work, for example nvm use 20, put it first in the commands of each pane. Yes, that means repeating it. The example above holds the string once in a locals block, so each pane reads local.setup. See Locals.

environment on a window or a pane. tmuxp sets a window or pane environment. Glazier accepts envs on the session only, because tmux gives a new variable only to the shells it starts after the variable is set, and a pane already has its shell by then. An earlier version of Glazier accepted envs on a window and a pane. It looked like it worked, and it did not. Put the variable on the session, or inline it in the command: EDITOR=nvim nvim .. See Environment.

global_options. tmuxp sets these globally, so they apply to the whole tmux server. Glazier never sets a global option. options on the session block goes to the session, and a window option in it goes to every window of the session. The option is in effect for this session only, which is what a project file usually means anyway. An option that must be global belongs in tmux.conf. See Hooks and options.

before_script. tmuxp runs this script before the session exists, and a non-zero exit stops the load. Glazier has commands on the session block, and they run in the active pane after Glazier creates all windows and panes. Nothing checks their exit status. For a script that must finish, and must succeed, before anything else, run it in your shell: ./bootstrap.sh && glaze up. See Session and Scripting.

suppress_history. You can drop this key. Glazier does not type the commands into the pane. It loads them into a tmux paste buffer and types one line that starts with a space, so a shell that ignores such lines does not keep it in the history. There is no switch to turn it off. See Run commands reliably.

options_after. tmuxp has this key for one job: synchronize-panes after the panes exist. Glazier applies window options before it runs the pane commands, and tmux then types each command line into every pane of the window. A command runs twice and a pane reports a missing buffer. So:

warning

Do not set synchronize-panes in options on a window whose panes have commands.

Set it on a window whose panes have no commands, or turn it on by hand after up with tmux set-option -w synchronize-panes on.

Differences in the workflow

  • tmuxp keeps workspaces in $TMUXP_CONFIGDIR, ~/.config/tmuxp/ or ~/.tmuxp/, and load also takes a path. Glazier looks for .glaze in the current directory, then in $GLAZE_PATH, or where --profile-path points. A profile lives with the project, so it goes into the repository. See Profile resolution.
  • tmuxp reads YAML and JSON and converts between them. A profile is HCL only. There is no converter, which is why this page exists.
  • tmuxp replaces ${VAR} in a few keys from the environment. Glazier has env.* from GLAZE_ENV_* variables, typed variable blocks and --var flags, so one profile serves many projects. See Variables and One profile for many projects.
  • Glazier waits for each pane command except the last with tmux wait-for, so npm install finishes before npm run dev starts. There are no fixed sleeps. See Run commands reliably.

Check the translation

Run glaze format --validate before the first glaze up. It decodes the profile and reports each problem that it can find, with the file and the line, before tmux starts:

Console
$ glaze format --validate --stdout > /dev/null
Error: Invalid layout specified

  on /home/v/runs/arasaka/.glaze line 9, in session:
   9:     layout = "main-diagonal"

The layout value of "main-diagonal" is not a supported preset
(even-horizontal, even-vertical, main-horizontal, main-vertical, tiled) nor a
valid tmux layout string.

the glaze profile contains errors

Without --stdout, format also rewrites the profile into the canonical form, which is a fine first step for a file you just typed by hand. See glaze format.

Two files, same workspace. Keep the one you prefer.