NSCC Job Manager
Submit, monitor, and manage jobs on NSCC's Aspire 2A HPC cluster without leaving the
editor. Ship a project, submit PBS jobs, watch them run, and read live output — from a
sidebar panel, or from an AI coding agent through a bundled MCP server.
What it does
- Submit panel — pick GPUs and walltime, paste the commands you want to run (one per
line, for array jobs), and submit. No hand-written PBS script required.
- Job tree — every job you've submitted, grouped by project, refreshing on its own.
Array jobs collapse into one entry with per-subjob status underneath. Finished jobs stay
until you dismiss them, because
qstat forgets them fast.
- Live output — tail a running job's stdout/stderr as it happens, instead of waiting
for it to finish.
- Status bar — connection state and a running/queued job count at a glance.
.pbs/.def linting — squiggles and quick-fixes for common PBS script and Apptainer
definition mistakes, before you submit. Includes cluster-specific checks: %j is a Slurm
idiom PBS takes literally, -q ai needs ngpus >= 1, log paths must not live under the
50 GB /home quota, and an array wider than the destination queue's max_run will run
serially.
- Container builds — draft an Apptainer
.def with an agent, then build the .sif
locally (Aspire's login node cannot build images).
- An MCP server, so an AI coding agent (Claude Code, Codex, etc.) can ship, submit,
monitor, and diagnose jobs on your behalf — through the same core the UI uses, so the
cluster rules can't drift between the two. A job your agent submits shows up in your
sidebar within a second.
Requirements
- macOS or Linux. POSIX
sh, ssh, and rsync are assumed. WSL works; native
Windows does not.
- VS Code 1.90+.
- An NSCC Aspire 2A account, reachable from your network (campus or VPN).
- Apptainer or Singularity locally, only if you want to build container images from
this extension.
Aspire doesn't support SSH keys, so the extension keeps an SSH multiplexed connection
alive and reads a locally stored password rather than prompting you every time.
Setup
1. Install the extension
Install NSCC Job Manager from the VS Code Marketplace, then open your project folder.
An Aspire icon appears in the activity bar.
2. Store your cluster credentials
Open the Aspire sidebar. With no credentials stored yet, the Jobs view shows a
Set Up Credentials button (also Aspire: Set Up Credentials in the Command
Palette). It stages a setup script in a real terminal — reading a password without echoing
it needs an actual TTY — and you press Enter to run it. Three steps:
- Writes an SSH multiplexing
Host aspire block to ~/.config/aspire/aspire.conf and
Includes it from ~/.ssh/config (your existing config is backed up first).
- Records the login node's host key.
- Prompts for your password and writes it to
~/.config/aspire/password, mode 600.
Your password goes straight from that terminal to the file — the extension never sees or
handles it. Safe to re-run any time; every step checks the current state before changing
anything.
The password is stored in plain text at mode 600. Anyone who can read your account
(including root) can read it. This is the tradeoff a cluster without key auth forces.
3. Connect and verify
Run Aspire: Connect, then Aspire: Test Connection — it runs end-to-end checks
(SSH, PBS, scratch) and reports each result in the output channel. The status bar should
read $(account) <your-username>.
4. Set your charge code
Set aspire.projectCode in Settings to your PBS project code (#PBS -P). Leave it empty
and you'll be asked on every submit.
5. Build a container image
The Submit panel runs your commands inside an Apptainer image, and refuses to submit
without one. It looks for <folder-name>.sif in the project root — override with
aspire.sifName.
- No
.def yet? Aspire: Generate Apptainer Definition (agent) drafts one with your
local claude or codex CLI and shows it as a diff. (This spends tokens on your own
account.)
Aspire: Build Container Image builds the .sif locally, streaming the build log
into the output panel. It lints the .def first and asks before spending twenty minutes
on a definition that already has errors.
aspire.containerPython (default /app/.venv/bin/python) is the interpreter inside the
container that each command line is handed to.
6. Choose what gets shipped
Shipping is an rsync of your project to /scratch/users/nus/<user>/<name>/. Exclusions
live in a .aspireignore file at the project root, so the editor and agents read exactly
the same list. Run Aspire: Edit Ship Exclusions (.aspireignore) to create or edit it;
a sensible starter list (.git, .venv, __pycache__, node_modules, wandb, …) is
offered on first use.
The old aspire.shipExclude setting is deprecated and no longer read. Existing values
were migrated to .aspireignore automatically — remove the setting once you've checked.
7. Optional — wire up an AI agent
Run Aspire: Configure Agent Access (MCP) to register the bundled MCP server with
Claude Code (.mcp.json) or Codex (~/.codex/config.toml). Then run
Aspire: Install Skill (Claude Code / Codex) for the operational knowledge that goes
with it — cluster quirks, failure diagnosis, direct SSH fallbacks. No separate marketplace
or clone required, and it tells you when a newer copy is bundled.
Everyday use
|
|
| Submit panel |
Job name, GPUs, walltime, queue, and one command per line. A modal shows the routing plan (destination queue, array width, warnings) before anything is submitted. |
| Jobs view |
Runs grouped by project, refreshing on their own. Right-click a job for logs, live output, resubmit, cancel, or dismiss. |
| Status bar |
$(account) haotian 2R 1Q when connected, Aspire: disconnected when the node is reachable but the SSH master is down, Aspire: offline when it isn't. Both disconnected states click to retry. |
Command Palette
Everything below is available from the Command Palette (Cmd/Ctrl+Shift+P).
| Command |
What it does |
Aspire: Connect |
Bring up the multiplexed SSH master |
Aspire: Disconnect |
Tear it down |
Aspire: Refresh |
Force a poll now instead of waiting for the timer |
Aspire: Ship Project to Scratch |
rsync the project to scratch without submitting anything |
Aspire: Test Connection |
End-to-end checks (SSH, PBS, scratch), results in the output channel |
Aspire: Set Up Credentials |
Stage the one-time credential setup in a terminal |
Aspire: Edit Ship Exclusions (.aspireignore) |
Create or edit the project's ship-exclusion list |
Aspire: Build Container Image |
Build a .sif from a .def, locally |
Aspire: Generate Apptainer Definition (agent) |
Draft a .def with your local agent CLI, shown as a diff |
Aspire: Configure Agent Access (MCP) |
Register the bundled MCP server with Claude Code or Codex |
Aspire: Install Skill (Claude Code / Codex) |
Install the bundled cluster skill into either agent |
Aspire: Show Jobs From All Projects |
Widen the Jobs view and status bar to every project on this machine |
Aspire: Show Only This Project's Jobs |
Narrow it back to the current workspace |
Aspire: Show Log Output |
Open the extension's output channel |
From the Jobs view only
These act on a specific run, so they're on the tree item's context menu rather than the
palette:
| Command |
Where |
Aspire: Open Job Log |
Any job or subjob — stdout / stderr |
Aspire: Watch Live Output |
Any job or subjob — tails as it runs |
Aspire: Cancel Job |
Running or queued jobs; qdel behind a modal confirm |
Aspire: Dismiss Finished Job |
Finished jobs; removes it from the tree |
Aspire: Resubmit |
Any job; reuses that run's recorded qsub arguments |
Aspire: Copy Job ID / Aspire: Copy Remote Path |
Any job |
Aspire: Diagnose Failure (agent) |
Finished jobs; logs → agent → proposed patch |
Settings
All under aspire.*.
| Setting |
Default |
Meaning |
host |
aspire |
SSH host alias (the Host block in ~/.ssh/config) |
projectCode |
(empty) |
PBS charge code (#PBS -P); empty means prompt each submit |
remoteName |
(workspace folder name) |
Directory under /scratch/users/nus/<user>/ |
sifName |
<folder>.sif |
Container image filename in the project root |
containerPython |
/app/.venv/bin/python |
Interpreter inside the container |
apptainerModule |
apptainer/1.5.0 |
Module loaded before running the container |
buildCommand |
apptainer |
Local build executable (singularity on older installs) |
pollIntervalRunning |
30 |
Seconds between polls while a job is running |
pollIntervalQueued |
90 |
Seconds between polls when jobs are only queued |
connectionCheckInterval |
20 |
Seconds between connection heartbeats; never authenticates |
notify |
true |
Notify when a job starts or reaches a terminal state |
showAllWorkspaces |
false |
Show every project's runs, not just this workspace's |
mcp.allowCancel |
false |
Let agents cancel jobs; off because qdel is irreversible and a tool call can't ask you to confirm |
agent.command |
(empty) |
claude or codex for generation; empty means detect and ask |
pbsTemplate.single / pbsTemplate.array |
(bundled) |
Path to your own .pbs template with {{TOKEN}} placeholders |
binPath |
(bundled) |
Override the bundled helper-script directory |
Once Aspire: Configure Agent Access (MCP) has run, an agent gets these tools:
| Tool |
|
cluster_status |
Connection state, remote user, scratch root, routing queues, active run count |
list_jobs |
Recorded runs, newest first, including submissions still shipping |
get_job |
Full state of one job — queries both PBS servers, falling back to accounting history after PBS drops it |
ship_project |
rsync the project to scratch |
ship_and_submit |
Ship, then submit an existing .pbs |
submit_commands |
Ship, render a .pbs from the template, submit one job or an array |
wait_for_job |
Block until a job finishes — preferred over polling get_job |
tail_log |
Read the end of a job's output — a live merged stream while it runs, the PBS files after |
validate_pbs |
The same lint the editor shows as squiggles, for .pbs and .def |
cancel_job |
qdel, only if you enable aspire.mcp.allowCancel |
There is deliberately no general ssh_run(command) verb. Narrow verbs only.
Known limits
- No always-on monitoring. Polling stops when VS Code closes and the MCP server exits.
License
MIT — see LICENSE.