Set up your workshop
Install uv, Python 3.12, git and VS Code, create a project, store an API key safely with a spending limit, and make your first model call.
Words in this lessonuv · Virtual environment · .env file · Environment variable · API key · SDK · Git · Terminal
- uv
- A fast tool that installs Python, creates project environments and manages a project's libraries. Like a kitchen manager who stocks each station with exactly the ingredients its recipe needs, and writes the list down.
- Virtual environment
- A private folder of Python and libraries for one project, separate from every other project. Like giving each recipe its own labelled pantry shelf, so the Christmas cake's ingredients never get mixed into the croissants.
- .env file
- A small private file that holds secrets like API keys as NAME=value lines, kept out of your code and out of git. Like a locked drawer for the shop keys, separate from the recipe binder everyone can read.
- Environment variable
- A named value, like ANTHROPIC_API_KEY, that programs started from your shell can read. Like notes pinned on the kitchen noticeboard that every cook on the shift can read.
- API key
- A long secret string that identifies your account when your code calls an API. Like the key to the shop's back door: anyone holding it gets in, and whatever they take goes on your tab.
- SDK
- A ready-made library that lets you call an API in a few lines of your own programming language. Like a waiter who already speaks the kitchen's language, so you do not have to shout into the kitchen yourself.
- Git
- A tool that records save points of your project so you can see changes, undo mistakes and collaborate. Like a bakery's production logbook, with a photo of every recipe card each day and the power to roll back.
- Terminal
- A text window where you type exact instructions to your computer instead of clicking. Like the kitchen's back door where staff call out exact orders, compared with the shop front's picture menu.
On this page
- Why each tool is on the list
- Step 1: Open a terminal and install uv
- Step 2: Install Python 3.12 with uv
- Step 3: Install git and VS Code
- Step 4: Create the crumb-lab project
- Step 5: Get an API key and set a spending limit
- Step 6: Store the key in .env and keep it out of git
- Step 7: Hello world, then hello Claude
- When it does not work
- Recap
- Go deeper
Arjun’s new Crumb laptop arrives on Saturday morning, still in its box. Priya has sent him a short list: terminal, uv, Python 3.12, git, VS Code, a project, an API key with a spending limit, a .env file, hello world.
“Fifteen minutes,” Arjun says to himself. He is a backend developer. He has set up machines before.
It takes him seventy minutes. Not because any step is hard, but because four small things go wrong, each in a way that is completely normal and completely baffling the first time. A command he just installed is “not found”. His computer insists it already has Python, the wrong one. He nearly publishes a secret key to the internet. And his first call to Claude fails with an error that makes no sense, because the key in his file is correct.
This lab walks you through the same setup, and the same four surprises, so that yours takes fifteen minutes. Every step ends with what you should see when it worked. If you see something else, the step tells you why.
Important
The idea in one sentence: A good workshop is a terminal, Python 3.12 managed by uv, git, and VS Code, plus one project folder whose secret API key lives in a .env file that git ignores and whose provider account has a spending limit, so you can experiment freely without leaking keys or running up bills.
Why each tool is on the list
Before installing anything, Arjun asks the right question: “Why these, specifically?” Priya answers with the bakery.
- The terminal is the back door to the kitchen. Menus and buttons are the shop front; the terminal is where you type exact instructions to your computer. Every AI tool you will use can be driven from it. (The Developer Toolkit has a full lesson on it.)
- Python is the language almost all AI engineering is written in. We use version 3.12: modern, and well supported by every AI library in this course.
- uv is the kitchen manager. It installs Python itself, creates a separate, clean set of ingredients for each project, and records exactly which library versions you used, so your project works the same on Priya’s laptop as on yours. It replaces several older tools (
pip,venv,pyenv) with one fast one. - git is a save-point system for code. Every time something works, you save a snapshot; when you break it, you go back.
- VS Code is the workbench: a free code editor with good Python support.
- An API key is your account’s password for calling a model. A spending limit makes sure a bug cannot turn into a large bill.
- A
.envfile is a small, private file that holds secrets like that key, kept out of your code and out of git.
Total cost: zero for the tools, plus a few dollars of API credit.
Step 1: Open a terminal and install uv
Open a terminal.
- macOS: press Cmd+Space, type “Terminal”, press Enter.
- Windows: press the Windows key, type “Terminal” (Windows 11) or “PowerShell” (Windows 10), press Enter.
- Linux: usually Ctrl+Alt+T, or find “Terminal” in your applications.
Type this and press Enter:
echo hello
You should see hello printed back. You just gave your computer an exact instruction.
Install uv. On macOS or Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
On Windows, in PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
These commands download uv’s official installer and run it. (Alternatives: brew install uv on macOS with Homebrew, or winget install --id=astral-sh.uv -e on Windows.) In general, only run “download and execute” commands like these from sources you trust; this one comes from uv’s own documentation, linked at the end.
Now check it worked:
uv --version
This is where Arjun’s first surprise happened. He typed it in the same window and got:
zsh: command not found: uv
(On Windows it reads “The term ‘uv’ is not recognized”.) The installer had worked. But a terminal reads its list of places to look for programs, called the PATH, only when it starts. The window he had open was started before uv existed.
Close the terminal completely and open a new one, then run uv --version again. You should now see a version number, such as uv 0.12.5 (yours may be newer; that is fine).
Step 2: Install Python 3.12 with uv
Arjun’s second surprise came from being curious. Before installing anything, he typed python3 --version and got:
Python 3.9.6
“I already have Python?” Many computers ship with an old Python that the operating system uses for its own purposes. macOS includes one; most Linux distributions include one. Leave it alone: do not upgrade or delete it, because parts of your system may depend on it. uv installs and manages its own Pythons, separately, and picks the right one per project.
uv python install 3.12
You should see something like Installed Python 3.12.14 in 2.31s (the last number of the version will differ). Check it:
uv run --python 3.12 python --version
You should now see Python 3.12.x. Notice that this did not change what plain python3 --version says. That is deliberate: your projects will use uv’s Python, and the system keeps its own.
Note
Pause and think. Why would it be a bad idea for every project on your laptop to share one Python and one big pile of installed libraries?
Show the answer
Because projects need different versions, and one change breaks another. Suppose the support bot needs version 1 of a library and next month’s RAG project needs version 2, which works differently. With one shared pile, upgrading for the new project silently breaks the old one. And you can never tell a teammate exactly what your project needs. uv solves this by giving each project its own isolated set of libraries, called a virtual environment, plus a file recording the exact versions. You will see both in Step 4.
Step 3: Install git and VS Code
git.
- macOS: run
xcode-select --installand accept the dialog (this installs Apple’s command-line developer tools, which include git). Or, with Homebrew,brew install git. - Windows: run
winget install --id Git.Git -e, or download the installer from git-scm.com and accept the defaults. Then open a new terminal. - Linux:
sudo apt install giton Ubuntu or Debian,sudo dnf install giton Fedora.
Check with git --version. You should see something like git version 2.50.1.
Now tell git who you are. Every save point records an author, and it will refuse to save without one:
git config --global user.name "Arjun Mehta"
git config --global user.email "arjun@example.com"
git config --global init.defaultBranch main
Use your own name and the email you will use for GitHub. The last line names your main line of history main, which is the modern convention. These commands print nothing when they work.
VS Code. Download it from code.visualstudio.com and install it. Then:
- Open VS Code and click the Extensions icon on the left (four small squares), or press Ctrl+Shift+X (Cmd+Shift+X on macOS).
- Search for Python and install the one published by Microsoft.
- On macOS only: open the Command Palette with Cmd+Shift+P, type “shell command”, and choose Shell Command: Install ‘code’ command in PATH. (On Windows and Linux the installer usually does this for you.)
Open a new terminal and type code --version. You should see a version number. Now code . will open the current folder in VS Code.
Step 4: Create the crumb-lab project
Make a folder for all your course work and create your first project inside it. These commands work in macOS, Linux and Windows PowerShell:
mkdir ~/code
cd ~/code
uv init crumb-lab --python 3.12 --no-package
cd crumb-lab
mkdir makes a directory, cd moves into it, and ~ means your home folder. (If ~/code already exists, mkdir complains; that is harmless.) --no-package asks uv for a simple application layout with one main.py; without it, some uv versions create a src/ folder meant for publishable libraries, which we do not need.
List what uv made, including hidden files (names starting with a dot): ls -a on macOS and Linux, ls -Force in PowerShell. You should see:
.git .gitignore .python-version README.md main.py pyproject.toml
pyproject.toml: the project’s ID card, with its name, Python version and (soon) its libraries..python-version: says “3.12”, so uv always uses the right Python here.main.py: a starter script..gitand.gitignore: uv also made this folder a git repository, with a list of files git should ignore.
Run the starter script:
uv run main.py
The first time, you should see:
Using CPython 3.12.14
Creating virtual environment at: .venv
Hello from crumb-lab!
uv noticed there was no environment yet and created one in a hidden .venv folder: this project’s private Python and library shelf. Now add the two libraries for this lab, Anthropic’s SDK (the ready-made Python library for calling Claude) and python-dotenv (which reads .env files):
uv add anthropic python-dotenv
You should see a list of packages with + signs as uv installs them and their dependencies. Open pyproject.toml and you will find them recorded under dependencies, and a new file, uv.lock, pins the exact version of every package. Commit both files to git and anyone can recreate your environment exactly with uv sync.
Many tutorials online use pip install anthropic. That installs a package too, but does not record it in your project. In this course, uv add is the equivalent, and better habit.
Step 5: Get an API key and set a spending limit
You need an account with at least one model provider. The course mostly uses Anthropic (Claude), with OpenAI and Google Gemini in places. Start with one; add others when a lesson needs them.
- Go to the Anthropic documentation and follow the link to sign in to the Console (the developer dashboard). Create an account.
- Open the billing section and add a small amount of prepaid credit, say $5. That is plenty for weeks of exercises. Leave automatic reload switched off. With prepaid credit and no auto-reload, the most you can ever spend is what you put in.
- Look in the settings for spending limits, and set a monthly limit if one is offered. Menus move around; search the docs for “spend limits” if you cannot find it.
- Open the API keys page and create a key. Name it after where it will live, like
crumb-lab-laptop, so you know which to revoke if this laptop is lost. - Copy the key immediately. It is shown only once. It starts with
sk-ant-and is long.
Do not paste it anywhere yet. Not into a chat, not into a document, not into main.py. The next step gives it a safe home.
For OpenAI, the process is similar at platform.openai.com: prepaid credit, auto-recharge off, then a key. Be aware that some providers’ “budgets” send an alert email rather than blocking requests, which is why prepaid credit without auto-recharge is the most reliable cap. Google Gemini offers a free tier through Google AI Studio (see the Gemini docs), which is a good option if you would rather not add a card yet; the alternative code at the end of Step 7 uses it.
Warning
An API key is money. Anyone who has your key can run up charges on your account. Never put a key in your code, in a screenshot, in a chat with an assistant, or in a git commit. Bots scan public GitHub for leaked keys within minutes of a push. If a key ever leaks, revoke it in the Console immediately and create a new one; deleting the file afterwards is not enough, because git history remembers.
Step 6: Store the key in .env and keep it out of git
In VS Code, open the project with code . from inside crumb-lab. Create a new file at the top level of the project (next to pyproject.toml) named exactly .env, with one line:
ANTHROPIC_API_KEY=sk-ant-paste-your-real-key-here
No spaces around = are needed, and no quotes. Save it.
Windows users: create this file in VS Code, not Notepad. Notepad likes to save it as .env.txt while showing you .env, and then nothing can find it.
Now Arjun’s third surprise. Run:
git status
You will see something like:
Untracked files:
.env
.gitignore
.python-version
README.md
main.py
pyproject.toml
uv.lock
.env is in that list. The .gitignore uv created ignores .venv and Python’s cache files, but not .env. If Arjun had typed git add . now, as he does a dozen times a day at work, his key would have been in the first commit. If he had then pushed to GitHub, it would have been public.
Add .env to the ignore list. On macOS or Linux:
echo ".env" >> .gitignore
In Windows PowerShell:
Add-Content .gitignore ".env"
(The PowerShell version matters: older PowerShell’s >> writes the file in an encoding git may not read.) Run git status again. You should now see every file except .env. Make your first save point:
git add .
git commit -m "Set up crumb-lab project"
git ls-files
git ls-files lists everything git is tracking. You should see .gitignore, .python-version, README.md, main.py, pyproject.toml and uv.lock, and no .env.
Note
Pause and think. Your teammate clones crumb-lab from GitHub. The .env file is not there, because git ignored it. How do they get the project running, and how should they know which secrets it needs?
Show the answer
They create their own .env with their own key. Secrets are per person (and per machine), never shared through git. To tell people which variables are needed, projects usually commit a harmless template called .env.example containing the variable names with blank or fake values, like ANTHROPIC_API_KEY=. Your teammate copies it to .env and fills it in. Then uv sync installs the exact libraries from uv.lock. Add a .env.example to crumb-lab now; it is a good habit.
Step 7: Hello world, then hello Claude
First, prove the key loads, without calling any model. Replace everything in main.py with:
import os
from dotenv import load_dotenv
load_dotenv() # read .env into environment variables
key = os.getenv("ANTHROPIC_API_KEY")
if not key:
raise SystemExit("No ANTHROPIC_API_KEY found. Is .env in this folder?")
# Never print a whole key. The start and end are enough to recognise it.
print(f"Key loaded: {key[:7]}...{key[-4:]} ({len(key)} characters)")
Line by line: load_dotenv() reads .env and puts each line into the program’s environment variables (named values a program can read from its surroundings). os.getenv reads one of them, returning None if it is missing. If it is missing, we stop with a helpful message instead of a confusing crash later. Then we print just enough to recognise the key.
uv run main.py
You should see Key loaded: sk-ant-... followed by the last four characters and a length of around a hundred characters. If you see “No ANTHROPIC_API_KEY found”, the .env file is missing, misnamed, or in a different folder.
Now call a model. Create hello_claude.py:
import anthropic
from dotenv import load_dotenv
load_dotenv() # puts ANTHROPIC_API_KEY into the environment
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY automatically
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=300, # a hard cap on the length (and cost) of the reply
system="You are Crumb's friendly support assistant.",
messages=[{"role": "user", "content": "Do you have eggless cakes? Answer in one sentence."}],
)
print(next(b.text for b in response.content if b.type == "text"))
print("Tokens in:", response.usage.input_tokens, "out:", response.usage.output_tokens)
The new pieces: anthropic.Anthropic() creates a client that knows how to talk to the API; messages.create sends one request; system is the standing instruction; messages is the conversation so far, here a single user message. The reply comes back as a list of content blocks, and the next(...) line picks out the text. response.usage reports how many tokens (small chunks of text) went in and out, which is what you are billed for.
uv run hello_claude.py
Arjun’s fourth surprise: it failed.
anthropic.AuthenticationError: Error code: 401 - {'type': 'error',
'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}}
main.py had just shown the right key. Priya asked one question: “Have you ever set this variable another way on this laptop?” He had: months ago, following a tutorial, he had added an old, revoked key to his shell’s startup file. load_dotenv() does not overwrite environment variables that already exist, so the old key won. He removed the line from his shell startup file, opened a new terminal, and ran it again.
You should now see something like:
Yes, we have a lovely range of eggless cakes, including chocolate truffle and pineapple!
Tokens in: 31 out: 24
Your wording will differ, because models do not produce identical text every time. A call this size costs a tiny fraction of a cent. Now look at that answer critically. The model has no idea what Crumb sells. It invented chocolate truffle and pineapple because that is what a bakery assistant usually says. That is the hallucination from the last lesson, live on your laptop, and fixing it properly is what Module 09 is for.
Prefer Gemini's free tier? Use this instead
Add GEMINI_API_KEY=your-key to .env, run uv add google-genai, and create hello_gemini.py:
import os
from dotenv import load_dotenv
from google import genai
load_dotenv()
client = genai.Client() # reads GEMINI_API_KEY
response = client.models.generate_content(
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
contents="You are Crumb's support assistant. Do you have eggless cakes? One sentence.",
)
print(response.text)
Model names change often; the current list is on the provider’s models page. Library APIs change quickly too. If a name has moved, check the docs linked below.
Finally, run it from VS Code. Open hello_claude.py. Press Ctrl+Shift+P (Cmd+Shift+P on macOS), choose Python: Select Interpreter, and pick the one inside .venv. Click the play button at the top right. You should see the same output in VS Code’s built-in terminal. If the editor underlines import anthropic in red, it is using the wrong interpreter; select the .venv one again.
Save your progress: git add . then git commit -m "First model call". Check once more that git ls-files does not list .env.
When it does not work
| What you see | What it means | Fix |
|---|---|---|
command not found: uv (or “not recognized”) |
The terminal started before uv was installed | Close every terminal window and open a new one |
python3 --version shows an old version |
That is the system’s Python | Ignore it; use uv run, which uses the project’s 3.12 |
ModuleNotFoundError: No module named 'anthropic' |
Library not installed in this project, or you ran plain python |
Run uv add anthropic inside crumb-lab, and use uv run |
No ANTHROPIC_API_KEY found |
.env is missing, misnamed (.env.txt), or in another folder |
Create .env next to pyproject.toml in VS Code |
AuthenticationError ... 401 |
The key is wrong, revoked, cut short, or an old one is set elsewhere | Check the key’s ending against the Console; look for an old variable in your shell settings |
| An error mentioning credit or billing | No credit on the account | Add prepaid credit in the Console |
.env appears in git status |
It is not in .gitignore |
Add it before any git add |
Recap
- Your workshop: a terminal, uv (which installs and manages Python 3.12), git, and VS Code with the Python extension.
uv init,uv addanduv runcreate a project, record its libraries, and run code in its private virtual environment.- Secrets go in
.env, loaded with python-dotenv;.envgoes in.gitignorebefore your first commit. - Prepaid credit with auto-reload off, plus a spending limit, caps what a bug can cost you.
- New terminal windows pick up newly installed tools; existing environment variables beat
.env.
At 11:10 a.m., Arjun walks over to Meera with the laptop and shows her the eggless cake answer.
“So it works,” she says.
“The plumbing works,” Arjun says. “My laptop can safely talk to the model, my key is locked away where git cannot leak it, and the account cannot spend more than five dollars even if I write a terrible loop. But look: it invented two cakes we do not make. The pipe is connected. Now I have to learn what to send through it.”
“How long did it take?”
“Seventy minutes. It would have been fifteen if I had read the error messages properly the first time.”
Priya grins. “Which is exactly what the Developer Toolkit is for. Next: the terminal, without fear.”
Go deeper
- uv documentation: installation options, projects, and Python versions.
- Anthropic documentation: getting started, API keys and the Messages API.
- The Python tutorial: the official introduction, if Python itself is new to you.