# Options and hooks

Source: https://libtmux.org/en/tmux/topics/options-and-hooks/

> Read and update tmux options, and register commands for tmux events.

Use options to change tmux behavior, such as `automatic-rename` or the
status-line format. Use hooks to run commands on events such as
`session-renamed` or `after-split-window`. Choose the scope supported by the
option or hook.

## Reading and writing options

Read, set, or unset an option at its supported scope. Distinguish a local
override from the effective value inherited from a parent scope.

### Python

**Read all (this scope):** [`pane.show_options()`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-show_options/>)

**Read effective/inherited:** [`pane.show_option(name, global_=True)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-show_option/>) reaches the
global fallback explicitly; no separate "resolved" call

**Set:** [`pane.set_option(name, value)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-set_option/>)

**Unset:** [`pane.unset_option(name)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-unset_option/>)

### TypeScript

**Read all (this scope):** [`pane.showOptions()`](<https://libtmux.org/en/ts/latest/reference/pane-pane-showoptions/>)

**Read effective/inherited:** [`pane.showResolvedOptions()`](<https://libtmux.org/en/ts/latest/reference/pane-pane-showresolvedoptions/>)

**Set:** [`pane.setOption(name, value)`](<https://libtmux.org/en/ts/latest/reference/pane-pane-setoption/>)

**Unset:** [`pane.unsetOption(name)`](<https://libtmux.org/en/ts/latest/reference/pane-pane-unsetoption/>)

### Go

[`pane.Options(ctx)`](<https://libtmux.org/en/go/latest/reference/tmux-pane-options/>) returns a fresh typed snapshot, including inherited values.
Its accessors return an [`OptionValue`](<https://libtmux.org/en/go/latest/reference/tmux-optionvalue/>); use [`OptionValue.Get`](<https://libtmux.org/en/go/latest/reference/tmux-optionvalue-get/>) to distinguish a
present value from an absent one. Check the read error before inspecting the snapshot.

Use the handle that owns the option's scope. For example, `automatic-rename`
belongs to a window: use [`Window.SetOption`](<https://libtmux.org/en/go/latest/reference/tmux-window-setoption/>) or [`Window.UnsetOption`](<https://libtmux.org/en/go/latest/reference/tmux-window-unsetoption/>), then read
[`Window.Options`](<https://libtmux.org/en/go/latest/reference/tmux-window-options/>) again for an updated snapshot.

For a single raw value, [`Pane.RawOption`](<https://libtmux.org/en/go/latest/reference/tmux-pane-rawoption/>) returns the string, its presence, and an
error. Do not treat an error as an absent option.

### Rust

**Read all (this scope):** [`pane.options()`](<https://libtmux.org/en/rs/latest/reference/pane-pane-options/>) (typed [`BTreeMap`](<https://doc.rust-lang.org/std/collections/struct.BTreeMap.html>)),
[`pane.option_names()`](<https://libtmux.org/en/rs/latest/reference/pane-pane-option_names/>)

**Read effective/inherited:** [`pane.typed_option(name)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-typed_option/>) decodes one value by its
declared kind

**Set:** [`pane.set_option(name, value)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-set_option/>), [`pane.append_option(name, value)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-append_option/>)

**Unset:** [`pane.unset_option(name)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-unset_option/>)

### Java

**Read all (this scope):** [`pane.options().all()`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-options/>)

**Read effective/inherited:** [`pane.options().get(name)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-options/>) reads `show-options -A
-v`: inherited, not just local

**Set:** [`pane.options().set(name, value)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-options/>)

**Unset:** [`pane.options().unset(name)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-options/>)

### C#

**Read all (this scope):** [`pane.Options.GetAllAsync()`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptions-getallasync/>)

**Read effective/inherited:** [`pane.Options.GetAsync(new GetOptionRequest(name,
includeInherited: true))`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptions-getasync/>): an explicit opt-in flag, mapped straight to tmux's
own `-A`

**Set:** [`pane.Options.SetAsync(new SetOptionRequest(name, value))`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptions-setasync/>)

**Unset:** [`pane.Options.UnsetAsync(...)`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxoptions-unsetasync/>)

### C++

**Read all (this scope):** [`pane->options()`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-options/>)

**Read effective/inherited:** Not listed.

**Set:** [`pane->set_option(name, value)`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-set_option/>)

**Unset:** [`pane->unset_option(name)`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane-unset_option/>)

### Swift

**Read all (this scope):** [`server.options(.pane(pane))`](<https://libtmux.org/en/swift/latest/reference/server-options(_-)/>)

**Read effective/inherited:** [`server.option(name, scope: .pane(pane))`](<https://libtmux.org/en/swift/latest/reference/server-option(_-scope-)/>) reads
presence from the listing, then the value with `-v`

**Set:** [`server.setOption(name, to: value, scope: .pane(pane))`](<https://libtmux.org/en/swift/latest/reference/server-setoption(_-to-scope-)/>)

**Unset:** [`server.unsetOption(name, scope: .pane(pane))`](<https://libtmux.org/en/swift/latest/reference/server-unsetoption(_-scope-)/>)

### Examples

After a successful write completes, read the option to obtain its updated value.
The following examples set, read, and unset an option:

```python
pane.set_option("automatic-rename", "off")
pane.show_options()
pane.unset_option("automatic-rename")
```

```typescript
await pane.setOption("automatic-rename", "off");
await pane.showOptions();
await pane.unsetOption("automatic-rename");
```

```go
if err := window.SetOption(ctx, "automatic-rename", "off", tmux.SetOptionOptions{}); err != nil {
    return fmt.Errorf("set automatic rename: %w", err)
}
options, err := window.Options(ctx)
if err != nil {
    return fmt.Errorf("read window options: %w", err)
}
value, present := options.AutomaticRename().Get()
fmt.Println("automatic rename:", value, "present:", present)
if err := window.UnsetOption(ctx, "automatic-rename", tmux.UnsetOptionOptions{}); err != nil {
    return fmt.Errorf("unset automatic rename: %w", err)
}
```

```rust
pane.set_option("automatic-rename", "off").await?;
pane.options().await?;
pane.unset_option("automatic-rename").await?;
```

```java
pane.options().set("automatic-rename", "off");
pane.options().all();
pane.options().unset("automatic-rename");
```

```csharp
await pane.Options.SetAsync(new SetOptionRequest("automatic-rename", "off"));
await pane.Options.GetAllAsync();
await pane.Options.UnsetAsync("automatic-rename");
```

```cpp
pane->set_option("automatic-rename", "off");
pane->options();
pane->unset_option("automatic-rename");
```

```swift
try await server.setOption("automatic-rename", to: "off", scope: .pane(pane))
try await server.options(.pane(pane))
try await server.unsetOption("automatic-rename", scope: .pane(pane))
```

## Hooks

### Python

**Set:** [`pane.set_hook(name, command)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-set_hook/>)

**Unset:** [`pane.unset_hook(name)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-unset_hook/>)

**List:** [`pane.show_hook(name)`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-show_hook/>), [`pane.show_hooks()`](<https://libtmux.org/en/py/latest/reference/libtmux-pane-show_hooks/>) (all)

**Run now, without the event:** Not listed.

### TypeScript

**Set:** [`pane.setHook(name, command, { append })`](<https://libtmux.org/en/ts/latest/reference/pane-pane-sethook/>)

**Unset:** [`pane.unsetHook(name)`](<https://libtmux.org/en/ts/latest/reference/pane-pane-unsethook/>)

**List:** [`pane.showHooks()`](<https://libtmux.org/en/ts/latest/reference/pane-pane-showhooks/>) (all; no singular `showHook`)

**Run now, without the event:** Not listed.

### Go

Use [`session.SetHook`](<https://libtmux.org/en/go/latest/reference/tmux-session-sethook/>) to register a command and [`session.Hooks`](<https://libtmux.org/en/go/latest/reference/tmux-session-hooks/>) to read the
session's typed hook values. [`session.UnsetHook`](<https://libtmux.org/en/go/latest/reference/tmux-session-unsethook/>) removes a registration.
[`Session.SetHooks`](<https://libtmux.org/en/go/latest/reference/tmux-session-sethooks/>) writes indexed entries when an event needs more than one command.

Use [`server.GlobalSessionScope()`](<https://libtmux.org/en/go/latest/reference/tmux-server-globalsessionscope/>) for hooks shared by sessions. Keep hook
registration at a scope supported by the tmux event.

### Rust

**Set:** [`pane.set_hook(name, command)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-set_hook/>)

**Unset:** [`pane.unset_hook(name)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-unset_hook/>)

**List:** [`pane.hook(name)`](<https://libtmux.org/en/rs/latest/reference/pane-pane-hook/>): one name only; **no listing at pane/window scope**,
by design (see below)

**Run now, without the event:** Not listed.

### Java

**Set:** [`pane.hooks().set(event, command)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-hooks/>), `.append(event, command)`

**Unset:** [`pane.hooks().unset(event)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-hooks/>)

**List:** [`pane.hooks().all()`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-hooks/>)

**Run now, without the event:** [`pane.hooks().run(event)`](<https://libtmux.org/en/java/latest/reference/io-github-libtmux-pane-pane-hooks/>): tmux's `set-hook -R`

### C#

**Set:** [`pane.Hooks.SetAsync(new SetHookRequest(event, command))`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhooks-setasync/>)

**Unset:** [`pane.Hooks.UnsetAsync(...)`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhooks-unsetasync/>)

**List:** [`pane.Hooks.GetAllAsync()`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhooks-getallasync/>)

**Run now, without the event:** [`pane.Hooks.RunAsync(...)`](<https://libtmux.org/en/csharp/latest/reference/libtmux-tmuxhooks-runasync/>)

### C++

**Set:** [`session.set_hook(name, command)`](<https://libtmux.org/en/cxx/latest/reference/libtmux-session-set_hook/>): no [`Window`](<https://libtmux.org/en/cxx/latest/reference/libtmux-window/>)/[`Pane`](<https://libtmux.org/en/cxx/latest/reference/libtmux-pane/>) overload exists
at all

**Unset:** Not listed.

**List:** [`session.hooks()`](<https://libtmux.org/en/cxx/latest/reference/libtmux-session-hooks/>), [`server.global_hooks()`](<https://libtmux.org/en/cxx/latest/reference/libtmux-server-global_hooks/>)

**Run now, without the event:** Not listed.

### Swift

**Set:** [`server.setHook(name, to: command, at: index, in: scope)`](<https://libtmux.org/en/swift/latest/reference/server-sethook(_-to-at-in-)/>)

**Unset:** [`server.unsetHook(name, in: scope)`](<https://libtmux.org/en/swift/latest/reference/server-unsethook(_-in-)/>)

**List:** [`server.hooks(scope)`](<https://libtmux.org/en/swift/latest/reference/server-hooks(_-)/>)

**Run now, without the event:** [`server.runHook(name, in: scope)`](<https://libtmux.org/en/swift/latest/reference/server-runhook(_-in-)/>)

### Examples

tmux stores hook commands in indexed arrays, such as `after-new-window[0]`.

Include the array index in the hook name.
Include the array index in the hook name or pass `{ append: true }` to append.
[`Session.SetHooks`](<https://libtmux.org/en/go/latest/reference/tmux-session-sethooks/>) accepts indexed hook entries. Pass a context and check errors from
both mutations and reads; a successful write does not refresh earlier snapshots.
The `at:` parameter selects the array index.
Use `.append()` to add a command without choosing the next array index.

Set and list a session hook. The next section explains window and pane scope
limitations:

```python
session.set_hook("session-renamed", "display-message 'renamed'")
session.show_hooks()
```

```typescript
await session.setHook("session-renamed", "display-message 'renamed'");
await session.showHooks();
```

```go
if err := session.SetHook(ctx, "session-renamed", "display-message 'renamed'"); err != nil {
    return fmt.Errorf("set session hook: %w", err)
}
value, present, err := session.RawHook(ctx, "session-renamed")
if err != nil {
    return fmt.Errorf("read session hooks: %w", err)
}
fmt.Println("session-renamed:", value, "present:", present)
```

```rust
session.set_hook("session-renamed", "display-message 'renamed'").await?;
session.hooks().await?;
```

```java
session.hooks().set("session-renamed", "display-message 'renamed'");
session.hooks().all();
```

```csharp
await session.Hooks.SetAsync(new SetHookRequest("session-renamed", "display-message 'renamed'"));
await session.Hooks.GetAllAsync();
```

```cpp
session.set_hook("session-renamed", "display-message 'renamed'");
session.hooks(); // No session unset helper is listed above.
```

```swift
try await server.setHook("session-renamed", to: "display-message 'renamed'", in: .session(session.id.rawValue))
try await server.hooks(.session(session.id.rawValue))
```

<a id="window-and-pane-hook-scopes-are-mostly-fiction"></a>

## Supported hook scopes

tmux stores hooks globally or per session. Accepted `set-hook -w` or `-p` flags
do not imply a separate window or pane hook table, and `show-hooks` does not
provide a corresponding listing. Check the event's supported scope if a hook is
accepted but never fires.

Check `hooks().all()` when diagnosing a hook that does not fire. tmux can accept
a hook at an unsupported scope without an effective registration.

[`Pane::set_hook`](<https://libtmux.org/en/rs/latest/reference/pane-pane-set_hook/>) and [`Window::set_hook`](<https://libtmux.org/en/rs/latest/reference/window-window-set_hook/>) return [`Error::OptionScopeMismatch`](<https://libtmux.org/en/rs/latest/reference/error-error-optionscopemismatch/>)
for an unsupported scope.

[`HookScope`](<https://libtmux.org/en/swift/latest/reference/hookscope/>) restricts registration to `.global` and `.session`.

Use [`Session::set_hook`](<https://libtmux.org/en/cxx/latest/reference/libtmux-session-set_hook/>) or [`Server::global_hooks()`](<https://libtmux.org/en/cxx/latest/reference/libtmux-server-global_hooks/>). Window and pane handles
do not provide hook methods.

Options have window and pane tables of their own. The hook-scope limitation does
not apply to ordinary options.

## tmux version compatibility

The compatibility notes list these tmux requirements:

| Feature | Minimum tmux |
|---------|-------------|
| All options/hooks features | 3.2+ |
| Window/pane hook *scope flags* (`-w`, `-p`) accepted | 3.2+; see the supported-scope caveat above |
| `client-active`, `window-resized` hooks | 3.3+ |
| `pane-title-changed` hook | 3.5+ |

Check the library's supported tmux versions before using a version-specific
option or hook.

Use the command references for [show-options](https://libtmux.org/en/tmux/latest/manual/show-options/),
[set-option](https://libtmux.org/en/tmux/latest/manual/set-option/),
[show-hooks](https://libtmux.org/en/tmux/latest/manual/show-hooks/), and
[set-hook](https://libtmux.org/en/tmux/latest/manual/set-hook/) to check the flags and scope rules
for your tmux version.

<details>
<summary>tmux manual and source</summary>

The tmux manual defines [option scopes and inherited reads](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/tmux.1#L4725).
Unsetting a local value restores inheritance. Hook programs run in tmux when
their event occurs; see the [hook implementation](https://github.com/tmux/tmux/blob/94796f6b1182507efac8a272fc309a79e22e58a5/cmd-set-option.c).

</details>
