---
title: "Tmux DSL"
description: "thinslice's tmux integration. Lay out a window, split it into panes, and launch a program in each one when you create a worktree or start your services."
---
# 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.

```toml
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.

```toml
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

```toml
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

```toml
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:

```toml
[hooks.new-worktree.complex]
exec = "$SLICE_PROJECT_DIR/scripts/tmux-complex-layout.sh $SLICE_CODE_DIR $SLICE_STATE_DIR $@"
```
