automation/skills/tmux/SKILL.md
Persistent tmux sessions inside containers: shell reconnection, background commands, output capture, and key sending. Use when running long-lived or TTY-dependent commands. MUST be invoked before any work involving: charly tmux commands, persistent shells, background container commands, or TTY-dependent TUI programs.
npx skillsauth add overthinkos/overthink-plugins tmuxInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
charly tmux manages tmux sessions inside running containers. It solves two problems:
charly tmux shell <image> again and you're back where you left off.openclaw models auth login need a real terminal to function. charly shell --tty piped through tee or redirected breaks the TUI event loop. charly tmux run provides a real tmux terminal that the TUI can use, while charly tmux capture reads the output without attaching.All operations translate to engine exec container tmux <args>. The tmux candy must be present in the box (candy/tmux/charly.yml — installs the tmux RPM).
| Action | Command | Description |
|--------|---------|-------------|
| Persistent shell | charly tmux shell <image> | Create or reattach to a shell session |
| Send command | charly tmux cmd <image> "command" -s <name> | Send command to session (with notification) |
| Run detached | charly tmux run <image> -s <name> "<command>" | Start command in new detached session |
| Attach | charly tmux attach <image> -s <name> | Attach to session interactively |
| List sessions | charly tmux list <image> | Show active tmux sessions |
| Capture output | charly tmux capture <image> -s <name> | Print pane output (for automation) |
| Send keys | charly tmux send <image> -s <name> "text" --enter | Send keystrokes to session |
| Kill session | charly tmux kill <image> -s <name> | Kill a tmux session |
All commands accept -i INSTANCE for multi-instance support.
charly tmux shell — Persistent ShellThe user-friendly entry point. Creates or reattaches to a persistent shell session.
# First call creates a "shell" session and attaches
charly tmux shell sway-browser-vnc
# After detaching (Ctrl-b d) or disconnect, reattach:
charly tmux shell sway-browser-vnc
# → Picks up right where you left off
# Use a custom session name:
charly tmux shell sway-browser-vnc -s dev
Behavior:
tmux attach-session -t <name>tmux new-session -s <name> (creates with bash)syscall.Exec with -it for a real terminalshellcharly tmux cmd — Send Command to SessionSends a command (text + Enter) to an existing tmux session. Returns immediately after sending. Sends a desktop notification by default (disable with --no-notify).
charly tmux cmd sway-browser-vnc "ls -la" -s oauth
charly tmux cmd jupyter "python train.py" -s training --no-notify
Behavior:
charly tmux list to see sessions)charly tmux send <image> -s <name> -l "command" --entercharly tmux run — Detached CommandStarts a command in a new named tmux session. Returns immediately — the command runs in the background with a real TTY.
# Run OAuth flow in background with real terminal
charly tmux run sway-browser-vnc -s oauth \
"openclaw models auth login --provider openai-codex --set-default"
# Run any long-lived command
charly tmux run jupyter -s training "python train.py --epochs 100"
Behavior:
exec.Command, returns immediately-d (detached)charly tmux attach — Interactive AttachAttaches to an existing session. Use when you want to interact with a running command.
charly tmux attach sway-browser-vnc -s oauth
# Detach with Ctrl-b d
Behavior:
syscall.Exec replaces the processcharly tmux list to see sessions)charly tmux list — List Sessionscharly tmux list sway-browser-vnc
# shell: 1 windows (created Sat Mar 21 16:54:15 2026)
# oauth: 1 windows (created Sat Mar 21 17:01:22 2026)
No sessions is not an error — prints an informational message.
charly tmux capture — Read OutputReads the current pane content without attaching. Essential for automation — Claude Code and scripts can check on running commands.
# Read visible pane content
charly tmux capture sway-browser-vnc -s oauth
# Read last 50 lines of history
charly tmux capture sway-browser-vnc -s oauth -n 50
Flags:
-n <lines> — Number of history lines (0 = visible pane only, default)charly tmux send — Send KeysSends keystrokes to a running session. For automation when you need to respond to prompts.
# Type text and press Enter
charly tmux send sway-browser-vnc -s oauth "yes" --enter
# Send literal text (disable tmux key name interpretation)
charly tmux send sway-browser-vnc -s oauth -l "C-c is not ctrl-c here"
# Send special keys
charly tmux send sway-browser-vnc -s oauth Enter
charly tmux send sway-browser-vnc -s oauth C-c
Flags:
--enter — Append Enter key after the text-l / --literal — Send keys literally (disable key name lookup)charly tmux kill — Kill Sessioncharly tmux kill sway-browser-vnc -s oauth
# Killed tmux session "oauth" in charly-sway-browser-vnc
The primary use case that motivated charly tmux. The openclaw models auth login TUI requires a real terminal to complete the post-callback token exchange. charly shell --tty piped through tee or backgrounded breaks the TUI event loop — the callback is received but tokens are never saved.
IMG=sway-browser-vnc
# 1. Start OAuth in a tmux session (real terminal)
charly tmux run $IMG -s oauth \
"openclaw models auth login --provider openai-codex --set-default"
# 2. Read the OAuth URL from tmux output
charly tmux capture $IMG -s oauth | grep -o 'https://auth.openai.com/[^ ]*'
# 3. Drive the browser via cdp:/vnc: plan steps (the cdp: verb is served
# out-of-process by candy/plugin-cdp): cdp: open the OAuth URL, then locate
# "Continue with Google" / "Continue" (consent) with cdp: coords on
# 'button._buttonStyleFix_wvuha_65' / 'button._primary_3rdp0_107' and deliver
# each click via the vnc: verb. Run the leg with:
# charly check live $IMG --filter cdp --filter vnc (full recipe: /charly-check:cdp)
# 4. Verify token exchange completed
sleep 10
charly tmux capture $IMG -s oauth | tail -5
# Should show: "OpenAI OAuth complete", "Default model set to openai-codex/gpt-5.4"
# 5. Clean up
charly tmux kill $IMG -s oauth
# Start a shell that survives disconnects
charly tmux shell jupyter
# Work inside the shell...
# pip install something, edit configs, run scripts
# Connection drops or terminal closes
# Just reconnect:
charly tmux shell jupyter
# → Everything is still there
The tmux candy must be included in the box. Check with:
charly shell <image> -c "which tmux"
If tmux is not installed, charly tmux returns: "tmux is not installed in container <name> (add the tmux layer to your image)".
The tmux candy is already a dependency of openclaw-full (and all derivative boxes). For other boxes, add tmux to the candies list in charly.yml.
For users unfamiliar with tmux:
| Key | Action |
|-----|--------|
| Ctrl-b d | Detach from session (leaves it running) |
| Ctrl-b [ | Enter scroll mode (navigate with arrows, q to exit) |
| Ctrl-b c | Create new window |
| Ctrl-b n / Ctrl-b p | Next / previous window |
| Ctrl-b % | Split pane vertically |
| Ctrl-b " | Split pane horizontally |
Command execution follows a consistent naming pattern across charly:
| Interactive shell | Single command | Persistent session |
|-------------------|---------------|-------------------|
| charly shell | charly cmd | — |
| charly tmux shell | charly tmux cmd | charly tmux run |
charly cmd — runs command synchronously in running container, notifies on completioncharly tmux cmd — sends command to existing tmux session, notifies on dispatchcharly tmux run — creates new detached tmux session with commandcharly cmd — Single command execution with D-Bus notification (running containers only, no tmux)/charly-core:shell — charly shell for one-shot commands (no persistence) or charly shell -c (full container setup)/charly-check:cdp — Chrome DevTools Protocol (used with tmux for OAuth flows)/charly-automation:openclaw-deploy — OpenClaw gateway config (OAuth requires tmux for token exchange)/charly-core:service — Supervisord service management (different scope: persistent services vs ad-hoc commands)/charly-infrastructure:tmux-layer — The tmux candy definition/charly-infrastructure:dbus-layer — D-Bus session bus (required for notifications)MUST be invoked when the task involves:
tools
Use when authoring or modifying a charly PLUGIN — a candy with a `plugin:` block that contributes Providers (verbs/kinds/deploy-targets/steps/builders/commands), its own CUE schema, builtin (compiled-in) or external (out-of-tree git repo). Covers the unified Provider model, the per-plugin CUE-schema contract (single source → Go params for dev + schema-over-Describe RPC for runtime), the SDK, and the loader.
tools
The CUE data-validation / configuration CLI (cue), pinned to v0.16.1. Use when working with the cue candy, installing the cue binary into a box or onto a target:local dev host, or running the offline schema-vendoring pipeline that feeds charly's egress validation.
tools
CUE EGRESS validation — validating (and, where it adds value, generating) the config files charly WRITES to a system BEFORE the bytes hit disk. MUST be invoked before working on charly/egress.go, the vendored schemas under candy/plugin-egress/egress-schemas/vendor/, the ValidateEgress / registerVendoredEgressKind path, the offline `task cue:vendor` pipeline, or adding an egress schema for any written artifact (cloud-init, k8s manifests, traefik routes, runtime config, install ledger, systemd/quadlet units, ssh_config, libvirt XML).
tools
Kubernetes cluster-probe declarative check verb — the `kube:` check verb (nodes, pods, ingress, storage class, addon health, apply/delete, and arbitrary resource GETs) served out-of-process by the candy/plugin-kube plugin (vendored client-go; no external kubectl required).