Slurm
Use a persistent Slurm allocation for environment-sensitive development work,
especially ROCm/GPU build, test, profiling, and verification loops. The
allocation is held by a salloc shell that lives inside a detached tmux
session; every other command (srun, squeue, scancel, builds, tests) runs
in a normal shell and addresses the allocation by job ID.
The skill auto-activates when ~/.cache/slurm-detection contains available.
The first Slurm skill or hook caller creates that file after checking whether
salloc, srun, and squeue are on PATH. An unavailable result makes the
skill inactive, so the agent runs commands directly without an srun wrapper
- and without adding any Slurm-related text to the final report.
Quick Start
- Confirm the execution boundary:
- Read-only exploration may happen outside Slurm.
- Cursor file edits are allowed.
- Builds, tests, profiler runs, GPU checks, and final verification commands
run inside the Slurm allocation via
srun --jobid="$JOBID" <command>.
- Read or initialize the cached Slurm detection result, then prepare the
allocation. This single block reuses an existing
cursor-agent allocation
if one is exported in the environment, and otherwise detects-or-creates one
in tmux:
SLURM_DETECTION_CACHE="$HOME/.cache/slurm-detection"
SLURM_DETECTION_STATE=""
if [[ -r "$SLURM_DETECTION_CACHE" ]]; then
SLURM_DETECTION_STATE=$(<"$SLURM_DETECTION_CACHE")
fi
if [[ "$SLURM_DETECTION_STATE" != "available" \
&& "$SLURM_DETECTION_STATE" != "unavailable" ]]; then
rm -f "$SLURM_DETECTION_CACHE" 2>/dev/null || true
if command -v salloc >/dev/null 2>&1 \
&& command -v srun >/dev/null 2>&1 \
&& command -v squeue >/dev/null 2>&1; then
SLURM_DETECTION_STATE="available"
else
SLURM_DETECTION_STATE="unavailable"
fi
if mkdir -p "$HOME/.cache" 2>/dev/null; then
SLURM_DETECTION_TMP=$(mktemp "$HOME/.cache/.slurm-detection.XXXXXX" 2>/dev/null || true)
if [[ -n "$SLURM_DETECTION_TMP" ]]; then
printf '%s\n' "$SLURM_DETECTION_STATE" > "$SLURM_DETECTION_TMP"
chmod 600 "$SLURM_DETECTION_TMP" 2>/dev/null || true
if ! ln "$SLURM_DETECTION_TMP" "$SLURM_DETECTION_CACHE" 2>/dev/null \
&& [[ -r "$SLURM_DETECTION_CACHE" ]]; then
SLURM_CACHED_STATE=$(<"$SLURM_DETECTION_CACHE")
if [[ "$SLURM_CACHED_STATE" == "available" \
|| "$SLURM_CACHED_STATE" == "unavailable" ]]; then
SLURM_DETECTION_STATE="$SLURM_CACHED_STATE"
fi
fi
rm -f "$SLURM_DETECTION_TMP"
fi
fi
fi
if [[ "$SLURM_DETECTION_STATE" != "available" ]]; then
# Cached Slurm detection says the skill is inactive.
# The skill does not apply: run commands directly, no srun wrapper,
# no Slurm-related text in the final report.
return 0 2>/dev/null || exit 0
fi
JOBID=""
if [ -n "${SLURM_JOB_ID:-}" ] \
&& [ "$(squeue -j "$SLURM_JOB_ID" -h -o '%j' 2>/dev/null)" = "cursor-agent" ]; then
JOBID="$SLURM_JOB_ID"
fi
if [ -z "$JOBID" ]; then
JOBID=$(squeue -u "$USER" -h -o "%A" -t R --name=cursor-agent | head -n1)
if [ -z "$JOBID" ]; then
GPU_PREFS=(
"gfx942-mi300x"
"gfx942-mi308x"
"gfx942-mi300a"
"gfx942-mi325x"
"gfx950-mi350x"
"gfx950-mi355x"
)
GRES_NAME=""
for gpu in "${GPU_PREFS[@]}"; do
if sinfo -h -N -o "%G %t" 2>/dev/null \
| awk -v g="$gpu" '$1 ~ g && ($2 == "idle" || $2 == "mix") { found=1; exit }
END { exit !found }'; then
GRES_NAME="$gpu"
break
fi
done
[ -z "$GRES_NAME" ] && GRES_NAME="gfx942-mi300x"
GRES="gpu:${GRES_NAME}:1"
tmux new-session -d -s cursor-agent-alloc \
"salloc --job-name=cursor-agent \
--gres=$GRES \
--cpus-per-task=32 \
--mem=1T \
--time=12:00:00"
for _ in $(seq 1 60); do
JOBID=$(squeue -u "$USER" -h -o "%A" -t R --name=cursor-agent | head -n1)
[ -n "$JOBID" ] && break
sleep 5
done
fi
fi
- Run each command from a regular shell using the captured
$JOBID (do not
wrap these in tmux):
srun --jobid="$JOBID" rocminfo
srun --jobid="$JOBID" python -m pytest path/to/test_file.py -k test_name
- Capture evidence in timestamped logs by wrapping the
srun invocation
(not the salloc/tmux line) with tee.
- Run targeted verification first, then broader build/install/tests when the
change touches shared or user-facing behavior.
Explicit standalone fallback
The persistent cursor-agent allocation above is the only normal Cursor
execution path. A human running a GPU-dependent skill helper directly outside
Cursor may explicitly request one short-lived allocation:
bash <SLURM_SKILL_DIR>/scripts/run-standalone.sh -- <command> [args...]
The wrapper executes directly when already inside a Slurm step, reuses an
exported cursor-agent allocation through srun, or creates one short-lived
salloc ... srun allocation. When Slurm commands are unavailable it executes
inline. It returns the command's status and is never called automatically by
sibling skills. See REFERENCE.md.
Behavior Rules
- Read Slurm availability from
~/.cache/slurm-detection. On the first call,
or when the file is empty or invalid, check salloc, srun, and squeue
and atomically cache available or unavailable. Never source the file.
Both results persist until the file is deleted manually. If the cache cannot
be written, use the detected result for the current invocation. When the
result is unavailable, do not wrap commands with srun and do not add a
"Slurm unavailable" note to the report.
- If
$SLURM_STEP_ID is set, run directly inside that step. If only
$SLURM_JOB_ID is set, reuse it when squeue -j "$SLURM_JOB_ID" -h -o '%j' equals cursor-agent. Reject a differently named inherited job rather
than nesting another allocation inside it.
- Use the baseline
salloc flags --job-name=cursor-agent --gres=$GRES --cpus-per-task=32 --mem=1T --time=12:00:00. $GRES is selected
automatically by probing sinfo for the first preferred GPU type with
idle or mix capacity. The preference order is mi300x, mi308x,
mi300a, mi325x (gfx942 family), then mi350x, mi355x (gfx950
family). If nothing is idle anywhere, queue on gpu:gfx942-mi300x:1. Ask
for site-specific additions (partition, account, QoS) only if these
defaults fail.
- Run only the
salloc launch inside tmux new-session -d -s cursor-agent-alloc .... Do not wrap srun, squeue, scancel, the
polling loop, or any verification command in tmux.
- Whenever the skill is active, runtime-sensitive work (builds, tests,
profilers, GPU/ROCm checks) goes through
srun --jobid="$JOBID"; only file
inspection, planning, and source edits run on the login node.
- Do not silently piggyback on a job whose name is not
cursor-agent - it may
have different --gres/time and the agent did not pick its flags.
- Keep final reports concise: command, pass/fail status, key output summary, and
log location.
- If
squeue -j "$JOBID" shows the job gone (time limit, scancel, or tmux
session killed), re-run the detect-or-create step and rerun only missing
verification.
- Do not copy
salloc logic into sibling helpers. Outside Cursor, a user may
explicitly wrap one command with scripts/run-standalone.sh; inside Cursor,
use the persistent allocation workflow.
Additional Resources
- REFERENCE.md
- EXAMPLES.md
- scripts/run-standalone.sh
1---2name: slurm3description: ALWAYS use this skill on every task that runs a shell command. Runs development, build, test, and verification workflows through an interactive Slurm allocation (salloc in detached tmux, then per-command srun --jobid) while preserving Cursor editing ergonomics. Reads cached availability from ~/.cache/slurm-detection and silently does not apply when Slurm is unavailable.4---56# Slurm78Use a persistent Slurm allocation for environment-sensitive development work,9especially ROCm/GPU build, test, profiling, and verification loops. The10allocation is held by a `salloc` shell that lives inside a detached tmux11session; every other command (`srun`, `squeue`, `scancel`, builds, tests) runs12in a normal shell and addresses the allocation by job ID.1314The skill auto-activates when `~/.cache/slurm-detection` contains `available`.15The first Slurm skill or hook caller creates that file after checking whether16`salloc`, `srun`, and `squeue` are on `PATH`. An `unavailable` result makes the17skill inactive, so the agent runs commands directly without an `srun` wrapper18- and without adding any Slurm-related text to the final report.1920## Quick Start21221. Confirm the execution boundary:23 - Read-only exploration may happen outside Slurm.24 - Cursor file edits are allowed.25 - Builds, tests, profiler runs, GPU checks, and final verification commands26 run inside the Slurm allocation via `srun --jobid="$JOBID" <command>`.272. Read or initialize the cached Slurm detection result, then prepare the28 allocation. This single block reuses an existing `cursor-agent` allocation29 if one is exported in the environment, and otherwise detects-or-creates one30 in tmux:3132```bash33SLURM_DETECTION_CACHE="$HOME/.cache/slurm-detection"34SLURM_DETECTION_STATE=""35if [[ -r "$SLURM_DETECTION_CACHE" ]]; then36 SLURM_DETECTION_STATE=$(<"$SLURM_DETECTION_CACHE")37fi3839if [[ "$SLURM_DETECTION_STATE" != "available" \40 && "$SLURM_DETECTION_STATE" != "unavailable" ]]; then41 rm -f "$SLURM_DETECTION_CACHE" 2>/dev/null || true4243 if command -v salloc >/dev/null 2>&1 \44 && command -v srun >/dev/null 2>&1 \45 && command -v squeue >/dev/null 2>&1; then46 SLURM_DETECTION_STATE="available"47 else48 SLURM_DETECTION_STATE="unavailable"49 fi5051 if mkdir -p "$HOME/.cache" 2>/dev/null; then52 SLURM_DETECTION_TMP=$(mktemp "$HOME/.cache/.slurm-detection.XXXXXX" 2>/dev/null || true)53 if [[ -n "$SLURM_DETECTION_TMP" ]]; then54 printf '%s\n' "$SLURM_DETECTION_STATE" > "$SLURM_DETECTION_TMP"55 chmod 600 "$SLURM_DETECTION_TMP" 2>/dev/null || true56 if ! ln "$SLURM_DETECTION_TMP" "$SLURM_DETECTION_CACHE" 2>/dev/null \57 && [[ -r "$SLURM_DETECTION_CACHE" ]]; then58 SLURM_CACHED_STATE=$(<"$SLURM_DETECTION_CACHE")59 if [[ "$SLURM_CACHED_STATE" == "available" \60 || "$SLURM_CACHED_STATE" == "unavailable" ]]; then61 SLURM_DETECTION_STATE="$SLURM_CACHED_STATE"62 fi63 fi64 rm -f "$SLURM_DETECTION_TMP"65 fi66 fi67fi6869if [[ "$SLURM_DETECTION_STATE" != "available" ]]; then70 # Cached Slurm detection says the skill is inactive.71 # The skill does not apply: run commands directly, no srun wrapper,72 # no Slurm-related text in the final report.73 return 0 2>/dev/null || exit 074fi7576JOBID=""77if [ -n "${SLURM_JOB_ID:-}" ] \78 && [ "$(squeue -j "$SLURM_JOB_ID" -h -o '%j' 2>/dev/null)" = "cursor-agent" ]; then79 JOBID="$SLURM_JOB_ID"80fi8182if [ -z "$JOBID" ]; then83 JOBID=$(squeue -u "$USER" -h -o "%A" -t R --name=cursor-agent | head -n1)8485 if [ -z "$JOBID" ]; then86 GPU_PREFS=(87 "gfx942-mi300x"88 "gfx942-mi308x"89 "gfx942-mi300a"90 "gfx942-mi325x"91 "gfx950-mi350x"92 "gfx950-mi355x"93 )94 GRES_NAME=""95 for gpu in "${GPU_PREFS[@]}"; do96 if sinfo -h -N -o "%G %t" 2>/dev/null \97 | awk -v g="$gpu" '$1 ~ g && ($2 == "idle" || $2 == "mix") { found=1; exit }98 END { exit !found }'; then99 GRES_NAME="$gpu"100 break101 fi102 done103 [ -z "$GRES_NAME" ] && GRES_NAME="gfx942-mi300x"104 GRES="gpu:${GRES_NAME}:1"105106 tmux new-session -d -s cursor-agent-alloc \107 "salloc --job-name=cursor-agent \108 --gres=$GRES \109 --cpus-per-task=32 \110 --mem=1T \111 --time=12:00:00"112 for _ in $(seq 1 60); do113 JOBID=$(squeue -u "$USER" -h -o "%A" -t R --name=cursor-agent | head -n1)114 [ -n "$JOBID" ] && break115 sleep 5116 done117 fi118fi119```1201213. Run each command from a regular shell using the captured `$JOBID` (do **not**122 wrap these in tmux):123124```bash125srun --jobid="$JOBID" rocminfo126srun --jobid="$JOBID" python -m pytest path/to/test_file.py -k test_name127```1281294. Capture evidence in timestamped logs by wrapping the `srun` invocation130 (not the salloc/tmux line) with `tee`.1315. Run targeted verification first, then broader build/install/tests when the132 change touches shared or user-facing behavior.133134## Explicit standalone fallback135136The persistent `cursor-agent` allocation above is the only normal Cursor137execution path. A human running a GPU-dependent skill helper directly outside138Cursor may explicitly request one short-lived allocation:139140```bash141bash <SLURM_SKILL_DIR>/scripts/run-standalone.sh -- <command> [args...]142```143144The wrapper executes directly when already inside a Slurm step, reuses an145exported `cursor-agent` allocation through `srun`, or creates one short-lived146`salloc ... srun` allocation. When Slurm commands are unavailable it executes147inline. It returns the command's status and is never called automatically by148sibling skills. See [REFERENCE.md](REFERENCE.md#explicit-standalone-execution).149150## Behavior Rules151152- Read Slurm availability from `~/.cache/slurm-detection`. On the first call,153 or when the file is empty or invalid, check `salloc`, `srun`, and `squeue`154 and atomically cache `available` or `unavailable`. Never source the file.155 Both results persist until the file is deleted manually. If the cache cannot156 be written, use the detected result for the current invocation. When the157 result is `unavailable`, do not wrap commands with `srun` and do not add a158 "Slurm unavailable" note to the report.159- If `$SLURM_STEP_ID` is set, run directly inside that step. If only160 `$SLURM_JOB_ID` is set, reuse it when `squeue -j "$SLURM_JOB_ID" -h -o161 '%j'` equals `cursor-agent`. Reject a differently named inherited job rather162 than nesting another allocation inside it.163- Use the baseline `salloc` flags `--job-name=cursor-agent --gres=$GRES164 --cpus-per-task=32 --mem=1T --time=12:00:00`. `$GRES` is selected165 automatically by probing `sinfo` for the first preferred GPU type with166 `idle` or `mix` capacity. The preference order is `mi300x`, `mi308x`,167 `mi300a`, `mi325x` (gfx942 family), then `mi350x`, `mi355x` (gfx950168 family). If nothing is idle anywhere, queue on `gpu:gfx942-mi300x:1`. Ask169 for site-specific additions (partition, account, QoS) only if these170 defaults fail.171- Run only the `salloc` launch inside `tmux new-session -d -s172 cursor-agent-alloc ...`. Do not wrap `srun`, `squeue`, `scancel`, the173 polling loop, or any verification command in tmux.174- Whenever the skill is active, runtime-sensitive work (builds, tests,175 profilers, GPU/ROCm checks) goes through `srun --jobid="$JOBID"`; only file176 inspection, planning, and source edits run on the login node.177- Do not silently piggyback on a job whose name is not `cursor-agent` - it may178 have different `--gres`/time and the agent did not pick its flags.179- Keep final reports concise: command, pass/fail status, key output summary, and180 log location.181- If `squeue -j "$JOBID"` shows the job gone (time limit, scancel, or tmux182 session killed), re-run the detect-or-create step and rerun only missing183 verification.184- Do not copy `salloc` logic into sibling helpers. Outside Cursor, a user may185 explicitly wrap one command with `scripts/run-standalone.sh`; inside Cursor,186 use the persistent allocation workflow.187188## Additional Resources189190- [REFERENCE.md](REFERENCE.md)191- [EXAMPLES.md](EXAMPLES.md)192- [scripts/run-standalone.sh](scripts/run-standalone.sh)