Sentinel is a terminal-first workspace delivered as a single binary. It gives you an interactive browser UI to manage tmux sessions, run standalone terminals, and inspect active host terminals in one place.
No Electron. No cloud relay. Just your machine and your shell.
- Real PTY terminals in the browser.
- tmux session, window, and pane control with live attach.
- Built-in tmux recovery journal with restore after reboot/power loss.
- Standalone shell tabs that are not tied to tmux.
- Optional token auth and origin validation.
- One binary and simple operations.
Session and pane management with full tmux visibility.
Interactive terminal focused on the active workspace.
Responsive terminal workflow with touch-first controls.
Theme customization and terminal identity tuning.
Token authentication setup for protected access.
curl -fsSL https://raw.githubusercontent.com/opus-domini/sentinel/main/install.sh | bashWhat install.sh does:
- regular user:
- installs binary to
~/.local/bin/sentinel - installs
~/.config/systemd/user/sentinel.service - starts or restarts the service (
systemctl --user start|restart sentinel)
- installs binary to
- root:
- installs binary to
/usr/local/bin/sentinel - installs
/etc/systemd/system/sentinel.service - starts or restarts the service (
systemctl start|restart sentinel)
- installs binary to
- macOS:
- installs binary to
~/.local/bin/sentinel(orINSTALL_DIR) - regular user installs
~/Library/LaunchAgents/io.opusdomini.sentinel.plist - root installs
/Library/LaunchDaemons/io.opusdomini.sentinel.plist - starts or restarts service via
launchctl
- installs binary to
- optional persistence:
systemctl --user enable sentinel(regular user)systemctl enable sentinel(root)
- optional auto-update:
ENABLE_AUTOUPDATE=1 curl -fsSL https://raw.githubusercontent.com/opus-domini/sentinel/main/install.sh | bash- or later:
sentinel service autoupdate install - to force root/system scope on Linux:
sentinel service autoupdate install --scope system
go install github.com/opus-domini/sentinel/cmd/sentinel@latestOr from local checkout:
go install ./cmd/sentinelGo puts the binary in GOBIN (or $(go env GOPATH)/bin when GOBIN is empty).
If needed:
export PATH="$(go env GOPATH)/bin:$PATH"For development from source, see CONTRIBUTING.md.
install.sh already starts (or restarts, if already running) the service for you.
If installed as regular user:
systemctl --user status sentinel
journalctl --user -u sentinel -fIf installed as root:
systemctl status sentinel
journalctl -u sentinel -fIf installed on macOS:
sentinel service status
tail -f ~/.sentinel/logs/sentinel.out.logOptional: persist across reboot/login.
# regular user
systemctl --user enable sentinel
# root/system install
systemctl enable sentinelOptional: enable daily updater timer.
sentinel service autoupdate install
sentinel service autoupdate statusFor Linux root/system scope:
sentinel service autoupdate install --scope system
sentinel service autoupdate status --scope systemOpen http://127.0.0.1:4040.
Default binding is local-only (127.0.0.1:4040).
Sentinel uses:
- config file:
~/.sentinel/config.toml - data dir:
~/.sentinel
The config file is created on first startup.
sentinelorsentinel serve: start server.sentinel service install: install local user service (systemd on Linux, launchd on macOS).sentinel service uninstall: remove local user service (systemd on Linux, launchd on macOS).sentinel service status: show service state.sentinel service autoupdate install|uninstall|status: manage daily updater timer (Linux/macOS).sentinel doctor: print environment diagnostics.sentinel recovery list: list persisted recovery sessions.sentinel recovery restore: restore snapshot from local recovery journal.sentinel update check|apply|status: check and apply binary updates.sentinel -h/sentinel --help: help.sentinel -v/sentinel --version: version.
Examples:
sentinel serve
sentinel service install
sentinel service status
sentinel service autoupdate install
sentinel update check
sentinel doctor
sentinel recovery list
sentinel recovery restore --snapshot 42
sentinel --help
sentinel --versionBy default Sentinel listens on:
listen = "127.0.0.1:4040"For remote access, update ~/.sentinel/config.toml:
listen = "0.0.0.0:4040"
token = "strong-token"
allowed_origins = ["https://sentinel.example.com"]
log_level = "info"After editing config, restart the service.
Regular user service:
systemctl --user restart sentinelRoot/system service:
systemctl restart sentinelSecurity recommendations:
- never expose Sentinel without token auth;
- prefer private networking (Tailscale) or authenticated Cloudflare Tunnel;
- set
allowed_originsexplicitly when using reverse proxies.
Environment variables override config file values and are useful for technical/automation scenarios.
| Environment variable | Config key | Default | Description |
|---|---|---|---|
SENTINEL_LISTEN |
listen |
127.0.0.1:4040 |
Listen address |
SENTINEL_TOKEN |
token |
disabled | Bearer token for API and WS auth |
SENTINEL_ALLOWED_ORIGINS |
allowed_origins |
auto | Comma-separated allowlist |
SENTINEL_LOG_LEVEL |
log_level |
info |
debug, info, warn, error |
SENTINEL_DATA_DIR |
n/a | ~/.sentinel |
Data directory |
SENTINEL_WATCHTOWER_ENABLED |
watchtower_enabled |
true |
Enable watchtower activity projector |
SENTINEL_WATCHTOWER_TICK_INTERVAL |
watchtower_tick_interval |
1s |
Activity collection interval |
SENTINEL_WATCHTOWER_CAPTURE_LINES |
watchtower_capture_lines |
80 |
Lines captured per pane tail |
SENTINEL_WATCHTOWER_CAPTURE_TIMEOUT |
watchtower_capture_timeout |
150ms |
Timeout per pane capture |
SENTINEL_WATCHTOWER_JOURNAL_ROWS |
watchtower_journal_rows |
5000 |
Max activity journal rows retained |
SENTINEL_RECOVERY_ENABLED |
recovery_enabled |
true |
Enable recovery journal/restore engine |
SENTINEL_RECOVERY_SNAPSHOT_INTERVAL |
recovery_snapshot_interval |
5s |
Snapshot polling interval |
SENTINEL_RECOVERY_MAX_SNAPSHOTS |
recovery_max_snapshots |
300 |
Max snapshots retained per session |
Sentinel exposes watchtower operational state via API:
GET /api/tmux/activity/stats: current runtime counters and last collect metadata.GET /api/tmux/activity/delta?since=<rev>&limit=<n>: journal deltas byglobalRev.
Key fields in /api/tmux/activity/stats:
collectTotal: total collect cycles since startup.collectErrorsTotal: collect cycles that returned error.lastCollectDurationMs: duration of latest cycle.lastCollectSessions: sessions seen in latest cycle.lastCollectChanged: sessions with effective activity change in latest cycle.globalRev: latest persisted activity revision.
For local performance baselines, run:
go test -run=^$ -bench=BenchmarkCollectFiftyPanes -benchmem ./internal/watchtowerThe tmux route publishes client runtime counters to:
window.__SENTINEL_TMUX_METRICS
Useful fields:
wsMessages,wsOpenCount,wsCloseCount,wsReconnectssessionsRefreshCount,inspectorRefreshCount,recoveryRefreshCountfallbackRefreshCount(poll fallback executions while events WS is down)deltaSyncCount,deltaSyncErrors,deltaOverflowCount
Expected healthy behavior:
- while
/ws/eventsis connected, no periodic polling loops for windows/panes; sessionsRefreshCountshould increase mostly on explicit actions or structural events;fallbackRefreshCountshould stay flat unless websocket is disconnected.
- Host support: Linux and macOS only.
- Windows is not supported yet.
- tmux workflows require
tmuxinstalled on the host. - Recovery restores session structure/context, not in-memory process state.
- No multi-tenant RBAC yet.
make dev
make build
make test
make test-client
make lint
make lint-client
make ci- Versioning and release notes are automated by
release-pleaseonmain. - Follow Conventional Commits (
feat:,fix:,feat!:...) so version bumps and changelogs are accurate. - When a release is created, CI builds and uploads platform archives and checksum manifest (
sentinel-<version>-checksums.txt) automatically. - Manual tag releases are still supported via
.github/workflows/release.ymland now always include generated notes. - Required GitHub setting for the default
GITHUB_TOKENpath:Settings->Actions->General->Workflow permissions- enable
Read and write permissions - enable
Allow GitHub Actions to create and approve pull requests
Pull requests are welcome.
- Fork repository
- Create a feature branch
- Run
make ci - Open a pull request





