DON’T PANIC.
You’ve just joined the team. You have a fresh laptop, a Slack account you haven’t figured out how to mute yet, and a link to a monorepo called “yolo.” You are about to set up a development environment involving no fewer than three package managers, two operating systems, a Python lockfile the size of a novella, and a cluster named after a bird of prey.
This guide contains the same steps as the official Getting Started doc. The difference is that I’ve added context for the parts where you will, statistically speaking, get stuck and quietly question your life choices. All commands are accurate and copy-pasteable. The commentary is there so you know why you’re running them, and so you feel less alone when something inevitably explodes.
Let’s go.
Act I: Cloning the Repo (The Easy Part)
gh repo clone infinity-microsoft/yolo
cd yolo
git submodule update --init --recursive
Clone it to ~/yolo. Some internal tools have this path hardcoded, because of course they do. If you put it somewhere creative like ~/code/projects/work/microsoft/repos/yolo, you will discover this the hard way in about two weeks.
If gh repo clone fails with an auth error, run gh auth login first. GitHub CLI will walk you through an OAuth flow. It takes 30 seconds. You’ll feel silly for not doing it sooner.
The --recursive flag on submodule init is important. Without it, you’ll have directories that exist but are empty, which is the git equivalent of opening a refrigerator and finding only a single condiment.
Act II: Installing uv (Your New Best Friend)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv is a Python package manager written in Rust, which means it’s fast in the way that makes you suspicious. “There’s no way it resolved 400 dependencies in 0.3 seconds” fast. It replaces pip, poetry, conda (for dependency management), and most of your excuses for getting coffee while packages install.
You will use uv for everything. Installing deps. Running code. Running tests. It is the one ring. Learn to love it. We’ll get to the specifics in Act V.
Act III: The Great Environment Setup
This is where the guide forks based on where you’re working. Think of it as a choose-your-own-adventure book, except both paths lead to Python virtual environments and one of them also involves a supercomputer.
Are you on a MacBook? You’re doing local dev. Read everything.
Are you on Condor? You’re on a GPU cluster. Skip the steps marked [SKIP ON CONDOR] — Condor already has conda and torch baked into the system image, like a hotel room that comes pre-furnished. You just have to know where the furniture is.
Step 1: Create a conda environment [SKIP ON CONDOR]
conda create -n yolo python=3.12.3
conda init $SHELL
Then close your terminal and reopen it, because conda init modifies your shell profile and shells don’t re-read their own config files while they’re running. This is one of those facts about Unix that everyone learns exactly once, in exactly this way.
“Wait,” you say, “I thought uv replaced conda?” It does, mostly. But torch is a 2GB monster with CUDA bindings and platform-specific wheels, and uv handles it better when it can inherit torch from a conda environment rather than downloading it from scratch. Think of conda as the foundation contractor and uv as the interior designer. The foundation contractor pours the concrete slab (torch); the interior designer does everything else.
Step 2: Install torch in the conda env [SKIP ON CONDOR]
conda activate yolo
conda install -y pip
export PYTHONNOUSERSITE=1
pip install torch==2.7.0 torchvision==0.22.0 torchaudio --index-url https://download.pytorch.org/whl/cpu --extra-index-url https://pypi.org/simple
Yes, we’re using pip inside conda. Yes, conda purists are screaming. The PYTHONNOUSERSITE=1 prevents pip from seeing packages in your user site-packages, which would otherwise cause the kind of version conflicts that make grown engineers weep.
The --index-url flag points to the CPU-only torch wheels. You’re on a Mac. You don’t have NVIDIA GPUs. This is fine. The Mac build is for writing and testing code, not for training models. Training happens on Condor, where torch is already installed with full CUDA support and the GPUs cost more than your car.
This step matters. uv will later inherit this torch installation via --system-site-packages. If you skip this or get the version wrong, you’ll get mysterious import errors about 40 minutes from now, and you’ll have forgotten that this step was the cause.
Step 3: Initialize the uv environment
This is where uv takes over.
On Condor:
uv venv --system-site-packages --python /mnt/vast/python/miniconda3/envs/yolo312/bin/python3.12
uv sync --all-packages --frozen
On MacBook (with conda):
uv venv --system-site-packages --python $HOME/miniconda3/envs/yolo/bin/python
uv sync --all-packages --frozen
The --system-site-packages flag is the bridge between conda and uv. It tells uv: “hey, there’s already a Python environment with torch in it — use that, and layer everything else on top.” Without this flag, uv creates a hermetic venv that can’t see torch, and you’re back to the 2GB download conversation.
--frozen means “use the lockfile exactly as-is, don’t try to resolve anything.” This is what you want. The lockfile has been tested. Your laptop’s opinion about dependency resolution has not.
The Mac “Too Many Open Files” Interlude
If you’re on macOS and uv sync dies with Too many open files, run:
ulimit -n 2048
This is because macOS ships with a default open file limit of 256, which was probably reasonable in 1997 when the biggest software project was Netscape Navigator. A monorepo with 400+ packages disagrees.
Step 4: Source environment variables [CONDOR ONLY]
source /mnt/vast/configs/.bash_env
source /mnt/vast/configs/.launcher_api_keys
These set up cluster-specific paths, API endpoints, and credentials. On your Mac, these don’t exist, and you don’t need them. On Condor, they’re load-bearing.
Step 5: Verify
uv run python -c "import torch; print(torch.__version__)"
Expected output: 2.7.0+cpu
If you get this, congratulations. You have a working Python environment with torch. This is genuinely an achievement. If you get an ImportError, go back to Step 2 and check whether your conda env is activated and torch is actually installed. If you get a version mismatch, something has gone wrong in a way that will require detective work. Check which Python uv is actually using with uv run which python.
Act IV: Dev Environment (The Part Where You Actually Write Code)
The Python environment is set up. Now let’s make it a development environment.
Pre-commit hooks
uv sync
uv run pre-commit install
This installs git hooks that run formatting and linting checks before every commit. You will be annoyed by this exactly twice — once when it reformats a file you thought was fine, and once when it blocks a commit because of a trailing whitespace. After that, you’ll forget it exists, which is the hallmark of good tooling.
The yolo CLI (optional but recommended)
uv run yolo setting init --cluster {mango-pdx|falcon-phx-ga|falcon-phx-gb|condor1|condor2}
This configures the yolo CLI for your target cluster. The cluster names deserve a brief field guide:
| Cluster | Personality |
|---|---|
| Condor | The big GPU cluster. Named after the bird. Two instances: condor1 and condor2. This is where training happens. |
| Mango | Portland-based infra cluster. Runs services, CI, and container registries. Named after the fruit, presumably. |
| Falcon | Phoenix-based GPU clusters. Two generations: GA and GB. Fast, new, slightly temperamental. Named after the bird that hunts other birds. |
Pick whichever cluster your team uses. If nobody has told you which one, ask in Slack. If you pick the wrong one, the CLI will just time out when you try to connect, which is the cluster equivalent of calling a wrong number.
Neptune API key [CONDOR ONLY]
Go to neptune.mai.microsoft.com and get your API key. Neptune is the experiment tracking platform. It records metrics, hyperparameters, and the slow realization that your learning rate was wrong.
Getting a compute node [CONDOR ONLY]
You’ll want two kinds of nodes:
CPU node (for development):
uv run yolo login # plain terminal
uv run yolo login --vscode # VSCode Remote-SSH (recommended)
This gives you a CPU node where you can edit code, run tests, and generally live your life without burning GPU hours. Think of it as your desk at the office.
GPU node (for running experiments):
uv run yolo interactive # bash session
uv run yolo interactive --vscode # VSCode tunnel
uv run yolo interactive --vscode --detached # runs in background
This gives you a GPU node with actual GPUs. Think of it as the expensive lab equipment.
Important warning: Code changes made directly on an interactive GPU node can be lost. The node’s filesystem is ephemeral. If the node gets preempted (and it will — GPU nodes get preempted like interns get assigned to oncall), your unsaved work goes with it. Prefer yolo login --vscode on a CPU node for development, and use interactive GPU nodes only for running things.
When you land on either node, you’ll be at /app/yolo with a cached venv at /venv. This is your working directory. It exists. It has your code. Don’t overthink it.
Act V: The uv Rabbit Hole
You’re going to use uv every day, so here’s the mental model.
The key concepts
uv.lock — The lockfile. One file, entire monorepo. It pins every dependency to an exact version with hashes. It’s checked into git. Do not edit it by hand. Do not look at it for too long. It’s 10,000+ lines and it knows things about your dependency tree that you don’t want to know.
uv sync — Installs dependencies. Reads the lockfile, downloads what’s missing, removes what shouldn’t be there. Idempotent — running it twice does nothing the second time.
uv run — Runs a command inside the managed environment. Prepend it to anything: uv run python, uv run pytest, uv run mypy. If you forget the prefix and use bare python, you’ll be using system Python or conda Python or some other Python that doesn’t have your deps installed, and you’ll get an import error that will take you 15 minutes to diagnose.
uv add / uv remove — Adds or removes a dependency for a specific package. Updates both pyproject.toml and uv.lock.
Commands you’ll actually use
# Sync everything (after pulling main, after lockfile changes)
uv sync --all-packages
# Sync just one package (faster, for focused work)
uv sync --package mai_config
# Rebuild compiled deps (when C extensions are acting up)
uv sync --package mai_kernels --reinstall
# Run Python
uv run python
# Run tests
uv run pytest mai_config/
# Add a dependency to a specific package
uv add --package mai_multimodal cvxpy
Where You Will Get Stuck (A Prophecy)
These are not hypothetical. These are the things that have happened to every person who has set up this repo. I’m documenting them here so you can skip the part where you spend 45 minutes thinking you broke something fundamental.
Merge conflicts in uv.lock
You pulled main, you have conflicts in uv.lock, and the diff is 800 lines of hashes that mean nothing to you.
Do this:
git checkout origin/main -- uv.lock && uv sync
Do NOT try to resolve the conflicts manually. Do NOT delete uv.lock and run uv lock from scratch. The lockfile is generated output — treat it like a compiled binary. Take the upstream version and re-sync. Done.
Bloated uv.lock diffs
Your PR shows a 2000-line diff in uv.lock and you only added one dependency. This usually means your local uv is a different version than what CI uses. Run:
uv self update
Then re-lock. The diff should shrink to something reasonable. If it doesn’t, check whether you accidentally changed the Python version or platform markers.
“Singleton lock file” error on interactive nodes
You get an error about a singleton lock file and nothing works.
rm -rf ~/yolo-vscode
Then reconnect. This directory caches VSCode server state, and sometimes it holds a stale lock. Deleting it is safe. This is the “turn it off and on again” of Condor development.
Slow cache clearing on Condor
If you need to clear the uv cache, do not rm -rf ~/.cache/uv directly. Condor’s filesystem handles large recursive deletes about as gracefully as a cat handles a bath. Instead:
mv ~/.cache/uv ~/.cache/uv-tmp
Then let it get cleaned up in the background, or delete it later. The mv is instant because it’s a metadata operation. The rm would have taken ten minutes because it’s deleting thousands of small files one by one.
Act VI: Other Dev Tools (The Supporting Cast)
Pyright (static type checking)
uv run pyright
Pyright catches type errors before your code runs. In VSCode, install the Pylance extension — it uses Pyright under the hood and gives you inline type errors, autocomplete, and that satisfying feeling of red squiggles disappearing as you fix things.
Ruff (formatting and linting)
Ruff is the code formatter. It’s configured in pyproject.toml (currently v0.9.9). It’s opinionated about things like import ordering and trailing commas, and you should let it be. Arguing with a formatter is like arguing with a traffic light — technically possible, entirely pointless.
VSCode setup:
- Install the Ruff extension
- Set the path to use the project’s version:
"ruff.path": ["uv run ruff"] - Enable format-on-save in VSCode settings
Once configured, Ruff formats your code every time you save. You’ll never think about indentation again. This is the dream.
The Survival Cheat Sheet
For the impatient — the entire setup in one block, with no commentary. MacBook version. Copy, paste, go.
# 1. Clone
gh repo clone infinity-microsoft/yolo
cd yolo
git submodule update --init --recursive
# 2. Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 3. Conda env with torch
conda create -n yolo python=3.12.3
conda init $SHELL
# (reopen terminal)
conda activate yolo
conda install -y pip
export PYTHONNOUSERSITE=1
pip install torch==2.7.0 torchvision==0.22.0 torchaudio \
--index-url https://download.pytorch.org/whl/cpu \
--extra-index-url https://pypi.org/simple
# 4. uv env
uv venv --system-site-packages --python $HOME/miniconda3/envs/yolo/bin/python
uv sync --all-packages --frozen
# 5. Verify
uv run python -c "import torch; print(torch.__version__)"
# Should print: 2.7.0+cpu
# 6. Dev tools
uv sync
uv run pre-commit install
If that all worked, you’re done. Welcome to the monorepo. It’s a lot. But now you know where everything is, and more importantly, you know what to do when it breaks.
Go write some code. And remember: uv run before everything. Everything.