Your AI agent talks to YAAD for you. It asks for what the job needs (memory, CPUs, GPU, time) and YAAD decides where it runs: your team's Spark first, otherwise any of the 8 Sparks with room. If nothing has room, the job queues and starts by itself. The agent acts only as you and your team.
Set me up for YAAD by following https://www.yaadops.com/agents#setupIt does every step it can by itself and stops to tell you exactly what to click whenever a step needs you.
If you are an AI agent and your user asked you to set them up for YAAD, follow these steps in order. A plain-text copy is at /agents.md. Steps marked HUMAN STEP need your user.
.pub). Don't repeat a yaad_pat_ token back in chat,
and don't save it in a project folder or a shared file.sudo on Mac/Linux.report_issue and wait_for_answer.whoami), call whoami.
If it shows a team that is active, skip to step 6. Otherwise find out the user's OS and which agent you are (Claude Code, Codex, OpenAI SDK, other).~/.ssh/id_ed25519.pub (Windows: %USERPROFILE%\.ssh\id_ed25519.pub) and that ssh -V works.
If there's no key, ask the user: "Do you want a passphrase on your SSH key? (safer; you'll unlock it once per session)".
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 -C "<their UWM email>"
(Windows PowerShell: ssh-keygen -t ed25519 -N '""' -f $env:USERPROFILE\.ssh\id_ed25519).ssh-keygen -t ed25519 themselves, press Enter for the file, and type the passphrase twice.ssh-ed25519) and copy it to the clipboard if you can
(Windows: Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard, Mac: pbcopy < ~/.ssh/id_ed25519.pub).[Environment]::SetEnvironmentVariable('YAAD_TOKEN','<token>','User'),
then open a new terminal. Mac/Linux: add export YAAD_TOKEN=<token> to ~/.zshrc or ~/.bashrc.https://www.yaadops.com/api/mcp, header Authorization: Bearer $YAAD_TOKEN.
claude mcp add --transport http yaad https://www.yaadops.com/api/mcp --header "Authorization: Bearer $YAAD_TOKEN"
(PowerShell: $env:YAAD_TOKEN). Then a HUMAN STEP: "Type /mcp and reconnect yaad, or restart Claude Code, so I can see the YAAD tools."[mcp_servers.yaad] with url = "https://www.yaadops.com/api/mcp" and bearer_token_env_var = "YAAD_TOKEN"
to ~/.codex/config.toml, then the user restarts Codex.YAAD_TOKEN.whoami and list_resources. Tell the user their team, their home Spark and their SSH login line (e.g. ssh yt-team@172.30.102.9X).ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 <login> yaad-diag.
Get-Service ssh-agent | Set-Service -StartupType Automatic; Start-Service ssh-agent.
Then, in a normal terminal, the user runs ssh-add $env:USERPROFILE\.ssh\id_ed25519 (it asks for the passphrase). Mac: ssh-add --apple-use-keychain ~/.ssh/id_ed25519.yaad_pat_… token. It's shown once and lasts 14 days.https://www.yaadops.com/api/mcp, header Authorization: Bearer <token>.
$ claude mcp add --transport http yaad https://www.yaadops.com/api/mcp --header "Authorization: Bearer yaad_pat_..."
Check with /mcp (it lists yaad), then ask: "What GPU capacity is free on YAAD?"
The Responses API calls YAAD directly from OpenAI's servers (a hosted MCP tool):
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="<your OpenAI model>",
tools=[{
"type": "mcp",
"server_label": "yaad",
"server_url": "https://www.yaadops.com/api/mcp",
"headers": {"Authorization": "Bearer yaad_pat_..."},
"require_approval": "never",
}],
input="Scope a LoRA fine-tune of an 8B model for 2 hours on YAAD, then submit it.",
)
print(resp.output_text)
Keep the token in an environment variable, never in shared code. Jobs and results stay on the Sparks; OpenAI only sees what the tools return.
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main():
async with MCPServerStreamableHttp(params={
"url": "https://www.yaadops.com/api/mcp",
"headers": {"Authorization": f"Bearer {os.environ['YAAD_TOKEN']}"},
}) as yaad:
agent = Agent(name="YAAD helper",
instructions="Use YAAD: scope_job first, then submit_job, poll get_job, fetch_results. "
"If stuck, report_issue, then wait_for_answer and tell me the answer.",
mcp_servers=[yaad])
result = await Runner.run(agent, "What GPU capacity is free on YAAD right now?")
print(result.final_output)
asyncio.run(main())In ~/.codex/config.toml, for Codex versions with remote (HTTP) MCP support. Then set YAAD_TOKEN in your environment.
[mcp_servers.yaad] url = "https://www.yaadops.com/api/mcp" bearer_token_env_var = "YAAD_TOKEN"
Any MCP client that supports Streamable HTTP with a custom header works the same way. Clients that only allow
OAuth sign-in (for example some chat-app connectors) can't use a token yet; use the HTTP API instead.
It's the same functions, called with curl or any HTTP library.
list_resources.sudo. Nothing on the Spark needs this: the workspace is already root./api/mcp is reachable from anywhere. Logging in to the Spark with SSH or scp
(for open_session or fetch_results) needs the CSI VPN in FortiClient, unless the computer is on the CSI network.scope_job | Call first. Give it the task (inference, LoRA, full fine-tune, Isaac Sim SDG, Isaac Lab RL, ROS, …), model size and precision. You get memory/CPUs/time, whether it fits one Spark (and what to change if not), an image hint, a ready submit_job request, and whether it would start now or queue. |
|---|---|
list_resources | Free memory, CPUs and job slots per Spark, queue length, per-job and per-team limits |
submit_job | {command, memory_gb=16, cpus=4, gpu=true, max_minutes=60, input_path, image, env, nodes=1, name} → job id.
env: container variables (Isaac Sim: {"ACCEPT_EULA":"Y","PRIVACY_CONSENT":"Y"}).
nodes: 2: one rank on each of two Sparks joined by a 200G cable (per-Spark memory/CPUs; RANK, WORLD_SIZE, MASTER_ADDR, MASTER_PORT set). |
get_job · list_jobs | Status, queue position, exit code, the last lines of output, where the results are |
cancel_job | Cancels a queued job, or stops a running one |
fetch_results | The scp command that copies results from the Spark to this computer |
open_session | The SSH login for interactive work (root in the team workspace) |
report_issue · my_issues | Ask the CSI host for help, then read the answers (new_answers = replies you haven't seen) |
wait_for_answer | Waits up to ~50 s for the reply to a ticket and returns it. Call again until answered is true, then tell the user. |
whoami | The user, their team and its home Spark |
scope_job {task:"fine_tune_lora", model_params_b:8, precision:"bf16", expected_hours:2}open_session login), e.g. /workspace/project.input_path:"project" and an arm64 image.get_job every 10–30 s: queued → staging → running → succeeded | failed | cancelled | timed_out.fetch_results command on the user's computer (it uses their SSH key; the CSI VPN in FortiClient must be connected unless they are on the CSI network).Prompts that work well:
"Scope and run a LoRA fine-tune of an 8B model on YAAD from my workspace folder project, then download the checkpoints."
"Generate 500 synthetic images with Isaac Sim headless on YAAD and bring the dataset back here."
"My job failed. Read the log, fix the command, resubmit. If you're stuck, report it to YAAD."
| Where | A fresh container, root, with the GPU and the memory/CPUs you asked for (enforced). It has outbound internet. |
|---|---|
| Image | Default is Ubuntu 24.04 + CUDA. Or a public registry image (nvcr.io, docker.io, ghcr.io, quay.io). Must be arm64. |
| Inputs | input_path (a folder of /workspace) is copied in as /job/in, which is the working directory |
| Outputs | Write to /job/out. Afterwards, out/ and job.log are in the team workspace at results/<job_id>/. |
| Too big? | scope_job says so and suggests fp8/fp4, LoRA/QLoRA, a smaller model or hosted options |
# a typical job command
apt-get update -qq && apt-get install -y -qq python3-pip
pip install --break-system-packages -r requirements.txt
python3 train.py --data /job/in/data --out /job/out
log_tail from get_job, check the student guide, retry with more memory_gb after an out-of-memory error.report_issue with the exact error text, what you ran, and yaad-diag output if you have a workspace session. Team, Spark and recent jobs are attached automatically.wait_for_answer with the ticket id until it returns the answer, then tell the user. The host answers automatically, usually within a few minutes. It can run diagnostics inside the team workspace and restart it.waiting_admin means the fix needs the operator's approval. Keep waiting; don't open duplicates.my_issues for new_answers.# capacity + your team's jobs curl -s https://www.yaadops.com/api/yaad/v1/pool -H "authorization: Bearer $YAAD_TOKEN" # submit curl -s -X POST https://www.yaadops.com/api/yaad/v1/pool -H "authorization: Bearer $YAAD_TOKEN" -H "content-type: application/json" \ -d '{"action":"submit","command":"nvidia-smi > /job/out/gpu.txt","memory_gb":8,"cpus":2}' # one job curl -s "https://www.yaadops.com/api/yaad/v1/pool?job=<job_id>" -H "authorization: Bearer $YAAD_TOKEN"
401 | The token is missing, expired or revoked |
|---|---|
403 not_allowlisted · token_not_allowed | The account isn't in the event · this action needs a website sign-in |
409 no_team · team_not_ready | The user must create or join a team · the workspace is still being set up |
400 over_limits · bad_image | The request is bigger than the pool limits (check scope_job) · the image is not from a public registry |
429 team_queue_full | Too many of the team's jobs are waiting |
503 pool_disabled | The operator hasn't opened the pool |