Setup guide
Install Infrathon and an agent CLI, prepare a task, and start a run.
Requirements
Linux x86-64 with H100 NVL or H100 SXM GPUs. The first-run example uses two GPUs: one for Worker and one for Judge.
Install Docker Engine 24+, an NVIDIA driver, and the NVIDIA Container Toolkit.
On Ubuntu, install the host tools:
sudo apt-get update
sudo apt-get install -y git git-lfs jq util-linux rsync patch curl ca-certificates tmux python3 coreutils tar xz-utils
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv tool install 'huggingface_hub[cli]==1.23.0'
git lfs install
sudo usermod -aG docker "$USER"Open a new login session for Docker group access, then configure and check the GPU runtime:
export PATH="$HOME/.local/bin:$PATH"
umask 022
sudo nvidia-ctk runtime configure --runtime=docker --set-as-default
sudo systemctl restart docker
docker info --format '{{.DefaultRuntime}}'
docker run --rm -e NVIDIA_VISIBLE_DEVICES=all \
nvidia/cuda:12.8.1-base-ubuntu24.04 nvidia-smi -LThe runtime should print nvidia and the container should list your GPUs. Allow about 25 GB for one task’s images and additional space for its models and run outputs; Miles requires a large scratch disk.
Installation
Clone the repository and install its Python dependencies. Run the following setup commands in Bash from this checkout.
git clone https://github.com/InfrathonX/Infrathon.git
cd Infrathon
uv sync --frozen --dev --python 3.12
uv pip install --python .venv/bin/python numpy==2.5.2
uv pip install --python .venv/bin/python \
--index-url https://download.pytorch.org/whl/cpu torch==2.14.1
.venv/bin/sforge --helpHost CUDA PyTorch for Flux and StreamDiffusionV2
These launchers check GPU peer access on the host. Put a CUDA PyTorch environment first on PATH:
uv venv ~/.venvs/host-torch --python 3.12
uv pip install --python ~/.venvs/host-torch/bin/python \
--index-url https://download.pytorch.org/whl/cu128 torch==2.8.0
export PATH=~/.venvs/host-torch/bin:$PATHAgent harness setup
The first-run example uses Codex. The builder downloads Node.js and the CLI into ../agent_runtimes/. The versions below are pinned in the repository.
Codex
export CODEX_CLI_VERSION=0.159.3
export SFORGE_AGENT_RUNTIME_DIR="$(realpath -m "../agent_runtimes/codex-$CODEX_CLI_VERSION")"
if [ ! -d "$SFORGE_AGENT_RUNTIME_DIR" ]; then
launch/build-agent-runtime.sh --agent codex --version "$CODEX_CLI_VERSION"
fi
PATH="$SFORGE_AGENT_RUNTIME_DIR/bin:$PATH" "$SFORGE_AGENT_RUNTIME_DIR/bin/codex" --versionEnable device-code login in your ChatGPT account or workspace, then sign in and save file-based credentials:
PATH="$SFORGE_AGENT_RUNTIME_DIR/bin:$PATH" \
"$SFORGE_AGENT_RUNTIME_DIR/bin/codex" \
-c 'cli_auth_credentials_store="file"' login --device-auth
chmod 600 "$HOME/.codex/auth.json"For API-key login or signing in from a local computer, see Codex authentication.
Claude Code
Build the Claude runtime and create an OAuth token:
CLAUDE_CODE_VERSION=2.1.287
CLAUDE_RUNTIME_DIR="$(realpath -m "../agent_runtimes/claude-code-$CLAUDE_CODE_VERSION")"
if [ ! -d "$CLAUDE_RUNTIME_DIR" ]; then
launch/build-agent-runtime.sh --agent claude-code --version "$CLAUDE_CODE_VERSION"
fi
PATH="$CLAUDE_RUNTIME_DIR/bin:$PATH" "$CLAUDE_RUNTIME_DIR/bin/claude" --version
PATH="$CLAUDE_RUNTIME_DIR/bin:$PATH" "$CLAUDE_RUNTIME_DIR/bin/claude" setup-tokenPaste the token into a file:
mkdir -p "$HOME/.config/infrathon"
read -rsp 'Claude OAuth token: ' CLAUDE_TOKEN; printf '\n'
(umask 077; printf '%s\n' "$CLAUDE_TOKEN" > "$HOME/.config/infrathon/claude.token")
unset CLAUDE_TOKEN
chmod 600 "$HOME/.config/infrathon/claude.token"Flux/Comet MoE accepts --agent claude-code --claude-token "$HOME/.config/infrathon/claude.token". Set SFORGE_AGENT_RUNTIME_DIR to the Claude runtime for that launch. The FP8 launcher used in this guide runs Codex.
For Miles, set AGENT=claude-code, SFORGE_AGENT_RUNTIME_DIR, and CLAUDE_OAUTH_TOKEN_FILE in the task’s run.env, and delete CODEX_AUTH_JSON_PATH from it. The submission reviewer retains the separate Codex settings in Configuration.
Change the version
Change the version variable in the chosen example and build that runtime. Save its SFORGE_AGENT_RUNTIME_DIR in launch/mlsysforge.env; for Codex, also save CODEX_CLI_VERSION. Task images can be reused.
Miles stores its runtime and version settings in the task’s run.env.
Configuration
After Codex login, enter a model ID available to your account. Worker and reviewer use the same model and credentials.
read -rp 'Model ID: ' MODEL
CODEX_CLI_VERSION="${CODEX_CLI_VERSION:-0.159.3}"
CODEX_RUNTIME_DIR="$(realpath -m "../agent_runtimes/codex-$CODEX_CLI_VERSION")"
cat > launch/mlsysforge.env <<EOF
MODEL=$MODEL
REASONING_EFFORT=max
CODEX_CLI_VERSION=$CODEX_CLI_VERSION
CODEX_AUTH_JSON_PATH="$HOME/.codex/auth.json"
SFORGE_AGENT_RUNTIME_DIR="$CODEX_RUNTIME_DIR"
INFRATHON_ASSETS_ROOT="$HOME/.cache/infrathon/assets"
SFORGE_VERSION_STORE_OPTIONAL=1
SFORGE_LLM_JUDGE_MODE=enforce
SFORGE_LLM_JUDGE_ENGINE=agent
SFORGE_LLM_JUDGE_AGENT=codex
SFORGE_LLM_JUDGE_MODEL=$MODEL
SFORGE_LLM_JUDGE_AGENT_RUNTIME_DIR="$CODEX_RUNTIME_DIR"
SFORGE_LLM_JUDGE_CODEX_AUTH_JSON="$HOME/.codex/auth.json"
EOF
set -a
. launch/mlsysforge.env
set +aThe FP8 example saves submission archives without a candidate-history store. Miles, Concurrent serving, KVPress, KVzip and Quant-VideoGen also need Candidate history. Use each task’s Run the task section for its GPU, model, data, and launcher settings.
Custom model endpoint
For the FP8 launcher’s OpenAI-compatible endpoint (http://HOST:PORT/v1, serving /v1/responses), set these values in launch/mlsysforge.env. The API key file contains the key and has mode 0600.
MODEL=MODEL_ID
MODEL_API_BASE_URL=http://ENDPOINT_HOST:PORT/v1
MODEL_API_KEY_FILE=/absolute/path/to/api.keyTo use that endpoint for the reviewer too, remove SFORGE_LLM_JUDGE_CODEX_AUTH_JSON from the file, add the following settings, and load the configuration in a new shell:
SFORGE_LLM_JUDGE_MODEL=MODEL_ID
SFORGE_LLM_JUDGE_API_BASE_URL=http://ENDPOINT_HOST:PORT/v1
SFORGE_LLM_JUDGE_API_KEY_FILE=/absolute/path/to/api.keyModels and data
Select Dynamic grouped FP8 GEMM and download its task assets. The download scripts read INFRATHON_ASSETS_ROOT from the configuration loaded into your shell.
TASK=standalone-dynamic-grouped-fp8-h100-v3-scratch
TASK_DIR="tasks/latest/$TASK"
"$TASK_DIR/assets/fetch.sh"
.venv/bin/python scripts/infrathon/assets.py check "$TASK"Dataset access and local assets
Task data comes from the gated Hugging Face dataset Infrathon/Infrathon. Request access on its page, and for gated models grant access to your account, then sign in before fetching:
hf auth loginThe repository’s default dataset is Infrathon/Infrathon. Set INFRATHON_HF_DATASET to use another dataset, or INFRATHON_ASSETS_SOURCE to install from an existing local copy.
Docker images
With TASK and TASK_DIR selected in Models and data, choose the host hardware: h100-94gb-400w for H100 NVL or h100-80gb-700w for H100 SXM.
export INFRATHON_HARDWARE=h100-94gb-400w
INFRATHON_PULL=1 bash "$TASK_DIR/scripts/build_images.sh"The helper pulls the recorded Work and public Judge images, adds the Judge’s private data, and records the local images for launch. For Miles and MInference, use this helper instead:
scripts/infrathon/pull_images.sh "$TASK"Docker Hub tags and direct pull
To download the images separately:
IMAGE_REPOSITORY="${INFRATHON_REGISTRY_REPOSITORY:-$(jq -r '.repository' scripts/infrathon/registry.json)}"
PUBLISHED="$TASK_DIR/images/published.json"
WORK_TAG="$(jq -er --arg hw "$INFRATHON_HARDWARE" '.hardware[$hw].work_tag' "$PUBLISHED")"
JUDGE_TAG="$(jq -er --arg hw "$INFRATHON_HARDWARE" '.hardware[$hw].judge_public_tag' "$PUBLISHED")"
docker pull "$IMAGE_REPOSITORY:$WORK_TAG"
docker pull "$IMAGE_REPOSITORY:$JUDGE_TAG"The default repository is infrathon/infrathon. For FP8 on H100 NVL, the Work tag is h100-94gb-400w-standalone-dynamic-grouped-fp8-h100-v3-scratch-work and the public Judge tag is the same with -judge at the end. The helper above reuses these downloads to finish task preparation.
Build from source
bash "$TASK_DIR/scripts/build_images.sh"Candidate history
Miles, Concurrent serving, KVPress, KVzip and Quant-VideoGen use a store for candidate versions. With TASK_DIR set to your task, initialize and register it:
Initialize the store
export SFORGE_VERSION_STORE_ROOT="$PWD/../infrathon-version-store"
.venv/bin/python - "$SFORGE_VERSION_STORE_ROOT" "$TASK_DIR" <<'PY'
import json, sys, uuid
from pathlib import Path
from sforge.harness.version_store import VersionStore
root, task = (Path(p).expanduser().resolve() for p in sys.argv[1:])
specs = list((task / "tasks").glob("*.json"))
assert len(specs) == 1, "Expected one task definition"
task_id = json.loads(specs[0].read_text())["task_id"]
root.mkdir(parents=True, exist_ok=True)
marker = root / ".sforge-version-store.json"
if not marker.exists():
marker.write_text(json.dumps({"schema_version": 1,
"kind": "sforge-version-store", "store_id": uuid.uuid4().hex}) + "\n")
VersionStore.open(root)
folder = root / "tasks" / task.name
(folder / "runs").mkdir(parents=True, exist_ok=True)
path = folder / "task.json"
record = {"schema_version": 1, "task_directory": task.name, "task_id": task_id}
if path.exists():
assert json.loads(path.read_text()) == record, "Existing registration differs"
else:
path.write_text(json.dumps(record) + "\n")
assert VersionStore.open(root).supports_task(task_id)
print("Registered", task_id, "in", root)
PY
.venv/bin/sforge versions --version-store-root "$SFORGE_VERSION_STORE_ROOT" --verifyFor Miles, copy the printed absolute path into SFORGE_VERSION_STORE_ROOT in the task’s run.env. For Concurrent serving, keep this variable exported in the launch shell. Register each task once in the same store.
Run a task
Start the FP8 task with Codex after completing Configuration, Models and data, and Docker images. Select two available GPU indices and an unused Judge port.
set -a
. launch/mlsysforge.env
set +a
nvidia-smi --query-gpu=index,uuid --format=csv,noheader
RUN_ID="fp8-$(date -u +%Y%m%d-%H%M%S)"
launch/standalone-fp8/run.sh --work-gpu 0 --judge-gpu 1 \
--model "$MODEL" --effort max --hours 12 \
--judge-port 18096 --run-id "$RUN_ID" \
--auth "$CODEX_AUTH_JSON_PATH"This starts the agent in the foreground. Add --tmux to run it in a detached session.
Submit from the Work container
The agent submits candidates during its run. In an interactive Work container session, these commands submit the current implementation and list submissions:
sforge-submit --details
sforge-submit --listOther tasks have their setup and launch commands under Task List.
Results and logs
Runs are saved under outputs/<task-directory>/runs/<run-id>/. Flux, ORPO, GKD and StreamDiffusionV2 use tasks/latest/<task>/logs/runs/<run-id>/; the Miles tasks use $MILES_SCRATCH_ROOT/<task>/.
| File | Contents |
|---|---|
sforge-run.log | Agent run log. |
<task-id>/submissions/agent-N/report.json | Score, validation results, and feedback. |
<task-id>/submissions/agent-N/submission.tar.gz | Submitted source code. |
<task-id>/final_archive.tar.gz | Workspace at the end of the run. |
completion.json | Run status and final-evaluation location. |
For setup questions, join Discord.