rl-agentic-launch-iris
SkillCloud & infraLaunch / relaunch agentic MarinSkyRL (SkyRL GRPO) RL on Marin's Iris / CoreWeave GPU cluster (cw-us-east-02a, 8x H100-80GB + InfiniBand per node) via `python -m cloud.iris.launch_rl_iris` (run from the MarinSkyRL repo root) + the gpu-rl Docker image (NO Apptainer SIF). Covers the MoE 30B-A3B arms (CP + DCP=2 + R3 @ 131k) and the dense 8B arms (seqnorm + TIS); the iris configs default to the **Megatron** training backend (`trainer.strategy: megatron`, FSDP2 selectable) — the exact launcher flag set (`--rl_config`, `--model_path`, `--train_data`, `--num-nodes`, `--rendezvous-dir`, `--job-name`, `--priority`, `--cpu`, `--max-retries`), the gang/leafgroup/Kueue multi-node Ray rendezvous, the iris config-authoring rules (NO container block, load-bearing top-level `extra_env:` forwarding, disaggregated placement + explicit `num_inference_engines`, SIF→Docker env translation), and the bring-up gotchas (`--cpu 48`, `--max-retries ≥1`). Use when asked to launch / relaunch an agentic SkyRL RL run on Iris / CoreWeave. Cluster access/hardware particulars live in .agents/ops/iris/ops.md (this skill defers to it). Reference: cloud/iris/launch_rl_iris.py, cloud/iris/start_rl_iris_controller.py, cloud/iris/configs/, .agents/ops/iris/ops.md.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the rl-agentic-launch-iris skill
What this skill tells your AI
The instructions your AI receives, as published by open-thoughts/openthoughts-agent in .agents/skills/rl-agentic-launch-iris/SKILL.md and read by ahel’s review.
⚠ Do not add comments to YAMLs. Report recommendations directly to the supervisor.
rl-agentic-launch-iris
Read first:
.agents/ops/iris/ops.mdfor Iris access, preamble, gotchas, and helper scripts.
⚠ Local clone = ground truth (CLAUDE.md §Always). ALL code/config edits go in the local Mac checkouts → commit. The Iris launcher uploads the LOCAL workspace to
/app(PYTHONPATH puts/app+/opt/skyrl/skyrl-trainfirst), so a local commit takes effect on the next launch immediately — no push-then-pull-on-cluster (there is no Iris clone to pull). Still never hand-edit on a remote, leave divergent state, or patch-by-rsync. The vLLM fork (compiled) is fixed only by an image rebuild + digest bump.
Agentic SkyRL/GRPO RL runs via python -m cloud.iris.launch_rl_iris from the MarinSkyRL repo root.
Each rollout is a Harbor agent episode in a Daytona sandbox (terminal_bench). Target is CoreWeave
cw-us-east-02a, with exclusive 8×H100-80GB nodes and gang/leafgroup scheduling. The gpu-rl Docker
image is the runtime: no Apptainer SIF or hpc.launch. Iris configs default to Megatron; set
trainer.strategy: fsdp2 for FSDP2.
1. Prereqs (the pre-launch preamble)
Launch from the local Mac, otagent py3.12 conda env, from the MarinSkyRL repo root:
cd ~/Documents/MarinSkyRL # `-m cloud.iris.launch_rl_iris` resolves from here; on main (or a cloud/iris branch)
source "${DC_AGENT_SECRET_ENV:?set DC_AGENT_SECRET_ENV to the secrets file first}" # HF_TOKEN, WANDB_*, DAYTONA_* (forwarded into the pod)
export KUBECONFIG=~/.kube/coreweave-iris-gpu # CoreWeave GPU cluster kubeconfig (see ops doc)
# otagent python = /Users/benjaminfeuer/miniconda3/envs/otagent/bin/python (symlinks fail in the sandbox); the `iris` SDK is installed in this env
- Confirm access before submitting; run
irisandkubectlsynchronously. The headroom check is in the ops doc. - Cluster config auto-resolves to
~/Documents/marin/lib/iris/config/cw-us-east-02a.yaml; override with--cluster-configonly if it moved. - gpu-rl image: deps-only (RL venv
/opt/openthoughts/envs/rl+ vLLM fork + MarinSkyRL editable/opt/skyrl+ harbor), pinned by immutable@sha256:digest incloud/iris/launch_rl_iris.py:DEFAULT_RL_DOCKER_IMAGE(NOT the floating:gpu-rltag — it stale-caches). Source syncs at runtime so first-party edits live without a rebuild; bump the digest on an image rebuild.
2. The canonical launch
Lifted from each iris config's header (carries its own ready-to-run command):
cd ~/Documents/MarinSkyRL # canonical launcher repo (on main / a cloud/iris branch)
source "${DC_AGENT_SECRET_ENV:?set DC_AGENT_SECRET_ENV to the secrets file first}"
python -m cloud.iris.launch_rl_iris \
--rl_config cloud/iris/configs/<cfg>.yaml \
--model_path <hf-id> \
--train_data '["<HF-repo-or-harbor-task-set>"]' \
--num-nodes N \
--gpus_per_node 8 \
--cpu 48 \
--max-retries 1 \
--rendezvous-dir s3://marin-us-east-02a/iris/rl-<slug>/<run> \
--job-name <name> \
--priority interactive \
--no-wait
Varies per arm: --rl_config, --model_path, --train_data, and --num-nodes (§3). Fixed on Iris:
--gpus_per_node 8, --cpu 48, --max-retries 1, --priority interactive, and --no-wait. Flag glossary:
--rl_config— repo-relative path undercloud/iris/configs/; it must exist in synced/app.--model_path— HF id (e.g.Qwen/Qwen3-8B,Qwen/Qwen3-Coder-30B-A3B-Instruct). CoreWeave nodes have egress → model pulled from HF online (do NOT setHF_HUB_OFFLINE).--train_data— JSON-list string'["..."]'(HF repoDCAgent/…/laion/…, or a harbor task set).--num-nodes N— number of whole, exclusive H100 nodes; one Iris task and eight GPUs per node.--rendezvous-dir— REQUIRED for--num-nodes>1(launcher hard-errors otherwise). Shared store the multi-node Ray head/workers rendezvous through. Build this offmarin_prefix()(rigging.filesystem— auto-resolves the active cluster's storage root, so a store migration is followed automatically); the literal below is an illustrative fallback. On cw-us-east-02a use ans3://URI under themarin-us-east-02abucket (e.g.s3://marin-us-east-02a/iris/rl-<slug>/<run>); the cluster injects working creds into every task pod (theiris-task-envSecret) so no external creds are needed and you must NOT forwardAWS_*/R2_*(clobbers the pod's injected creds and silently targets real AWS S3). Use a fresh sub-path per run so a stale head file from a prior attempt isn't picked up. ⚠ Store iss3://marin-us-east-02a(CW), NOT the olds3://marin-na(R2) — amarin-narendezvous PUT resolves to the nonexistentmarin-na.cwlota.comand STALLS.--job-name— controls/benjaminfeuer/<name>; set it explicitly for monitoring and teardown.--priority—production/interactive/batchband.--cpu/--memory/--disk— per-node resources (defaults 64 / 512GB / 512GB; set--cpu 48).--max-retries K— Iris re-brings-up a failed gang up to K times; use ≥1.--skyrl-ref <git-ref>—git fetch && checkoutthe baked/opt/skyrlMarinSkyRL clone to a newer/pinned commit BEFORE running (deps are baked, but skyrl-train is editable → the checkout is live; the launcher also purges stale.pycso the checkout isn't shadowed by baked bytecode). Use to pick up a MarinSkyRL fix that landed AFTER the image build without rebuilding.Do not omit
--skyrl-refwhen the required change postdates the baked2d9feefcommit. Compare local HEAD with the image commit; pass--skyrl-ref <local-HEAD>or rebuild and bump the digest.--skyrl_override '++a.b.c=val'— repeatable Hydra override (last-wins over the yaml).--dry-run— print the resolved config + in-container command without submitting (always dry-run a new config first: confirm the hydra args show the placement /num_inference_engines/ TP / extra_env you intend — see the resume log's VALIDATED block for the pattern).
3. Config map + node count (--num-nodes MUST match the config)
--num-nodes = total_GPUs_in_config / 8. Derive the GPU budget from the yaml (policy_num_nodes,
ref_num_nodes, num_inference_engines × inference_engine_tensor_parallel_size):
Config (cloud/iris/configs/…, MarinSkyRL) | Model | Layout | GPUs → --num-nodes |
|---|---|---|---|
56GPU_qwen3_8b.yaml | dense 8B (seqnorm + TIS) | disaggregated: 1 node policy + 1 node ref + 48×TP1 engines | 56 → 7 |
32GPU_qwen3_coder_30b_a3b_ep4.yaml | Qwen3-Coder-30B-A3B (MoE) — CANONICAL 30B (EP4) | disaggregated (EP4) | 32 → 4 |
- Only these configs are in MarinSkyRL
cloud/iris/configs/. Port any OT-Agent config into that directory and confirm its referenced assets are in the MarinSkyRL tree before use. - Smoke first. No dedicated toy smoke config ships. Validate via
--dry-run+ a short real arm before a full run. Author a throwawaycloud/iris/configs/*.yaml(colocate_all, small max_steps,trace_upload.enabled: false) if you need a live bring-up check. - Dense-8B is typically
Qwen/Qwen3-8B(orlaion/…8B); the MoE arm isQwen/Qwen3-Coder-30B-A3B-Instruct. Read each config header.
4. Config-authoring rules for cloud/iris/configs/ (MarinSkyRL)
Porting a Jupiter (Apptainer SIF) config to Iris (Docker) — the load-bearing rules:
- Every referenced asset must exist in the MarinSkyRL tree.
run_rl.pyparses/appand opens asset paths relative to it. Use the rootchat_templates/qwen3_thinking_acc.jinja2, not the terminal-bench example. - NO
container:/ SIF / apptainer / conda / binds / pydeps block. The gpu-rl image IS the container (RL venv/opt/openthoughts/envs/rl, MarinSkyRL/opt/skyrl, workspace synced to/app). - Top-level
extra_env:is load-bearing.load_config_extra_env()merges it intoEnvironmentSpec; the Iris path does not usecontainer.extra_env. Values are coerced to strings and launcher values win collisions. - SIF→Docker env translation (what to DROP / KEEP / hardcode in
extra_env:):- DROP all
APPTAINERENV_*duplicates,TRITON_LIBCUDA_PATH,LIBRARY_PATH=/.singularity-d/libs(SIF-only), andHF_HUB_OFFLINE/TRANSFORMERS_OFFLINE(CoreWeave has egress). - DROP the GH200/SIF NCCL disables
NCCL_P2P_DISABLE/NCCL_NVLS_ENABLE/NCCL_COLLNET_ENABLE— on H100+IB they CRIPPLE the intra-node NVLink all-reduce a TP=8 engine (DCP) depends on. Use NCCL defaults (NVLink intra-node + IB inter-node); keepNCCL_DEBUG=INFO+ the observability/raised timeouts (SKYRL_WORKER_NCCL_TIMEOUT_IN_S,TORCH_NCCL_*).disable_custom_all_reduce: trueSTAYS. Do NOT add these for MoE (falsified A/B — the salad was the w13 gate/up swap below). - KEEP
SKYRL_W13_RELOAD_BRACKETON (default1) for MoE. Re-applies the FusedMoEw13gate/up kernel swap (process_weights_after_loading) on the disaggregated RL weight update. WITHOUT it, the served MoE policy emits CJK token-salad (100% reward-0) on H100/FlashInfer-CUTLASS (fixed MarinSkyRL2bb70a88). Swap-inert on triton/dense → byte-identical there, so just leave it on; do NOT set0. Bring-up check: engine log showsinitialize_layerwise_reload/finish_weight_reload. - HARDCODE
LD_LIBRARY_PATH: /opt/openthoughts/envs/rl/lib(the RL conda prefix) — NOT$CONDA_PREFIX/lib: k8s does NOT shell-expand$VAR, so a literal$CONDA_PREFIX/libis a broken path. - KEEP the vLLM serve flags (
VLLM_USE_FLASHINFER_SAMPLER=0,VLLM_ATTENTION_BACKEND=FLASH_ATTN),PYTORCH_CUDA_ALLOC_CONF, and (for the MoE R3/DCP arm) the guard envVLLM_ALLOW_ROUTED_EXPERTS_DCP=1(+VLLM_MQ_MAX_CHUNK_BYTES_MB,VLLM_ROUTED_EXPERTS_SIDE_TIMEOUT_SECONDS,VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS) and the EPDIAG probe arm — all as plain top-levelextra_env:.
- DROP all
- Disaggregated (
colocate_all: false) vs colocated (true): smoke is colocated; real arms are disaggregated with policy/ref FSDP nodes separate from vLLM engines. - Set
num_inference_enginesEXPLICITLY when disaggregated.build_skyrl_hydra_argsonly DERIVES it (= total_gpus / TP) when the YAML leaves itnull. On a disaggregated split that derivation is WRONG — it counts the policy-only nodes too. E.g. the 30B config:(8×8)//8 = 8would be derived, but only 4 engines exist (4 nodes are policy-only). 4 is authoritative; pin it. (The colocated smoke can leave it null.) --gpus_per_node 8FORCESpolicy_num_gpus_per_node/ref_num_gpus_per_nodeto 8 (build_skyrl_hydra_argsoverrides the YAML values when the flag is set).policy_num_nodes/ref_num_nodesARE honored from the YAML. So in a port: divide the Jupiter node counts by 2 (GH200 4-GPU → H100 8-GPU nodes) for*_num_nodes; list*_num_gpus_per_node: 8for documentation only (the flag overrides it).- MoE / DCP placement constraints (hard — don't hand-edit around them): a TP=8 engine must place
intra-node on ONE 8-GPU node (NVLink decode, no cross-node TP — what CoreWeave's 8-GPU nodes unblock vs
Jupiter's 4-GPU).
inference_engine_mp_backend: false(RAY executor, R3+DCP mandatory) +async_scheduling: false(R3 guard). DCP ceilingdcp ≤ tp/num_kv_heads; MoE dim-0 guard(num_experts // ep) % fsdp == 0;policy_strict_spread_pg: truereserves policy nodes up front so engines land on the disjoint gen nodes.
5. Gang scheduling + multi-node Ray rendezvous
--num-nodes N→replicas=Nwhole H100x8 tasks. For GPUs with replicas>1,resolve_multinode_defaultsreturnsCoschedulingConfig(group_by="leafgroup")— all N nodes co-scheduled on one InfiniBand leaf fabric, all-or-nothing. cw-us-east-02a enables Kueue gang admission (host_network: truefor NCCL/IB) → the N-task gang is admitted atomically (all N whole nodes granted, or the job queues). At submit:replicas=N, coscheduling=leafgroup, then pods sit SchedulingGated (normal Kueue gang pre-admit) until admitted.- Every node runs
start_rl_iris_controller.py; Iris injectsIRIS_TASK_ID,IRIS_NUM_TASKS, andIRIS_ADVERTISE_HOST. Rank 0 starts Ray, writesray_head.json, waits for all nodes, and runsrun_rl.py. Workers join via the rendezvous then wait forray_head.done; rank 0 clears stale rendezvous on retry.
6. Bring-up gotchas (the pre-flight checklist)
--cpu 48, not 64. Persistent system overhead leaves too few 64-core nodes for an N-node leafgroup gang; 48-core requests fit all nodes. Memory 512GB is fine.--max-retries ≥1for the transient HF weight-resolution flake. At scale (e.g. 32 FSDP ranks each resolving sharded safetensors online) a single rank can hit a transient HF Hub HTTP/EOF failure → transformers reports… does not appear to have a file named model.safetensors; withmax_retries=0that one rank kills the gang.--max-retries 1re-brings-up the gang (time-only cost). A first-party retry-wrapper landed in MarinSkyRL (0b2b05b); keep--max-retries ≥1as belt-and-suspenders. (DURABLE alternative: pre-stage the model into the image's HF cache / a shared snapshot before the FSDP workers start, or raiseHF_HUB_DOWNLOAD_TIMEOUT.)- TP=8 must place intra-node on an 8-GPU node (NVLink decode) — guaranteed by
--gpus_per_node 8+ the per-engine STRICT_PACK PG; do not split a TP=8 engine across nodes. - DCP / CP / R3 / EPDIAG env must reach the pod — that's the
extra_env:forwarding (§4). After a launch, confirm from the rank-0 log that the guard ENGAGED (not rejected): SkyRL_validate_dcp_cfg VLLM_ALLOW_ROUTED_EXPERTS_DCP=1: allowing …AND vLLM-forkvllm.py … allowing --enable-return-routed-experts with decode_context_parallel_size=2. Theenvs.py "Unknown vLLM environment variable detected: VLLM_ALLOW_ROUTED_EXPERTS_DCP"line is ONLY the env-registry whitelist not listing the fork-added var — it is NOT a no-op when the fork's own code reads the var (it does). ghcr.ioblob EOFImagePullBackOffself-heals.shm_broadcast: No available shared memory broadcast block found in 60sis benign while engines wait for policy weights; do not salvage either.
7. Standing constraints (do NOT violate)
- Daytona RL concurrency ≤ 6 RUNNING per cluster. PENDING/SchedulingGated gangs that haven't admitted don't count, but a RUNNING gang does — don't launch a 7th concurrent RL job.
enable_db_registration: falsein every iris RL yaml (it is). DB registration is a manual cleanup step, never a launch flag.- The a3 series is CONCLUDED — do NOT launch / refill / auto-advance a3 rows. Active iris arms: the seqnorm/TIS dense-8B port + the CP+DCP2+R3 MoE port.
- Never alter config/hparams mid-series — propose a separate experiment.
- Daytona snapshot caps are HARD — clean STALE snapshots, never raise the cap
(
.agents/projects/daytona/daytona.md). - Never kill a RUNNING job without explicit permission; never
iris cluster restart/stop/bounce (kills every running job).iris job kill /benjaminfeuer/<job>is job-scoped (with permission).
8. Monitoring + completion
Use authoritative lifecycle state for liveness and terminal detection:
iris job summary --json→state. Use log greps only for sel_rows, EPDIAG, and throughput analysis.
- Watch a run (the primitive — use this, do not grep logs for liveness):
It pollsPY=/Users/benjaminfeuer/miniconda3/envs/otagent/bin/python # otagent env: ships iris + a WORKING kubernetes # one-shot authoritative state (state + error + per-task + pod cross-check): $PY scripts/iris/iris_ops.py /benjaminfeuer/<job> --once --json # watch until the run leaves RUNNING, emit a line on every transition, exit terminal: $PY scripts/iris/iris_ops.py /benjaminfeuer/<job> --interval 60 # exit 0 succeeded · 1 failed/killed/worker_failed/unschedulable · 2 absent (disappeared/0-pods) · 3 erroriris job summary --json(falls back to the SQLquery) and treats "no controller record AND 0 pods" as a TERMINALabsentverdict — the case the old content-watch missed. Importable:from scripts.iris.iris_ops import get_job_state, watch.
⚠ FRESH-LAUNCH 15-MIN + 30-MIN CHECK-INS MUST PARSE THE ROLLOUT LOGS — lifecycle state is necessary but NOT sufficient.
iris_opsreportsrunning, pods=8, failure_count=0for a job that is silently dead: a throughput-starvation wedge (engines decode but an oversubscribed queue never drains → the step-0 batch never assembles), node-local data starvation (a rank-0-only task-dataset stage → 7 ranks see empty task dirs → every rolloutreward 0), or vLLM simply never serving. State-polling alone reports all of these as "healthy." For ANY fresh Iris RL launch, the 15-min AND 30-min check-ins capture + parse the logs. Dispatch a subagent armed withrl-job-health-deep-dive(operationalizes the ladder below into a KILL/NO-KILL: syncs trace_jobs + logs viapeek … pull, live-polls the GPUs against the serving-throughput LUT, reads the literal rollouts). Procedure:# capture finelog + per-rank pod logs (our RL jobs use a REMOTE s3 trials_dir, so peek's ls/cat/grep bail — # `pull` still grabs the logs, where the live bring-up signal is). Override IRIS_BIN: the script defaults to # the marin .venv iris, which CANNOT drive cw (broken kubernetes import). IRIS_BIN=/Users/benjaminfeuer/miniconda3/envs/otagent/bin/iris \ bash scripts/iris/analyze_coreweave_rl_job_live.sh <pod-name-substring> pull # → ~/Documents/experiments/traces/<job>_<stamp>/logs/iris_finelog.logThen grep the finelog for the milestone ladder — each rung rules out a specific silent-death mode:
[rl-iris] MarinSkyRL now at <sha>(+HEAD is now at <sha>) — confirms--skyrl-reftook (the fix is live). Absent ⇒ forgot the flag / it failed → stale baked code.Staging train_data on this node (rank N/8)for ALL N ranks — else node-local data starvation → silentreward 0. Must see every rank.Ray nodes alive: N/N— rendezvous complete.- HF weight load: an
OSError … does not appear to have a file named model.safetensorsFOLLOWED byload_pretrained_with_retry … retrying→ the0b2b05bretry catching it (BENIGN). The SAME error with no retry wrapper + a task failure ~70s in = the stale-imagebuild_modelscrash. (MoE arm:AttributeError: … 'norm_topk_prob'is the other stale-image crash — must be ABSENT.)- vLLM ACTUALLY GENERATING =
loggers.py … Avg generation throughput: >0 tokens/s, Running: R reqs, Waiting: Wrecurring.Waitingpersistently ≫Runningwith flat throughput = the throughput-starvation WEDGE (de-oversubscribe: lowern_concurrent_trials/ raisemax_num_seqs).Waiting ≈ 0= healthy.- MoE DCP arm only:
_validate_dcp_cfg VLLM_ALLOW_ROUTED_EXPERTS_DCP=1: allowing …+decode_context_parallel_size=2— the R3+DCP guard engaged (theUnknown vLLM environment variableline is the benign whitelist note, NOT a no-op).- Train driver:
Resumed training from global_step 0+TerminalBenchGenerator initialized … Concurrent trials: K(Harbor RolloutCoordinator up; K×(#engines) = yourn_concurrent_trials).- Trials completing: first
result.json/ reward written +global_step0→1. At 15/30 min a 131k arm usually has ZERO completed (episodes are long) — report as "rollouts executing, 0 trials completed yet," NEVER "healthy/done." Completed-trial artifacts land in the remotes3://marin-us-east-02a/iris/<job>/trace_jobs(read viaaws s3 ls --endpoint-url <R2>), not the pod.Verdict rule: rungs 1–7 green + generation throughput >0 +
Waiting≈0⇒ genuinely progressing (even with 0 completed trials). Generation throughput 0 after engines are up, orWaiting≫Running, or no RolloutCoordinator, or any rank missing its data-stage line ⇒ escalate now (wedge / starvation), do not wait for the next sweep.
- Manual state / logs (synchronous calls only — no background
iris/kubectl; use the otagent iris binary — the bare marin.venv/bin/irislacks a workingkubernetesfor the cw k8s controller backend):
Rank-0 (# iris-side state (0=UNSPECIFIED 1=PENDING 2=BUILDING 3=RUNNING 4=SUCCEEDED 5=FAILED 6=KILLED # 7=WORKER_FAILED 8=UNSCHEDULABLE) — the watcher already wraps this: /Users/benjaminfeuer/miniconda3/envs/otagent/bin/iris --cluster=cw-us-east-02a query \ "SELECT job_id,state FROM jobs WHERE job_id LIKE '/benjaminfeuer/<job>%'" -f csv # richest single-job authoritative call (state + error + exit + per-task states + finished_at): /Users/benjaminfeuer/miniconda3/envs/otagent/bin/iris --cluster=cw-us-east-02a job summary /benjaminfeuer/<job> --json # via the python SDK (matches the launcher's client): # IrisClient.status(JobName.from_wire("/benjaminfeuer/<job>")) # IrisClient.fetch_task_logs(JobName.from_wire("/benjaminfeuer/<job>/0")) # rank 0 = the driver/…/<job>/0) is the training driver; ranks 1..N-1 are Ray workers that clean-exit on the head's done-marker (a healthy run's head failing shows1 task failed, N-1 succeeded). - Healthy bring-up: gang admitted → N pods running →
Ray nodes alive: N/N→ driver → engines → policy mesh → first step. A 30B/131k arm can take ~1h to first rollout and ~2.5–3h to gs1 forward. - Mandatory progress columns (per
monitor-job-tables): entropy / log_ratio / grad_norm + reward — not just step. For full-history science (sel_rows / EPDIAG / throughput stats) use the windowed pagination (scripts/iris/analyze_iris_harbor_job.py), NOTiris job logs --tail(under-samples 10–100×). - On completion →
rl-agentic-job-cleanup(best-ckpt selection, HF upload, the manual Supabase DB registration, trace export).enable_db_registrationstays false at launch. - Teardown:
iris job kill /benjaminfeuer/<job>(with permission). Rescue banked traces from the s3:// jobs/rendezvous path if the trace upload didn't auto-run (ops.md§4).
Final checks
- Always
--dry-runa new or edited config. Checkcolocate_all,policy_num_nodes, explicitnum_inference_engines, TP/DCP/CP/EP/FSDP, and intendedextra_env:with noNCCL_P2P_DISABLE. - This is the terminal_bench/Harbor/Daytona path. Forward
DAYTONA_*; do not forwardAWS_*orR2_*.
Signals
- GitHub stars
- 291
- Forks
- 41
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
rl-agentic-launch-iris- Source
- github.com/open-thoughts/openthoughts-agent