A terminal operations manual for long-running tasks on POSIX shells, macOS, and Linux. It does not falsely claim native Windows compatibility; Windows users should use it in WSL or another POSIX environment.
Customer-readable description
What this skill can do
| Customer wants | Skill will do | Customer can see |
|---|---|---|
| Start or observe a long-running task | Start a tmux/background task with parameterized session, log directory, and command | command, workdir, session/PID, log path, and current status |
| Determine whether a task is stalled | Within the user-specified observation window, cross-check logs, CPU, and network/subprocess progress | Evidence for each signal and a conclusion of "running/suspected stalled/unable to determine" |
| Recover or terminate a task | First confirm the target and data risk, then proceed in the order TERM→recheck→KILL | Each signal, confirmation point, exit status, and follow-up recovery recommendation |
How customers use it
Provide the following inputs; if inputs that would change the termination target or log destination are missing, ask first and do not guess:
- The command to run or diagnose, and the working directory;
- An existing PID or tmux session (if applicable);
session_name、log_dir、stall_window_seconds、term_grace_seconds;- Optional
fallback_command, and whether termination of the target process is pre-authorized.
No need to invoke this skill when only viewing short command output or file contents.
Dependencies and installation
Install this skill:
npx skills add soia-team/soia-open-dev-ts-skills -g -a '*' -s soia-dev-terminal-ops -y
Hard dependencies: POSIX shell,ps、kill. The tmux workflow requires tmux. Network connectivity checks optionally use lsof; if unavailable, mark it as "network signal not checked" and do not conclude deadlock based on that.
Optional configuration:
~/.config/soia-skills/soia-dev-terminal-ops/config.yml
SOIA_DEV_TERMINAL_OPS_CONFIG_FILE=<custom-config-path>
Recommended configuration structure:
schema_version: 2
env:
TERMINAL_OPS_LOG_DIR: "<user-log-dir>"
TERMINAL_OPS_SESSION_NAME: "<session-name>"
TERMINAL_OPS_STALL_WINDOW_SECONDS: "<seconds>"
TERMINAL_OPS_TERM_GRACE_SECONDS: "<seconds>"
TERMINAL_OPS_FALLBACK_COMMAND: "<optional-command>"
Priority: this user input/CLI arguments → process environment → configuration file. Use ${TMPDIR}only when no log directory is given; if TMPDIR is also unset, first ask the user to specify a directory.
Logs and completion receipts
Each report:
完成:<启动、诊断、恢复或终止结果>。
日志摘要:
- command/workdir: <命令与目录>
- session/pid: <会话名或 PID>
- log: <日志路径或“纯 stdout”>
- signals: <日志/CPU/网络/子进程证据>
- status: running / suspected-stall / inconclusive / completed / terminated / killed
验证:<退出码、复查命令和最后输出摘要>
问题与下一步:<fallback 或待确认项;没有则写“无”>
Trigger conditions
- Start or monitor a command expected to run for more than 30 seconds;
- Manage tmux sessions, background builds/tests, or continuous logs;
- Diagnose a process with no output, a hanging tool call, or an unrecoverable terminal;
- Terminate or downgrade a long-running task under an explicit confirmation gate.
Argument parsing
Before execution, parse and echo back non-secret arguments:
SESSION_NAME="${TERMINAL_OPS_SESSION_NAME:?set session name}"
LOG_DIR="${TERMINAL_OPS_LOG_DIR:-${TMPDIR:?set TERMINAL_OPS_LOG_DIR or TMPDIR}}"
STALL_WINDOW_SECONDS="${TERMINAL_OPS_STALL_WINDOW_SECONDS:?set observation window}"
TERM_GRACE_SECONDS="${TERMINAL_OPS_TERM_GRACE_SECONDS:?set TERM grace period}"
FALLBACK_COMMAND="${TERMINAL_OPS_FALLBACK_COMMAND:-}"
Verify that the session name contains only letters, digits, dots, underscores, or hyphens; before creating directories, show the resolved absolute path. Do not hardcode agent names, executor states, timeout values, or log file names in the skill.
Command risk classification
Default read-only/idempotent:
tmux list-sessions
ps -o pid,ppid,stat,etime,time,command -p <PID>
tail -n <LINES> <LOG_FILE>
lsof -nP -p <PID> -i # 可选
High-impact actions must first explain the target, basis, and data risk, and obtain user confirmation (or cite explicit pre-authorization in this request):
kill -TERM <PID>;kill -KILL <PID>;tmux kill-session -t <SESSION_NAME>;- Execute
FALLBACK_COMMAND, because it may incur costs, remote state changes, or duplicate work.
After confirming the PID, read the full command and parent PID again to avoid PID reuse or selecting the wrong process. Do not use broad pkill/killall Instead of an exact PID.
Background session management
The log name is specified by the caller and is not derived from the product name or agent name:
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/<log-name>.log"
tmux new-session -d -s "$SESSION_NAME" \
"cd '<workdir>' && <command> 2>&1 | tee '$LOG_FILE'"
tmux list-sessions
tmux capture-pane -p -t "$SESSION_NAME" -S -50
tail -n 50 "$LOG_FILE"
When a command, directory, or path contains user input, use host tools to pass parameters safely; do not directly concatenate unchecked shell fragments. If a compound command must be run, first show the final command to the user verbatim.
Multi-signal stall diagnosis
S only indicates interruptible sleep; being in S for a long time may also be normal waiting. Elapsed time or a single timeout is never a kill condition.
At STALL_WINDOW_SECONDS check at least two sampling points covered:
- Log progress: whether the log mtime, size, or last business progress entry has changed; when there is no log, explicitly record the gap.
- CPU progress: whether cumulative CPU time has increased; a single low CPU reading only means it was idle at that moment.
- Network/IPC progress: if the task depends on the network, check whether the connection exists and whether its state has changed;
lsofdo not fabricate conclusions when it is unavailable. - Child process progress: check whether the child process is still working, has exited, or is producing new output.
- Task-specific heartbeat: whether the test count, build targets, downloaded bytes, or queue counts, etc., have changed.
Only when "the observation window has exceeded the threshold" and at least two independent progress signals have continuously shown no change, and there is no reasonable normal-waiting explanation, mark it as suspected-stall. When signals are insufficient, mark it as inconclusive, continue observing, or ask the user to judge.
Example sampling (column names may differ slightly on macOS/Linux commands; interpret according to the actual output):
ps -o pid,ppid,stat,etime,time,command -p <PID>
wc -c < "$LOG_FILE"
tail -n 20 "$LOG_FILE"
lsof -nP -p <PID> -i 2>/dev/null || true
TARGET_PID=<PID>
ps -o pid,ppid,stat,etime,time,command -ax | awk -v p="$TARGET_PID" '$2 == p'
After waiting for the user-configured observation window, resample and take the difference. Do not mistakenly write "the command has not exited" as "there is no progress."
Safe termination and recovery
- Show the PID, full command, parent PID, working directory (when obtainable), and multi-signal evidence.
- Explain that TERM may interrupt writes, and KILL gives no chance to clean up; obtain confirmation.
- Send TERM.
- Within
TERM_GRACE_SECONDS, repeatedly recheck whether the process has exited, and check the log/disk-write status. - If it is still alive, show the recheck evidence and potential data loss, and obtain KILL confirmation again.
- Send KILL only to the same rechecked PID; then confirm that the process has disappeared, the session state, and output integrity.
- If a fallback is configured, first explain how context is passed, whether side effects and costs will be duplicated, and then execute after obtaining confirmation.
kill -TERM <PID>
# 按 TERM_GRACE_SECONDS 轮询:
ps -p <PID> >/dev/null 2>&1 || echo "terminated"
# 仍存活且再次确认后:
kill -KILL <PID>
ps -p <PID> >/dev/null 2>&1 && echo "still alive" || echo "killed"
Five classifications of output files
| Category | Examples in this skill | Location |
|---|---|---|
| A Temporary | Logs and sampling snapshots for this round of build/test | User-specified log directory; otherwise ${TMPDIR}/soia-dev-terminal-ops/ |
| B Audit | Records of high-impact actions such as kill, session cleanup, and fallback | User-specified state directory or ${XDG_STATE_HOME}/soia-dev-terminal-ops/; ask first when not configured |
| C Deliverable | Complete diagnostic package that the user requests be retained | User-specified path |
| D Product functionality is the log | Task logs defined by the target project | Obey only the conventions already documented by the target project; do not invent them in this skill |
| E Pure stdout | Short status check, summary that does not need to be retained | Do not write to disk |
The relative cwd must not be used as the default log directory. Category A may be rotated; Category B must not be deleted before the retention policy is confirmed.