Ops¶
Unified, config-driven session management for tmux and containers (Docker/Podman).
kstlib.ops provides a single API to start, stop, attach, monitor, and collect logs
from both tmux sessions and Docker/Podman containers. All session definitions live in
kstlib.conf.yml, making the config file the single source of truth.
What it does¶
Capability |
tmux |
Docker / Podman |
|---|---|---|
Start a new session |
|
|
Stop a session |
|
|
Attach (interactive) |
|
|
Status |
Session state + PID |
Container state + image |
Logs |
|
|
List all sessions |
All tmux + all containers + config-defined |
Container interoperability: kstlib ops detects and manages all running containers
on the host, not just those created by kstlib. You can attach, logs, status, and stop
any existing Docker/Podman container. The start command creates new containers from an image.
TL;DR¶
from kstlib.ops import SessionManager
# Local dev with tmux
session = SessionManager("dev", backend="tmux")
session.start("python -m app.bot")
session.attach() # tmux attach-session -t dev (Ctrl+B D to detach)
# Production with Podman/Docker
session = SessionManager(
"prod",
backend="container",
image="bot:latest",
volumes=["./data:/app/data"],
)
session.start()
session.attach() # podman attach prod (Ctrl+P Ctrl+Q to detach)
# Config-driven (from kstlib.conf.yml)
session = SessionManager.from_config("astro")
session.start()
Key Features¶
Unified API: Same interface for tmux sessions and Docker/Podman containers
Config-Driven: Session definitions in
kstlib.conf.ymlwithDEFINEDstate visibilityContainer Interop: Detects and manages all containers on the host (not just kstlib-created)
Pseudo-Terminal Support: Full TUI/Rich/Textual support with
attach()Log Persistence: Container logs available even after crash (via volume mounts)
CLI Integration:
kstlib ops start|stop|attach|status|logs|listDeep Defense: All config values validated (session names, commands, images, volumes, ports)
Quick Start¶
Backend Selection¶
Choose the appropriate backend for your environment:
Backend |
Use Case |
Attach/Detach |
|---|---|---|
|
Dev, backtesting |
Ctrl+B D |
|
Production |
Ctrl+P Ctrl+Q |
Using tmux Backend (Development)¶
from kstlib.ops import SessionManager
# Create and start
session = SessionManager("bot", backend="tmux")
session.start("python -m trading.bot")
# Check status
status = session.status()
print(f"{status.name}: {status.state.value}") # bot: running
# Get logs
logs = session.logs(lines=50)
print(logs)
# Attach (replaces current process)
session.attach() # Ctrl+B D to detach
# Stop
session.stop()
Using Container Backend (Production)¶
from kstlib.ops import SessionManager
# Create with container options
session = SessionManager(
"astro-prod",
backend="container",
image="astro-bot:latest",
volumes=["./data:/app/data"],
log_volume="./logs:/app/logs", # Persist logs for post-mortem
ports=["8081:8080"], # Prometheus metrics
env={"ASTRO_ENV": "production"},
)
# Start container
session.start()
# Check status
status = session.status()
print(f"PID: {status.pid}, Image: {status.image}")
# Attach (Ctrl+P Ctrl+Q to detach)
session.attach()
# Stop gracefully (SIGTERM, then SIGKILL after timeout)
session.stop(graceful=True, timeout=10)
Config-Driven Usage¶
Define sessions in kstlib.conf.yml:
ops:
default_backend: tmux
tmux_binary: tmux
container_runtime: null # auto-detect (podman or docker)
sessions:
astro:
backend: tmux
command: "python -m astro.bot"
working_dir: "/opt/astro"
env:
ASTRO_ENV: "development"
astro-prod:
backend: container
image: "astro-bot:latest"
volumes:
- "./data:/app/data"
log_volume: "./logs/astro:/app/logs"
env:
ASTRO_ENV: "production"
Then use:
from kstlib.ops import SessionManager
# Backend and options loaded from config
session = SessionManager.from_config("astro")
session.start()
Session Lifecycle (DEFINED State)¶
Sessions defined in kstlib.conf.yml are always visible in kstlib ops list,
even before they are started. This makes the config file the single source of truth:
kstlib.conf.yml kstlib ops start kstlib ops stop
┌──────────┐ ┌──────────┐ ┌──────────┐
│ DEFINED │ ──────► │ RUNNING │ ──────► │ DEFINED │
│ (config) │ │ (active) │ │ (config) │
└──────────┘ └──────────┘ └──────────┘
The defined state means “exists in config but not yet started”. It appears dimmed
in the CLI output to distinguish from active sessions:
$ kstlib ops list
Name Backend State PID
astro tmux defined -
astro-prod container defined -
$ kstlib ops start astro
$ kstlib ops list
Name Backend State PID
astro tmux running 12345
astro-prod container defined -
The kstlib ops status command also supports the defined state for config-only
sessions, showing the configured backend and image without requiring a running process.
Runtime Auto-Detect¶
Set container_runtime: null (or omit the key) to let kstlib auto-detect
the container runtime:
Checks for
podmanin PATHFalls back to
dockerin PATHRaises
ContainerRuntimeNotFoundErrorif neither is found
ops:
container_runtime: null # auto-detect
This ensures configs are portable across machines with different runtimes installed.
CLI Overrides on Config Sessions¶
Config values serve as defaults. CLI arguments override them when needed:
# Start with all options from config
kstlib ops start astro-prod
# Override the image
kstlib ops start astro-prod --image astro-bot:v2
# Override the backend (turns a tmux session into a container)
kstlib ops start astro --backend container --image astro-bot
The override priority chain is: CLI arguments > kstlib.conf.yml > defaults.
CLI Commands¶
# Start a session
kstlib ops start dev --backend tmux --command "python app.py"
kstlib ops start prod --backend container --image app:latest
# Session from config (recommended)
kstlib ops start astro
# Stop
kstlib ops stop dev
kstlib ops stop prod --force
# Attach
kstlib ops attach dev
# Status (works for running and config-defined sessions)
kstlib ops status dev
kstlib ops status prod --json
# Logs
kstlib ops logs dev --lines 50
# List all sessions (running + config-defined)
kstlib ops list
kstlib ops list --backend container --json
Exception Handling¶
from kstlib.ops import SessionManager
from kstlib.ops.exceptions import (
SessionExistsError,
SessionNotFoundError,
TmuxNotFoundError,
ContainerRuntimeNotFoundError,
)
try:
session = SessionManager("bot", backend="tmux")
session.start("python app.py")
except TmuxNotFoundError:
print("tmux not installed - install with: apt install tmux")
except SessionExistsError:
print("Session already exists - use stop first")
except SessionNotFoundError:
print("Session not found")
Low-Level Runners¶
For direct backend access without SessionManager:
from kstlib.ops import TmuxRunner, ContainerRunner, SessionConfig, BackendType
# Direct tmux usage
tmux = TmuxRunner()
config = SessionConfig(
name="direct-test",
backend=BackendType.TMUX,
command="python app.py",
)
status = tmux.start(config)
sessions = tmux.list_sessions()
tmux.stop("direct-test")
# Direct container usage
container = ContainerRunner(runtime="podman")
config = SessionConfig(
name="container-test",
backend=BackendType.CONTAINER,
image="python:3.10-slim",
command="python -c 'import time; time.sleep(3600)'",
)
status = container.start(config)
container.stop("container-test")
See Also¶
API Reference for complete API documentation
Configuration for configuration loading