Read and change scoped options
Use a local user option to record which workspace created a session. Read it
without inheritance when deciding whether the session belongs to that workspace.
only_if_unset refuses an existing local value; it does not compare an expected
owner or provide a workspace transaction.
The complete example also sets and removes a window override, checks that the inherited value is restored, and preserves an empty sparse array entry. It opens the supplied endpoint and creates/removes its own session. The repository runner supplies an isolated server and verifies cleanup:
$ mise exec -- escript tools/run_examples.escript options-module(options_demo).-moduledoc "Use local options to mark workspace ownership without inheritance.".-export([run/2]).
-spec run(binary(), binary()) -> map().run(Socket, Executable) -> {ok, Server} = tmux_server:open( #{socket_path => Socket, executable => Executable}), tmux_scope:run_or_error(fun() -> {ok, Session} = tmux_session:create(Server, #{name => <<"options">>, launch => #{argv => [<<"/bin/cat">>]}}), tmux_scope:run_or_error(fun() -> Owner = <<"@libtmux-owner">>, none = tmux_option:get(Session, Owner, #{}), {ok, _} = tmux_option:set(Session, Owner, <<"build-workspace">>, #{only_if_unset => true}), {ok, <<"build-workspace">>} = tmux_option:get(Session, Owner, #{}), {ok, Window} = tmux_window:create(Session, #{launch => #{argv => [<<"/bin/cat">>]}}), {ok, [<<"build-workspace">>, none]} = tmux_option:get_many([Session, Window], Owner, #{}), none = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, Effective} = tmux_option:get(Window, <<"remain-on-exit">>, #{inherit => true}), {ok, _} = tmux_option:set(Window, <<"remain-on-exit">>, <<"on">>), {ok, <<"on">>} = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, _} = tmux_option:unset(Window, <<"remain-on-exit">>), none = tmux_option:get(Window, <<"remain-on-exit">>, #{}), {ok, Effective} = tmux_option:get(Window, <<"remain-on-exit">>, #{inherit => true}), Env = <<"update-environment">>, {ok, _} = tmux_option:set(Session, {Env, 7}, <<>>), {ok, #{7 := <<>>}} = tmux_option:get(Session, Env, #{}), none = tmux_option:get(Session, {Env, 8}, #{}), #{owner => <<"build-workspace">>, restored_inheritance => true, empty_entry_preserved => true, missing_entry => true} end, fun() -> {ok, _} = tmux_session:kill(Session), ok end) end, fun() -> ok = tmux_server:close(Server) end).{ "owner": "build-workspace", "restored_inheritance": true, "empty_entry_preserved": true, "missing_entry": true}Select the table explicitly¶
| Scope argument | Table |
|---|---|
| Registered session record¶ | Local session options |
| Registered physical window record¶ | Local window options, shared by its memberships |
| Registered pane record¶ | Local pane options |
{server, Server}¶ | Server-wide options |
{session_defaults, Server}¶ | Global session defaults |
{window_defaults, Server}¶ | Global window defaults |
A physical window has no universal parent session. Session options require a session record; passing a pane to a session option fails rather than choosing an incidental session. Built-in names can override tmux’s native scope flags; the wrapper checks their source metadata before dispatch to prevent that.
get/3 uses local-only reads with #{}. #{inherit => true} follows the
selected table’s parents: session defaults, or window/window defaults for a
pane. User options follow the same table ancestry. Server options have no
parent. There is no inheritance from a session table to a window table.
tmux_option:get_many/3 reads one scalar key from one to seven local rows on
the same registered endpoint. Results preserve input order, including none
for absent values. The example checks session ownership and the window’s
independent local table together. Arrays, indexed entries, command options,
global tables and names outside the batch API’s ASCII grammar use get/3.
Each batch uses one native command sequence plus the normal identity-preflight client, with native ID observations around every row’s read. Aggregate stdout is limited to 1 MiB and stderr to 64 KiB, with a 2500 ms command deadline. Command or decoding failures reject the entire batch. These are interval observations: a queued reference may outlive a removed window, and target checks do not establish atomic topology or stronger server-incarnation identity. See ADR 0003.
Preserve absence and bytes¶
none means the selected local option or requested array entry is absent.
{ok, <<>>} means a known empty value. A whole array returns {ok, Entries}
with numeric indexes as map keys; an empty local array returns {ok, #{}}.
An unloaded graph field is unrelated to these live reads.
Set array entries with {Name, Index}. The API deliberately avoids whole-array
assignment and its separator grammar. unset/2 removes an entry or local option;
removing a local option restores inheritance. Unsetting a global built-in resets
its tmux default. Non-numeric array keys are outside this API; an observed array
with such keys fails decoding instead of silently dropping entries.
Values are NUL-free binaries, including arbitrary bytes. Names are literal;
#{...} in a user-option name does not expand. Prefixes, aliases and bracket
syntax in names are rejected. A scalar value is passed without -F, although
tmux may interpret a stored format or executable option later. Use this API
only with trusted option names and values; it is not an external write policy.
append uses tmux’s -a behavior for the selected type. only_if_unset uses
-o and reports already-set as an error. Empty flag values retain tmux’s toggle
behavior; use explicit <<"on">> or <<"off">> when state must be predictable.
Mutations are not retried after a timeout or unknown outcome.
Discover version support¶
The generated catalogue lists canonical names, scopes,
parser types, arrays and hooks from pinned release commits.
tmux_option:describe/2 and catalogue/1 read that metadata without I/O.
Built-ins have exact source catalogues for every release from 3.3a through
3.8, including intermediate patch releases. Tracking builds and unknown
versions return unsupported_option_catalogue; unavailable built-ins return
unsupported_tmux_option. User options do not depend on a built-in catalogue.
Hooks are executable commands and are rejected by this API, including hook
names discovered in the catalogue. Use tmux_hook:get/3 to read hooks and
tmux_hook:set/3 for registration; the hook guide covers their
scope, execution and cleanup.
Raw commands are also available for deliberate newer-version integration.
A missing target remains an operational error, never a missing option.