One authenticated window to a SLURM cluster — for a person at a keyboard, and for a script or an agent that has no keyboard at all.
hpc-session opens a single multiplexed SSH master connection, bringing a VPN up first
if your site needs one and answering a TOTP prompt if your site enforces two-factor
authentication. Every later command, file copy and job submission rides that one
connection and authenticates again not at all.
It exists because three ordinary site policies compose badly:
- Per-connection 2FA.
pam_google_authenticatorrefuses to reuse a code. Two fresh logins inside one 30-second step and the second is rejected — so a script that runsssh, thenscp, thensbatchstalls or fails halfway. - No controlling terminal. A cron job, a CI runner or a coding agent cannot type six
digits into a prompt.
sshwill happily take them from a program instead, which is the mechanism this tool is built around. - Full-tunnel VPNs. While the tunnel is up it monopolises the link. Anything that keeps it up "just in case" quietly costs you every other remote connection.
bash, ssh (OpenSSH 6.7+, for the %C control path), and python3 — the last one
only if your cluster uses TOTP. No other dependencies. Tested on macOS and Linux.
git clone https://github.com/HolobiomicsLab/hpc-session.git ~/git/hpc-session
ln -sf ~/git/hpc-session/bin/hpc-session ~/bin/hpc-session # anywhere on $PATH
hpc-session init # writes ~/.config/hpc-session/default.conf
$EDITOR ~/.config/hpc-session/default.conf # at minimum, set HS_HOST
hpc-session doctor # checks everything, touches no networkHS_HOST is best set to an ssh_config Host alias, so your key, user and any jump host
stay in ~/.ssh/config where every other tool can see them too:
Host mycluster
HostName login.cluster.example.edu
User yourlogin
You do not need to add ControlMaster lines to ~/.ssh/config — hpc-session
passes its own multiplexing options on every call. For an external tool that must share
the same connection, hand it $(hpc-session ssh-opts).
hpc-session open # VPN up + one authenticated master
hpc-session run squeue -u \$USER # runs ON the cluster
hpc-session run -- sacct -j 12345
hpc-session close # drop master + VPN, freeing the linkopen … run … run … close is the pattern that matters. Everything between the
first and last call is free.
The distinction that bites people:
| Command | Runs where | Use for |
|---|---|---|
hpc-session run <cmd> |
on the cluster | squeue, sbatch, ls, a compute job |
hpc-session local <cmd> |
on your machine, over the shared connection | rsync, git, sshfs |
hpc-session push <local> <remote> |
copy up | one file |
hpc-session pull <remote> <local> |
copy down | one file |
run rsync ./data host:/scratch/ would look for ./data on the cluster and fail.
That is what local is for:
hpc-session local rsync -a ./data/ mycluster:/scratch/$USER/data/hpc-session render templates/job.slurm.tmpl JOB_NAME=align PAYLOAD='./run.sh in.fa' > job.slurm
hpc-session submit job.slurm # copies it up, sbatch, prints the job id
hpc-session queue # your jobs
hpc-session watch 12345 # poll until it leaves the queue
hpc-session fetch 12345 ./results # bring back everything named after the job id
hpc-session cancel 12345submit copies a local script to HS_REMOTE_WORKDIR and submits it there; a path that
is not a local file is taken to be already on the cluster. Extra arguments go to sbatch
unchanged: hpc-session submit job.slurm --dependency=afterok:12344.
Template placeholders come from your profile, and any extra KEY=VALUE argument becomes
another substitution. A placeholder left empty removes its whole #SBATCH line, so an
unset account does not become an --account= that SLURM rejects. Keep %j in the
--output/--error patterns — that is how fetch finds the files.
On a full-tunnel VPN, do not leave watch running for a long job. Close the session
and come back to hpc-session queue later; the job does not care whether you are
connected.
The tool is the easy part. docs/ is the entry point for the rest:
knowing your site, staying inside sensible limits, installing software, and talking to
the people who run the machine.
| Cluster etiquette | the habits that keep a shared machine usable |
| Guardrails | limits and safety nets, especially for unattended runs |
| Software and environments | modules, Python, R, containers, building your own |
| Support and feedback | which channel, what to include, how to ask for a policy change |
| Site notes template | fill in once per cluster; answers most future questions |
One file per cluster in ~/.config/hpc-session/, selected with -p:
hpc-session -p bigiron open
hpc-session -p bigiron submit job.slurmEvery key is documented in config.example. Anything already set in
the environment wins over the file, so one-off overrides need no edit:
HS_SLURM_PARTITION=gpu hpc-session submit job.slurmAny VPN works, because the hooks are just shell commands — HS_VPN_UP_CMD,
HS_VPN_DOWN_CMD, and HS_VPN_STATUS_CMD (which must exit 0 when the tunnel is up).
Leave them empty if your cluster is reachable directly. Worked examples for Cisco Secure
Client, WireGuard, OpenVPN and Tailscale are in docs/vpn-hooks.md.
Set HS_TOTP_BACKEND to none (the default, key-only login) or to one of keychain,
pass, file, command. Enrollment, daily use and failure modes are in
docs/2fa-enrollment.md.
Read that page before storing a seed. A TOTP seed on the same disk as your SSH key
means one file read yields both factors — it is one-factor authentication wearing a
two-factor costume. Sometimes that trade is worth it for unattended automation;
it should never be made by accident. The command backend exists so you can keep the
seed in a hardware token or an external agent and never store it here at all.
This tool automates access to your own account, on clusters whose administrators are willing for you to do so. It is not a way around a control your site has not agreed to relax, and it has no business on a shared, service or third-party account. If a policy is blocking legitimate work, the productive move is to ask for it to be changed — the wording that tends to work is in docs/support-and-feedback.md.
What the tool does with a seed it holds: reads it straight into the generator on stdin,
so it never appears in argv or the environment where ps could see it; writes the
generated code to a mode-0600 temporary file that the askpass helper destroys after a
single read. That helper is deliberately single-shot — if it kept answering, a stale
code would make ssh re-invoke it in a loop and hang for minutes.
SECURITY.md states this in full, along with the known trade-offs and how to report a vulnerability.
tests/run_tests.shOffline and fast: RFC 6238 vectors for the code generator, template rendering, job-id parsing, config precedence, and the CLI's argument handling. No cluster required.
- One master per host alias. Two profiles pointing at the same alias share it.
rendersubstitutes single-line values only; give${PAYLOAD}a script for anything longer.fetchmatches remote filenames containing the job id. A job whose outputs are named otherwise needspull.sacctis absent on some sites;watchthen simply prints nothing after the job ends.
SKILL.md at the repository root makes this directory usable as a skill, so an agent
picks the right subcommand and respects the etiquette rules:
ln -s ~/git/hpc-session ~/.claude/skills/hpc-sessionIssues and pull requests are welcome, particularly worked profiles for other clusters
(as examples/<site>.conf, with placeholders instead of real logins) and VPN hooks for
clients not yet covered. Please keep tests/run_tests.sh green and add a case for any
behaviour you change.
Developed at the HolobiomicsLab — CNRS and Université Côte d'Azur.
MIT — see LICENSE. Copyright CNRS and Université Côte d'Azur.