Skip to main content

Configuration

pmux stores its configuration at ~/.config/pmux/config.toml. The file is created by pmux init with sensible defaults. Most users will never need to edit it.

Config precedence

Configuration values are resolved in three layers, where each layer overrides the previous:

  1. Defaults -- built into the pmux binary.
  2. Config file -- values set in ~/.config/pmux/config.toml.
  3. Environment variables -- override both defaults and file values.

Run pmux config to see the effective values with source annotations showing where each value came from (default, file, or env).

Schema reference

TOML keyTypeDefaultEnv overrideDescription
namestringOS hostname--Display name shown on the paired mobile device
log_levelstringinfoPMUX_LOG_LEVELAgent log verbosity
server.urlstringhttps://signal.pmux.ioPMUX_SERVER_URLSignaling server base URL
server.api_versionstringv1PMUX_API_VERSIONAPI version prefix for server endpoints. Leave as v1
identity.key_pathstring~/.config/pmux/keys/PMUX_KEY_PATHDirectory containing the Ed25519 public key
identity.secret_backendstringautoPMUX_SECRET_BACKENDSecret storage backend
connection.reconnect_intervalduration5s--Delay between signaling reconnect attempts
connection.keepalive_intervalduration30s--WebSocket heartbeat interval (max 45s)
connection.max_mobile_connectionsinteger1PMUX_MAX_CONNECTIONSMaximum concurrent mobile connections
connection.force_relaybooleanfalsePMUX_FORCE_RELAYForce ICE into relay-only (TURN) mode. Testing/debugging only
tmux.socket_namestringpmuxPMUX_SOCKET_NAMEtmux socket name for the -L flag
tmux.tmux_pathstring(empty)PMUX_TMUX_PATHAbsolute path to the tmux binary
update.enabledbooleantruePMUX_UPDATE_ENABLEDEnable background update checks
update.check_intervalduration24hPMUX_UPDATE_INTERVALHow often the agent checks for a new release
power.keep_awakebooleanfalsePMUX_KEEP_AWAKEPrevent the host from sleeping while the agent runs

Top-level

name -- the host display name shown on the paired mobile device. Set during pmux init using the OS hostname. Edit the value directly in config.toml to change it. If unset, the agent resolves the OS hostname at runtime.

log_level -- controls the agent's log verbosity. Accepted values are debug, info, warn, and error. The default is info. Useful for troubleshooting: set to debug for verbose output, or error to suppress routine messages. Logs are written to ~/.config/pmux/agent.log.

[server]

url -- the signaling server base URL. Accepts http://, https://, ws://, or wss:// schemes. The agent converts HTTP URLs to WebSocket URLs internally when connecting. Validation rejects any URL that does not start with one of these four schemes.

The environment variable PMUX_AGENT_SIGNAL_URL is also supported, but PMUX_SERVER_URL takes precedence when both are set.

api_version -- the API version prefix applied to all signaling server HTTP and WebSocket endpoints. Leave it set to v1 (the default); endpoints are prefixed with /<api_version>.

[identity]

key_path -- the directory where ed25519.pub (the Ed25519 public key) is stored. The private key is not stored as a file in this directory. It lives in the secret backend instead.

secret_backend -- controls where private keys and shared secrets are stored. Three values are accepted:

  • auto (default) -- tries the system keychain first. Falls back to an encrypted file if the keychain is unavailable.
  • keyring -- uses macOS Keychain or Linux SecretService via D-Bus. Fails with an error if neither is available.
  • file -- uses NaCl SecretBox (XSalsa20-Poly1305) encryption. Stores secrets at <key_path>/secrets.enc.

Validation rejects any value other than auto, keyring, or file.

[connection]

reconnect_interval -- a Go duration string (e.g., 5s, 1m30s, 500ms). Controls the delay between reconnect attempts when the signaling server connection drops. Must be a valid Go duration or validation fails.

keepalive_interval -- a Go duration string. Controls the WebSocket heartbeat interval used to maintain the signaling connection. Must be a valid Go duration. The signaling server marks a host offline after 90 seconds of heartbeat silence, so the interval is capped at half that window -- a larger value would let a single missed heartbeat flap a live host offline. A value over 45s is not a validation error: it is silently clamped to 45s, and pmux config annotates the clamped value with [clamped to 45s].

max_mobile_connections -- the maximum number of concurrent mobile connections. Must be 1 in the current release, which enforces the single-pairing model. Validation rejects any other value.

force_relay -- a boolean (default false). When true, the agent restricts ICE to relay-only mode (ICETransportPolicyRelay), forcing all WebRTC traffic through a TURN server instead of allowing a direct peer-to-peer path. This is a testing and debugging switch, not a production setting -- leave it false for normal use, since enabling it disables direct connections entirely. See Forcing TURN relay below for when and how to use it.

[tmux]

socket_name -- the tmux socket name passed to -L. All pmux commands use this socket. Changing it creates a completely separate tmux namespace. The default value pmux keeps Pocketmux sessions isolated from regular tmux sessions. Must not be empty.

tmux_path -- the absolute path to the tmux binary. pmux init discovers and saves this automatically using $PATH lookup. This ensures the agent can find tmux even when spawned non-interactively, where $PATH may be minimal. If empty, the agent falls back to searching $PATH at runtime. Set this manually if tmux moves to a different location after initialization.

[update]

enabled -- a boolean (default true). When true, the agent periodically checks GitHub for a newer release in the background and prints a one-line banner (A new version of pmux is available...) on your next pmux command. Set to false to disable background checks; pmux update still works on demand. Background checks are also skipped automatically for dev builds.

check_interval -- a Go duration string (default 24h). How often the background checker queries GitHub for a new release.

[power]

keep_awake -- a boolean (default false). When true, the agent prevents the host from going to sleep for as long as it is running, so the mobile app can reach the host on demand. A sleeping machine drops its signaling connection and shows offline, and the mobile app cannot wake it -- enabling this keeps the host reachable.

The inhibitor is released as soon as the agent stops; no persistent power setting is changed, so there is nothing to restore. The mechanism is OS-native:

  • macOS -- holds a caffeinate idle-sleep assertion.
  • Linux -- holds a systemd-logind sleep inhibitor lock (requires systemd).
  • Windows (WSL) -- requests SetThreadExecutionState on the Windows host via interop.

This is best-effort. On macOS it does not override closing the laptop lid (clamshell sleep) or a forced sleep on critically low battery; on Linux it has no effect on systems without systemd. The agent logs whether the inhibitor was successfully engaged.

Forcing TURN relay (testing & debugging)

Pocketmux normally lets WebRTC's ICE negotiation pick the best path between the mobile app and the agent -- usually a direct peer-to-peer connection, falling back to a TURN relay only when a direct path can't be established. Because the direct path almost always wins, the TURN relay is rarely exercised, which makes it hard to confirm the relay actually works.

The force-relay switch restricts ICE to relay-only mode on a peer, so every connection must traverse a TURN server. A successful connection then proves the relay path works end to end; a failure isolates TURN (rather than ICE in general) as the problem. Both ends default to off, and the normal "all paths" behavior is unchanged unless you opt in.

This is a diagnostic instrument, not a production feature. In relay-only mode there is no direct fallback, so if the TURN server is unreachable the connection simply fails.

On the agent

Set connection.force_relay = true in config.toml, or export PMUX_FORCE_RELAY=1 in the environment the agent is spawned from. Verify it took effect:

pmux config | grep force_relay
# connection.force_relay = true (env)

When enabled, the agent creates its peer connection with ICETransportPolicyRelay and logs the selected ICE candidate pair on connect (local/remote candidate types and a usingRelay flag), so you can confirm in ~/.config/pmux/agent.log whether the relay was actually used.

In the mobile app

Open Settings → Connection and enable Force TURN Relay (Debug). This:

  • restricts the device's RTCPeerConnection to iceTransportPolicy: 'relay';
  • fetches TURN credentials even if Allow TURN Relay is turned off (relay-only with no TURN server would otherwise fail for a misleading reason);
  • logs the negotiated transport on connect to the in-app Logs screen -- look for a line reading Connection transport: TURN relay [forceRelay] (versus P2P direct in normal mode).

Interpreting a test

For a true end-to-end relay test, enable the switch on both ends, then connect:

  • Connection succeeds -- TURN works. The agent log and the mobile Logs screen both report the relay transport.
  • Connection fails -- the TURN path is broken (credentials, server reachability, or firewall). Because relay-only removes the direct fallback, this cleanly distinguishes a TURN problem from a general ICE/connectivity problem.

Turn both switches back off when you're done to restore normal direct-first behavior.

Annotated example

A complete config.toml with all fields set:

# Host display name (shown on paired mobile device)
name = "my-workstation"
# Log level: "debug", "info", "warn", or "error" (env: PMUX_LOG_LEVEL)
log_level = "info"

[server]
# Signaling server URL (env: PMUX_SERVER_URL)
url = "https://signal.pmux.io"
# API version prefix; leave as "v1" (env: PMUX_API_VERSION)
api_version = "v1"

[identity]
# Ed25519 key directory (env: PMUX_KEY_PATH)
key_path = "~/.config/pmux/keys/"
# Secret storage: "auto", "keyring", or "file" (env: PMUX_SECRET_BACKEND)
secret_backend = "auto"

[connection]
# Reconnect delay after signaling disconnection
reconnect_interval = "5s"
# WebSocket heartbeat interval
keepalive_interval = "30s"
# Maximum mobile connections (must be 1)
max_mobile_connections = 1
# Force ICE relay-only (TURN) for testing/debugging (env: PMUX_FORCE_RELAY)
force_relay = false

[tmux]
# tmux socket name for -L flag (env: PMUX_SOCKET_NAME)
socket_name = "pmux"
# Absolute path to tmux binary (env: PMUX_TMUX_PATH)
# Resolved automatically during 'pmux init'. Set manually if tmux moves.
tmux_path = "/opt/homebrew/bin/tmux"

[update]
# Enable background update checks (env: PMUX_UPDATE_ENABLED)
enabled = true
# How often to check for a new release (env: PMUX_UPDATE_INTERVAL)
check_interval = "24h"

[power]
# Keep the host awake while the agent runs (env: PMUX_KEEP_AWAKE)
keep_awake = false

When pmux init creates the file, all values are commented out so they act as documentation without overriding the built-in defaults.

Environment variables

VariableConfig equivalentNotes
PMUX_SERVER_URLserver.urlTakes precedence over both the config file and PMUX_AGENT_SIGNAL_URL
PMUX_AGENT_SIGNAL_URLserver.urlAlternative to PMUX_SERVER_URL; lower precedence when both are set
PMUX_API_VERSIONserver.api_versionLeave as v1
PMUX_LOG_LEVELlog_levelMust be debug, info, warn, or error
PMUX_KEY_PATHidentity.key_pathOverrides the key directory path
PMUX_SECRET_BACKENDidentity.secret_backendMust be auto, keyring, or file
PMUX_MAX_CONNECTIONSconnection.max_mobile_connectionsParsed as an integer. Must be 1
PMUX_FORCE_RELAYconnection.force_relayTruthy values (true, 1, yes) enable relay-only ICE. Testing/debugging only
PMUX_SOCKET_NAMEtmux.socket_nameOverrides the tmux socket name
PMUX_TMUX_PATHtmux.tmux_pathOverrides the tmux binary path
PMUX_UPDATE_ENABLEDupdate.enabledTruthy values (true, 1, yes) enable background update checks
PMUX_UPDATE_INTERVALupdate.check_intervalGo duration string (e.g. 24h)
PMUX_KEEP_AWAKEpower.keep_awakeTruthy values (true, 1, yes) keep the host awake while the agent runs

File paths

All files and directories pmux creates:

PathCreated byPurpose
~/.config/pmux/pmux initConfiguration root directory
~/.config/pmux/config.tomlpmux initConfiguration file
~/.config/pmux/keys/pmux initKey storage directory
~/.config/pmux/keys/ed25519.pubpmux initEd25519 public key
~/.config/pmux/keys/secrets.encpmux initEncrypted secrets (file backend only)
~/.config/pmux/paired_devices.jsonpmux pairPaired mobile device information
~/.config/pmux/agent.pidAgent startupBackground agent PID file
~/.config/pmux/agent.logAgent startupAgent debug log