Tmux DSL
thinslice provides a small DSL for defining tmux layouts inside hook definitions. It's a simplified wrapper over tmux commands, designed to make common layouts easy to express in a TOML config.
The DSL is optional. If you'd rather write a shell script that calls tmux directly, use exec in your hook definition instead.
Commands
new-window
Create a new tmux window.
new-window -n <name>
The -n flag sets the window name, which appears in the tmux status bar. This is typically the branch name:
new-window -n $BRANCH
split-h
Split the current pane horizontally (side by side).
split-h # 50/50 split
split-h 70 # left pane gets 70% of width
After splitting, the two resulting panes can be addressed as left and right in send commands.
split-v
Split the current pane vertically (top and bottom).
split-v # 50/50 split
split-v 70 # top pane gets 70% of height
After splitting, the two resulting panes can be addressed as top and bottom in send commands.
send
Send a command to a pane. The pane is identified by its position relative to the most recent split.
send "command" # send to the current pane (before any split)
send-left "command" # left pane of the most recent split-h
send-right "command" # right pane of the most recent split-h
send-top "command" # top pane of the most recent split-v
send-bottom "command" # bottom pane of the most recent split-v
For more complex layouts with nested splits, panes are addressed by compounding directions:
split-h
split-right-v
send-left "command" # the left pane (unsplit)
send-topright "command" # top of the right pane
send-bottomright "command" # bottom of the right pane
focus
Control which pane or window has focus after the hook completes.
focus-prev # return focus to the window the user was in before
focus-this # leave focus on the new window
focus-left # focus a specific pane
focus-right
focus-top
focus-bottom
focus-topleft
focus-topright
focus-bottomleft
focus-bottomright
focus-prev is the most common choice for agent workflows — you fire off a task and keep working where you were.
focus-this is for when you want to immediately interact with the new window.
Layouts
Two panes side by side
The most common layout: an interactive tool on the left, processes on the right.
tmux = """
new-window -n $BRANCH
split-h
send-left "cd $SLICE_CODE_DIR && claude $@"
send-right "cd $SLICE_CODE_DIR && slice up"
focus-prev
"""
┌──────────────────┬──────────────────┐
│ │ │
│ claude │ slice up │
│ │ │
└──────────────────┴──────────────────┘
Editor with logs
A larger editor pane on top, logs on the bottom.
tmux = """
new-window -n $BRANCH
split-v 70
send-top "cd $SLICE_CODE_DIR && $SHELL"
send-bottom "cd $SLICE_CODE_DIR && slice logs --follow"
focus-top
"""
┌─────────────────────────────────────┐
│ │
│ $SHELL │
│ │
├─────────────────────────────────────┤
│ slice logs │
└─────────────────────────────────────┘
Three panes: editor, processes, logs
tmux = """
new-window -n $BRANCH
split-h
split-right-v
send-left "cd $SLICE_CODE_DIR && vim $@"
send-topright "cd $SLICE_CODE_DIR && slice up"
send-bottomright "cd $SLICE_CODE_DIR && slice logs --follow"
focus-left
"""
┌──────────────────┬──────────────────┐
│ │ slice up │
│ vim ├──────────────────┤
│ │ slice logs │
└──────────────────┴──────────────────┘
Four panes: individual processes
tmux = """
new-window -n $BRANCH
split-h
split-left-v
split-right-v
send-topleft "postgres -D $SLICE_STATE_DIR/pgdata -p $PG_PORT"
send-bottomleft "redis-server --port $REDIS_PORT"
send-topright "cargo run --bin api -- --port $API_PORT"
send-bottomright "npm run dev -- --port $FRONTEND_HTTP_PORT"
focus-topright
"""
┌──────────────────┬──────────────────┐
│ postgres │ api │
├──────────────────┼──────────────────┤
│ redis │ web │
└──────────────────┴──────────────────┘
Variable substitution
The tmux DSL uses the same variables available in all hook definitions:
| Variable | Source |
|---|---|
$BRANCH | Branch name of the worktree |
$SLICE_CODE_DIR | Absolute path to worktree |
$SLICE_STATE_DIR | Absolute path to state directory |
$SLICE_PROJECT_DIR | Project root |
$PG_PORT, etc. | Ports from process definitions |
$@ | All hook arguments |
$1, $2, $3... | Individual hook arguments |
${@:2} | Arguments from 2nd onward |
$SHELL | User's shell |
To include a literal $ in a command sent to a pane, escape it as \$.
Limitations
The tmux DSL is intentionally minimal. It covers the most common layouts — two to four panes in a single window. If you need more complex arrangements (multiple windows, custom key bindings, session management), use exec to run a shell script that calls tmux directly:
[hooks.new-worktree.complex]
exec = "$SLICE_PROJECT_DIR/scripts/tmux-complex-layout.sh $SLICE_CODE_DIR $SLICE_STATE_DIR $@"
