obsctl v0.2.0
๐ก obsctl
Your OBS control roomโright inside the terminal.
A fast Crystal TUI, automation-friendly CLI, and resilient local daemon for OBS Studio.
๐๏ธ Control ยท ๐ Observe ยท ๐ค Automate ยท ๐ Stay connected
Get started ยท Explore the TUI ยท Automate with the CLI ยท Read the docs
obsctl gives streamers, operators, and automation scripts one dependable control surface for OBS Studio. Use the responsive terminal dashboard while you are live, run precise one-shot commands from scripts, or keep the local daemon running as a user service.
โญโ OBSCTL // BROADCAST COMMAND CENTER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ daemon: connected โ OBS: connected scene: Main Camera โ
โโ LIVE TELEMETRY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ CPU 3.2% FPS 60.0 MEM 742MB NET 5842kbps โ
โโ Scenes โโโโโโโโโโโโโโโโโฌโ Audio Matrix โโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โถ Main Camera โ โ Mic/Aux 72% โโโโโโโโโโ โ
โ Screen Share โ โ Desktop Audio 48% โโโโโโโโโโ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โจ Why obsctl?
| Capability | What it gives you | |
|---|---|---|
| ๐๏ธ | Live terminal dashboard | Scenes, audio, profiles, collections, output state, telemetry, logs, and a command palette in one responsive view. |
| โก | Fast interactions | Optimistic UI updates, debounced volume changes, incremental rendering, and safe terminal resize reflow. |
| ๐ง | One OBS connection | A local daemon owns the WebSocket, eliminating competing CLI/TUI connections and centralizing reconnect behavior. |
| ๐ค | Automation-ready CLI | Stable commands, JSON envelopes, canonical error codes, and meaningful exit statuses for scripts and CI. |
| ๐ | Resilient operation | Bounded reconnect backoff, explicit reconnect control, state subscriptions, and secret-safe diagnostics. |
| ๐จ | Made for humans | 29 built-in themes, custom colors, Unicode and ASCII modes, English/Ukrainian UI surfaces, and keyboard-first navigation. |
| ๐งฑ | Built on CryTUI | An in-tree immediate-mode Crystal TUI library inspired by Ratatui and tested with memory, ANSI, and real PTY backends. |
๐ Quick start
Prerequisites
- Linux
- OBS Studio with obs-websocket 5.x enabled
- Crystal 1.20.2+ and Shards when building from source
- A UTF-8 terminal; a Nerd Font is recommended for the richest icon set
1. Build
git clone https://github.com/worxbend/obsctl.git
cd obsctl
shards install
make release
install -Dm755 bin/obsctl ~/.local/bin/obsctl
The release binary is written to bin/obsctl. Prebuilt Linux AMD64 archives are also available on the Releases page.
2. Initialize
obsctl init
obsctl validate-config
The default configuration lives at ~/.config/obsctl/config.yml. Override it with --config PATH or OBSCTL_CONFIG.
If OBS authentication is enabled, export its password before starting the server:
export OBS_WEBSOCKET_PASSWORD='your OBS WebSocket password'
No password? No problemโwhen the variable is absent, obsctl attempts the connection with an empty password.
3. Start the daemon and TUI
In one terminal:
obsctl server --headless
In another:
obsctl
Once connected, import live scene and audio names while preserving your local settings:
obsctl dump-config
[!TIP] Scene and audio names discovered from OBS work immediately. Running
dump-configis useful for adding memorable aliases and shortcuts, but it is not required before using the TUI.
๐๏ธ The control room
The TUI is a thin local client: it subscribes to daemon state, OBS events, and logs, then renders them through CryTUI. It does not open another OBS WebSocket connection.
Keyboard map
| Key | Action |
|---|---|
s / a / p / c |
Focus scenes, audio, profiles, or collections |
โ โ or j k |
Move within the focused panel |
Ctrl + arrows or Ctrl-h/j/k/l |
Move between panels |
Enter |
Activate the focused scene, profile, or collection |
m |
Toggle the focused audio input mute state |
โ โ or h l |
Lower or raise focused input volume |
/ or : |
Open the command palette |
Tab / Shift-Tab |
Cycle command completions |
Ctrl-T or F2 |
Open the appearance lab |
r / D / R |
Reload config, dump config, or reconnect OBS |
q or Ctrl-C |
Quit |
Rapid volume keypresses update the display immediately and coalesce into one OBS command 120 ms after input stops. Terminal shrinking and expansion trigger a full safe repaint; normal frames return to cell-level incremental updates.
Command palette
Press / and use the same grammar as the CLI:
/scene "Main Camera"
/mute Mic/Aux
/vol "Desktop Audio" 65
/profile Streaming
/collection Gaming
/stream
/rec
/status
/reconnect
๐งฐ CLI & automation
The daemon-backed CLI is designed to be pleasant interactively and predictable inside scripts.
# Status
obsctl status
obsctl obs-status
obsctl server-status
# Scenes and audio
obsctl scene main
obsctl mute mic
obsctl unmute mic
obsctl toggle-mute mic
obsctl volume "Desktop Audio" 70
# Studio and output controls
obsctl stream
obsctl record
obsctl reconnect
# Configuration and lifecycle
obsctl validate-config
obsctl dump-config
obsctl reload-config
obsctl shutdown-server
Aliases, shortcuts, exact OBS names, and case-insensitive names are supported. Quote names containing spaces.
JSON mode
Add --json before or after a scriptable command:
obsctl --json status
obsctl scene main --json
Every JSON invocation writes exactly one envelope to stdout:
{
"ok": true,
"result": {"message": "scene set: Main Camera"},
"error": null,
"exit_code": 0
}
Failures use canonical error codes and matching process exit statuses, making them straightforward to handle in shell scripts and other tools. See the command reference for the full grammar, supported JSON commands, error codes, and status schema.
๐๏ธ Architecture
flowchart LR
OBS["๐ฅ OBS Studio<br/>obs-websocket 5.x"]
D["๐ง obsctl server<br/>single connection owner"]
T["๐๏ธ CryTUI dashboard"]
C["โ๏ธ CLI / scripts"]
S["๐ ๏ธ systemd --user"]
OBS <-->|WebSocket| D
D <-->|Unix socket IPC| T
D <-->|Unix socket IPC| C
S -. supervises .-> D
The daemon is the authoritative state owner. This boundary provides:
- exactly one OBS WebSocket connection per user session;
- shared state and event delivery across every local client;
- centralized reconnect, validation, logging, and secret handling;
- short-lived CLI processes without repeated OBS handshakes.
The Unix socket lives under $XDG_RUNTIME_DIR/obsctl/ when an XDG runtime directory is available, with a user-specific /tmp/obsctl-$UID/ fallback. Control remains localโthere is no network-facing obsctl API.
๐ง Configuration
A minimal configuration looks like this:
version: 1
connection:
host: 127.0.0.1
port: 4455
password_env: OBS_WEBSOCKET_PASSWORD
reconnect:
enabled: true
endless: true
ui:
theme: default
advanced_ui: true
show_icons: true
locale: en
scenes:
- name: Main Camera
alias: main
shortcut: "1"
audio:
inputs:
- name: Mic/Aux
alias: mic
shortcut: m
Important behavior:
- secrets belong in environment variables; plaintext password values produce a secret-safe warning;
- unknown top-level fields are rejected instead of being silently discarded;
- config rewrites are atomic and preserve backups;
dump-configrefuses to create ambiguous aliases or shortcuts;OBSCTL_LOCALEoverridesui.locale; supported UI locales areenanduk;- custom themes can override any subset of the semantic color palette.
See the complete configuration reference.
๐ ๏ธ Run as a user service
No root daemon is required. Install a systemd --user unit using the current binary path:
obsctl service install
obsctl service start
obsctl service status
Other lifecycle commands:
obsctl service stop
obsctl service restart
obsctl service uninstall
The generated unit lives at ~/.config/systemd/user/obsctl.service.
๐ฉบ Troubleshooting
Show connection and retry diagnostics
obsctl --log-level debug server --headless
Server logs are mirrored to stderr and persisted at ~/.local/state/obsctl/obsctl.log. Passwords and generated authentication strings are redacted from both sinks. WebSocket resets include the close code, reason, reconnect attempt, and next delay.
The CLI says the server is unavailable
Start it directly:
obsctl server --headless
Or install/start the user service. Thin client commands exit with status 3 when the daemon or OBS connection is unavailable.
OBS was offline during startup
Reconnect is enabled by default. Check obsctl server-status, then request an immediate attempt with obsctl reconnect. If reconnect.enabled: false, restart the server after OBS becomes available.
๐งโ๐ป Development
shards install
make format
make test
make build
make release
make lint
The local test suite is deterministic and does not require OBS Studio. It uses a fake obs-websocket server, Unix-socket integration tests, memory rendering, ANSI assertions, and real PTY lifecycle probes.
Optional cross-implementation fixture verification against a sibling ../obsctl-rs checkout:
make contract-rs-compat
Strict compatibility mode requires a recognized fixture root in both repositories. See docs/protocol.md for the contract model.
๐ Documentation
| Guide | Contents |
|---|---|
| Commands | Complete CLI/palette grammar, JSON envelopes, errors, and status semantics |
| Configuration | Connection, reconnect, UI, theme, alias, and persistence settings |
| Protocol | IPC framing, subscriptions, state contracts, and compatibility fixtures |
| CryTUI research | Ratatui analysis, Crystal library evaluation, rendering architecture, and parity evidence |
๐ค Contributing
Issues, focused bug reports, documentation improvements, and pull requests are welcome. For behavior changes, include a regression test at the narrowest useful layer and run the development checks above before opening a PR.
Useful reports include:
- your OBS Studio and obs-websocket versions;
- terminal name, dimensions, font, and
$TERMfor rendering issues; - sanitized
obsctl.logexcerpts for connection problems; - the exact command, expected result, and actual result.
Please never include OBS passwords or generated authentication strings.
๐ License
obsctl is released under the MIT license.
Built with ๐ Crystal, terminal escape sequences, and an unreasonable love for reliable broadcast controls.
If obsctl improves your control room, consider starring the repository. โญ
obsctl
- 2
- 0
- 3
- 0
- 2
- 12 minutes ago
- November 24, 2019
Sun, 19 Jul 2026 18:41:51 GMT