# Configuration Reference

`smux` reads a main TOML config file plus optional project definition files.

Default path:

```text
~/.config/smux/config.toml
```

If `XDG_CONFIG_HOME` is set, `smux` uses:

```text
$XDG_CONFIG_HOME/smux/config.toml
```

Project definitions live in:

```text
~/.config/smux/projects/*.toml
```

or, when `XDG_CONFIG_HOME` is set:

```text
$XDG_CONFIG_HOME/smux/projects/*.toml
```

`smux init` writes starter files with `#:schema` directives pointing at version-matched JSON Schema files for editor support.

Schema files live in this repo at:

```text
schemas/smux-config.schema.json
schemas/smux-project.schema.json
```

## Structure

The main config has two top-level sections:

- `settings`
- `templates`

Example:

```toml
#:schema https://raw.githubusercontent.com/Aietes/smux/vX.Y.Z/schemas/smux-config.schema.json
[settings]
default_template = "default"
icons = "auto"

[settings.icon_colors]
session = 75
directory = 108
template = 179
project = 81

[settings.picker.bindings]
reset = "ctrl-c"
sessions = "ctrl-s"
folders = "ctrl-f"
projects = "ctrl-p"
delete_session = "ctrl-x"

[templates.default]
startup_window = "main"
windows = [{ name = "main" }]

[templates.rust]
startup_window = "editor"
startup_pane = 0
windows = [
  { name = "editor", pre_command = "source .venv/bin/activate", command = "nvim" },
  { name = "run", synchronize = true, layout = "main-horizontal", panes = [
      { command = "cargo run" },
      { layout = "right 40%", command = "cargo test", zoom = true },
    ] },
]
```

Example project file:

```toml
#:schema https://raw.githubusercontent.com/Aietes/smux/vX.Y.Z/schemas/smux-project.schema.json
path = "~/code/example"
session_name = "example"
template = "rust"
```

## `[settings]`

```toml
[settings]
default_template = "default"
icons = "auto"
```

Fields:

- `default_template`
  - type: string
  - optional
  - used when neither `--template` nor a matching project provides a template
- `icons`
  - type: `auto` | `always` | `never`
  - default: `auto`
  - controls whether picker icons are shown

### `[settings.icon_colors]`

```toml
[settings.icon_colors]
session = 75
directory = 108
template = 179
project = 81
```

Fields:

- `session`
  - type: integer
  - default: `75`
- `directory`
  - type: integer
  - default: `108`
- `template`
  - type: integer
  - default: `179`
- `project`
  - type: integer
  - default: `81`

These values are ANSI-256 color indexes used for picker icons.

### `[settings.picker.bindings]`

```toml
[settings.picker.bindings]
reset = "ctrl-c"
sessions = "ctrl-s"
folders = "ctrl-f"
projects = "ctrl-p"
delete_session = "ctrl-x"
```

Fields:

- `reset`
  - type: string
  - default: `ctrl-c`
  - resets the main picker to the full list
- `sessions`
  - type: string
  - default: `ctrl-s`
  - filters the main picker to tmux sessions
- `folders`
  - type: string
  - default: `ctrl-f`
  - filters the main picker to folders
- `projects`
  - type: string
  - default: `ctrl-p`
  - filters the main picker to saved projects
- `delete_session`
  - type: string
  - default: `ctrl-x`
  - closes the selected non-current tmux session and keeps the picker open

Rules:

- picker bindings must not be empty
- picker bindings must be unique within this block
- values are passed through as `fzf` key names

## `[templates.<name>]`

Templates describe the tmux layout applied when `smux` creates a new session.
The recommended and documented format uses TOML 1.1 inline tables for `windows` and nested `panes`.
That means template definitions should normally be written as `windows = [{ ... }]` with nested `panes = [{ ... }]`, rather than verbose `[[templates...]]` arrays of tables.

Example:

```toml
[templates.rust]
startup_window = "editor"
startup_pane = 0
windows = [
  { name = "editor", cwd = "~/code/example", pre_command = "source .venv/bin/activate", command = "nvim" },
  { name = "run", synchronize = true, layout = "main-horizontal", panes = [
      { command = "cargo run" },
      { layout = "right 40%", command = "cargo test" },
    ] },
]
```

If you use `folke/persistence.nvim`, a practical editor command is:

```toml
{ name = "editor", command = "nvim -c 'lua require(\"persistence\").load({ last = true })'" }
```

That restores the last saved Neovim session when the window opens.

Template fields:

- `root`
  - type: string
  - optional
  - currently accepted by the config schema
- `startup_window`
  - type: string
  - optional
  - must match one of the template window names if set
- `startup_pane`
  - type: integer
  - optional
  - default: `0`
  - zero-based pane index within the startup window
- `windows`
  - type: array of inline tables
  - required
  - must contain at least one window

### `windows = [{ ... }]`

Window fields:

- `name`
  - type: string
  - required
- `cwd`
  - type: string
  - optional
- `command`
  - type: string
  - optional
- `zoom`
  - type: boolean
  - default: `false`
  - zooms that pane after the window has been created
  - at most one pane per window may set `zoom = true`
- `pre_command`
  - type: string
  - optional
  - runs in each pane of the window before the pane or window command
- `layout`
  - type: string
  - optional
  - tmux window layout name passed to `tmux select-layout`
  - examples: `tiled`, `main-horizontal`, `main-vertical`, `even-horizontal`, `even-vertical`
  - applied after pane creation, so it may rearrange the final pane geometry
- `synchronize`
  - type: boolean
  - default: `false`
  - enables tmux synchronized panes for that window
- `panes`
  - type: array of inline tables
  - optional

Rules:

- a window may define `command`
- a window may define `panes`
- a window may define neither
- a window may not define both `command` and `panes`
- if `panes` is present, it must not be empty
- `pre_command` runs as a separate command before the window or pane command
- `window.layout` is a tmux layout name and is passed through to tmux without additional validation

### `panes = [{ ... }]`

Pane fields:

- `layout`
  - type: string
  - optional
  - format: `<position>` or `<position> <size>`
  - supported positions: `right`, `left`, `bottom`, `top`
  - controls how each new pane is created before any window-level tmux layout is applied
- `cwd`
  - type: string
  - optional
- `command`
  - type: string
  - optional

Examples:

- `layout = "right 40%"`
- `layout = "bottom 12"`
- `layout = "left"`

Interaction between pane and window layout:

- `pane.layout` controls split direction and optional size during pane creation
- `window.layout` is applied afterward with `tmux select-layout`
- if both are set, `window.layout` may rearrange the final pane geometry
- if you want tmux to normalize the final layout, set `window.layout`
- if you want to preserve the split sequence more closely, omit `window.layout`

## Recipes

These examples are meant to show practical combinations of pane `layout` and window `layout`.

### 2x2 grid

Use `tiled` when you want a simple 2x2-style workspace and do not care about preserving a specific split sequence.

```toml
[templates.grid]
startup_window = "grid"
windows = [
  { name = "grid", layout = "tiled", panes = [
      { command = "nvim" },
      { layout = "right", command = "cargo run" },
      { layout = "bottom", command = "cargo test" },
      { layout = "right", command = "git status -sb" },
    ] },
]
```

### One large top pane, two bottom panes

This is a good fit for `main-horizontal`.

```toml
[templates.dev]
startup_window = "run"
windows = [
  { name = "run", layout = "main-horizontal", panes = [
      { command = "nvim" },
      { layout = "bottom 30%", command = "cargo run" },
      { layout = "right", command = "cargo test" },
    ] },
]
```

This gives you one dominant pane at the top and two smaller panes below it.

### Sidebar on the left, work area on the right

```toml
[templates.sidebar]
startup_window = "main"
windows = [
  { name = "main", panes = [
      { command = "nvim" },
      { layout = "left 25%", command = "yazi" },
    ] },
]
```

### Vertical stack

```toml
[templates.stack]
startup_window = "stack"
windows = [
  { name = "stack", panes = [
      { command = "htop" },
      { layout = "bottom 40%", command = "cargo watch -x test" },
      { layout = "bottom 40%", command = "tail -f log/development.log" },
    ] },
]
```

## Project Definitions

Project definitions are stored as individual files in `~/.config/smux/projects/`.
The project name comes from the file name, for example:

```text
~/.config/smux/projects/myapp.toml
```

This project appears in `smux select` as `myapp`.

Project files can be written manually or exported from a live tmux session with:

```bash
smux save-project myapp
smux save-project myapp --stdout
```

Minimal project file:

```toml
path = "~/code/myapp"
template = "rust"
session_name = "myapp"
```

Fully defined project file:

```toml
path = "~/code/myapp"
session_name = "myapp"
startup_window = "editor"
windows = [
  { name = "editor", command = "nvim" },
  { name = "run", layout = "main-horizontal", panes = [
      { command = "cargo run" },
      { layout = "right 40%", command = "cargo test" },
    ] },
]
```

Project fields:

- `path`
  - type: string
  - required
  - expanded and normalized before matching
- `session_name`
  - type: string
  - optional
- `template`
  - type: string
  - optional
  - must refer to an existing template if set
- `root`
  - type: string
  - optional
- `startup_window`
  - type: string
  - optional
- `startup_pane`
  - type: integer
  - optional
- `windows`
  - type: array of inline tables
  - optional

Project behavior:

- a project may point at a template and use it as-is
- a project may define its own windows directly without using a template
- a project may use a template as a base and override it with project-specific session details
- when a project defines `windows`, they replace the template windows rather than merging window-by-window
- `smux save-project` exports concrete project files with inline `windows` instead of trying to infer template references

## Resolution Order

### Template resolution

When creating or connecting to a session, template resolution order is:

1. `--template`
2. matching project definition
3. `settings.default_template`
4. built-in fallback template

### Session name resolution

Session name resolution order is:

1. `--session-name`
2. matching project `session_name`
3. sanitized directory basename

## Validation Rules

`smux` validates the config when it is loaded.

Validation includes:

- `default_template` must exist if set
- each template must contain at least one window
- `startup_window` must refer to an existing template window
- `startup_pane` must be valid for the chosen startup window
- a window cannot define both `command` and `panes`
- a `panes` array cannot be empty
- project `template` references must exist
- project paths must be expandable and valid

## Picker Behavior

The unified picker combines:

- tmux sessions
- saved projects
- zoxide directories

The template picker is separate and appears only when `--choose-template` is used.

Current behavior:

- prompt is shown at the top
- `Esc` cancels cleanly
- typing still does normal fuzzy search
- `Ctrl-C` resets the picker
- `Ctrl-S` limits the main picker to sessions and keeps fuzzy search active
- `Ctrl-P` limits the main picker to projects and keeps fuzzy search active
- `Ctrl-F` limits the main picker to folders and keeps fuzzy search active
- `Ctrl-X` closes the selected non-current tmux session and keeps the picker open
- these keybinds are configurable through `[settings.picker.bindings]`

## Related Docs

- CLI overview: `README.md`
- design notes: `docs/design.md`
- distribution notes: `docs/distribution.md`
