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:
- Defaults -- built into the pmux binary.
- Config file -- values set in
~/.config/pmux/config.toml. - 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 key | Type | Default | Env override | Description |
|---|---|---|---|---|
name | string | OS hostname | -- | Display name shown on the paired mobile device |
log_level | string | info | PMUX_LOG_LEVEL | Agent log verbosity |
server.url | string | https://signal.pmux.io | PMUX_SERVER_URL | Signaling server base URL |
server.api_version | string | v1 | PMUX_API_VERSION | API version prefix for server endpoints. Leave as v1 |
identity.key_path | string | ~/.config/pmux/keys/ | PMUX_KEY_PATH | Directory containing the Ed25519 public key |
identity.secret_backend | string | auto | PMUX_SECRET_BACKEND | Secret storage backend |
connection.reconnect_interval | duration | 5s | -- | Delay between signaling reconnect attempts |
connection.keepalive_interval | duration | 30s | -- | WebSocket heartbeat interval (max 45s) |
connection.max_mobile_connections | integer | 1 | PMUX_MAX_CONNECTIONS | Maximum concurrent mobile connections |
connection.force_relay | boolean | false | PMUX_FORCE_RELAY | Force ICE into relay-only (TURN) mode. Testing/debugging only |
tmux.socket_name | string | pmux | PMUX_SOCKET_NAME | tmux socket name for the -L flag |
tmux.tmux_path | string | (empty) | PMUX_TMUX_PATH | Absolute path to the tmux binary |
update.enabled | boolean | true | PMUX_UPDATE_ENABLED | Enable background update checks |
update.check_interval | duration | 24h | PMUX_UPDATE_INTERVAL | How often the agent checks for a new release |
power.keep_awake | boolean | false | PMUX_KEEP_AWAKE | Prevent 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
caffeinateidle-sleep assertion. - Linux -- holds a systemd-logind sleep inhibitor lock (requires systemd).
- Windows (WSL) -- requests
SetThreadExecutionStateon 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
RTCPeerConnectiontoiceTransportPolicy: '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](versusP2P directin 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
| Variable | Config equivalent | Notes |
|---|---|---|
PMUX_SERVER_URL | server.url | Takes precedence over both the config file and PMUX_AGENT_SIGNAL_URL |
PMUX_AGENT_SIGNAL_URL | server.url | Alternative to PMUX_SERVER_URL; lower precedence when both are set |
PMUX_API_VERSION | server.api_version | Leave as v1 |
PMUX_LOG_LEVEL | log_level | Must be debug, info, warn, or error |
PMUX_KEY_PATH | identity.key_path | Overrides the key directory path |
PMUX_SECRET_BACKEND | identity.secret_backend | Must be auto, keyring, or file |
PMUX_MAX_CONNECTIONS | connection.max_mobile_connections | Parsed as an integer. Must be 1 |
PMUX_FORCE_RELAY | connection.force_relay | Truthy values (true, 1, yes) enable relay-only ICE. Testing/debugging only |
PMUX_SOCKET_NAME | tmux.socket_name | Overrides the tmux socket name |
PMUX_TMUX_PATH | tmux.tmux_path | Overrides the tmux binary path |
PMUX_UPDATE_ENABLED | update.enabled | Truthy values (true, 1, yes) enable background update checks |
PMUX_UPDATE_INTERVAL | update.check_interval | Go duration string (e.g. 24h) |
PMUX_KEEP_AWAKE | power.keep_awake | Truthy values (true, 1, yes) keep the host awake while the agent runs |
File paths
All files and directories pmux creates:
| Path | Created by | Purpose |
|---|---|---|
~/.config/pmux/ | pmux init | Configuration root directory |
~/.config/pmux/config.toml | pmux init | Configuration file |
~/.config/pmux/keys/ | pmux init | Key storage directory |
~/.config/pmux/keys/ed25519.pub | pmux init | Ed25519 public key |
~/.config/pmux/keys/secrets.enc | pmux init | Encrypted secrets (file backend only) |
~/.config/pmux/paired_devices.json | pmux pair | Paired mobile device information |
~/.config/pmux/agent.pid | Agent startup | Background agent PID file |
~/.config/pmux/agent.log | Agent startup | Agent debug log |