Model downloads, fine-tunes, big rsyncs — anything that outlives an SSH session. park drops the command into a detached tmux session and tees its output to a log; parked tells you which ones are still going, finished, or died.
~/.local/bin/park — start a command detached, log it, auto-close on finish:
#!/usr/bin/env bash
# usage: park <session-name> <command...>
set -euo pipefail
if [ "$#" -lt 2 ]; then
echo "usage: park <session-name> <command...>" >&2
exit 1
fi
session="$1"; shift
# refuse to clobber a session that's already running
if tmux has-session -t "$session" 2>/dev/null; then
echo "session '$session' already exists — attach with: tmux attach -t $session" >&2
exit 1
fi
logdir="$HOME/.park"
mkdir -p "$logdir"
logfile="$logdir/${session}.log"
# -d = detached: tmux runs the command in the background and returns immediately
tmux new-session -d -s "$session" \
bash -c '
set -o pipefail
logfile="$1"; shift
{
printf ">>> started: %s\n" "$(date)"
printf ">>> cmd:"; printf " %q" "$@"; printf "\n\n" # %q re-quotes each arg exactly
"$@"
} 2>&1 | tee "$logfile"
code=${PIPESTATUS[0]} # real exit code, not tee's
{
printf "\n>>> exit code: %s\n" "$code"
printf ">>> finished: %s\n" "$(date)"
} >> "$logfile"
' bash "$logfile" "$@"
echo "started '$session' (log: $logfile)"
echo "check later: tmux ls | tail -f $logfile | cat $logfile"
~/.local/bin/parked — summarize every task at a glance:
#!/usr/bin/env bash
# usage: parked [-l|--logs] (-l also prints the last log line)
set -euo pipefail
logdir="$HOME/.park"
show_tail=0
case "${1:-}" in
-l|--logs) show_tail=1 ;;
"") ;;
*) echo "usage: parked [-l|--logs]" >&2; exit 1 ;;
esac
# colours only when writing to a real terminal
if [ -t 1 ]; then
c_run=$(tput setaf 4); c_ok=$(tput setaf 2); c_fail=$(tput setaf 1)
c_die=$(tput setaf 3); c_dim=$(tput setaf 8); c_off=$(tput sgr0); c_bold=$(tput bold)
else
c_run=; c_ok=; c_fail=; c_die=; c_dim=; c_off=; c_bold=
fi
# a task is "running" if its tmux session still exists
active=""
if command -v tmux >/dev/null 2>&1; then
active=$(tmux ls -F '#{session_name}' 2>/dev/null || true)
fi
is_active() { printf '%s\n' "$active" | grep -qxF -- "$1"; }
shopt -s nullglob
logs=("$logdir"/*.log)
if [ ${#logs[@]} -eq 0 ]; then
echo "no park tasks found in $logdir"
exit 0
fi
printf "%s%-20s %-9s %s%s\n" "$c_bold" "SESSION" "STATUS" "DETAIL" "$c_off"
for log in "${logs[@]}"; do
name=$(basename "$log" .log)
if is_active "$name"; then # session alive → still running
started=$(grep -m1 '^>>> started:' "$log" | sed 's/^>>> started: //' || true)
printf "%-20s %s%-9s%s %s%s%s\n" \
"$name" "$c_run" "running" "$c_off" "$c_dim" "since ${started:-?}" "$c_off"
else
code=$(grep '^>>> exit code:' "$log" | tail -1 | sed 's/^>>> exit code: //' || true)
fin=$(grep '^>>> finished:' "$log" | tail -1 | sed 's/^>>> finished: //' || true)
if [ -z "$code" ]; then # no exit code → killed / OOM / reboot
printf "%-20s %s%-9s%s %s%s%s\n" \
"$name" "$c_die" "died" "$c_off" "$c_dim" "no exit code — killed / reboot?" "$c_off"
elif [ "$code" = "0" ]; then
printf "%-20s %s%-9s%s %s%s%s\n" \
"$name" "$c_ok" "ok" "$c_off" "$c_dim" "exit 0${fin:+, $fin}" "$c_off"
else
printf "%-20s %s%-9s%s %s%s%s\n" \
"$name" "$c_fail" "FAILED" "$c_off" "$c_dim" "exit $code${fin:+, $fin}" "$c_off"
fi
fi
if [ "$show_tail" -eq 1 ]; then
last=$(tail -1 "$log" 2>/dev/null || true)
printf " %s└ %s%s\n" "$c_dim" "$last" "$c_off"
fi
done
Drop both in ~/.local/bin, chmod +x, and go:
park dl-llama huggingface-cli download meta-llama/Llama-3.1-8B-Instruct --local-dir ./models/llama
parked # running / ok / FAILED / died
parked -l # same, plus each task's last log line
cat ~/.park/dl-llama.log
Quote any argument with a space; for pipes, &&, or redirection, put it in a script and run park job ./job.sh.