# How I set up a Python AI project

This is my opinionated guide to setting up a Python AI project from scratch. There are plenty of alternatives out there, but this is what's been working well for me.

* * *

## The Tools

Two things to install before anything else:

*   [**uv**](https://docs.astral.sh/uv/getting-started/installation/) — a blazing-fast Python package manager that replaces both `pip` and `venv`. It handles Python versions, dependencies, and virtual environments in one tool.
    
*   [**VSCode**](https://code.visualstudio.com/) — my editor of choice. Free, extensible, and excellent Python support. Pycharm is also excellent but for most of my learnings VSCode has been sufficient.
    

### Installing uv

On macOS or Linux, one line in your terminal:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

On Windows (PowerShell):

```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

Check it's working:

```bash
uv --version
```

* * *

## Getting Python 3.12

Here's something I love about `uv` — you don't need a separate Python installation. `uv` manages Python versions for you:

```bash
uv python install 3.12
```

Verify it's there:

```bash
uv python list
```

That's it. No fighting with system Python, no Homebrew conflicts, no PATH headaches. If you've heard of **pyenv** as an alternative, it's a solid tool, but for most beginners it's one extra thing to learn. `uv` does it all.

> **Why Python 3.12?** It's stable, widely supported, and every major AI/ML library works with it. Safe choice.

* * *

## Creating a New Project

Navigate to wherever you keep your code and run:

```bash
uv init my-project
cd my-project
```

`uv` scaffolds a clean project structure for you:

```plaintext
my-project/
├── .python-version   # pins the Python version
├── pyproject.toml    # project config & dependencies
├── README.md
└── main.py
```

[pyproject.toml](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/pyproject.toml:0:0-0:0) is the modern Python standard for project configuration — think of it as the project's passport. It declares the project name, which Python version it needs, and all its dependencies.

* * *

## Pinning the Python Version

Inside the project folder, tell `uv` to use 3.12:

```bash
uv python pin 3.12
```

This writes `3.12` into the [.python-version](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/.python-version:0:0-0:0) file. Now anyone who clones the repo uses the exact same version. No more "it works on my machine" surprises.

* * *

## Creating the Virtual Environment

A virtual environment isolates your project's packages from everything else on your machine. Without one, installing packages globally causes version conflicts across projects — it gets messy fast.

With `uv`, setup is a single command:

```bash
uv sync
```

This creates a [.venv/](cci:9://file:///Users/rob.mcbryde/code/ai-notebook/.venv:0:0-0:0) folder inside your project and installs all declared dependencies. The key thing: **you never need to activate it manually**. Use `uv run` to execute scripts and it handles the virtual environment automatically.

* * *

## Opening in VSCode

```bash
code .
```

When VSCode opens, it might prompt you to **"Select a Python Interpreter"**. Choose the one inside [.venv](cci:9://file:///Users/rob.mcbryde/code/ai-notebook/.venv:0:0-0:0) — it'll show a path like `./venv/bin/python`. This connects VSCode to your project's isolated environment.

* * *

## Two Extensions Worth Installing

Open the Extensions panel (`Cmd+Shift+X` on Mac, `Ctrl+Shift+X` on Windows) and add these two:

**Python** by Microsoft — syntax highlighting, IntelliSense, the ability to run and debug Python files. Essential.

**Ruff** by Astral Software — a linter and formatter that keeps your code consistent. It catches errors before you run code and auto-formats on save. I use this on every project.

* * *

## Adding Dependencies

Now for the actual project dependencies. I add two to every AI project:

**Ruff** for linting:

```bash
uv add ruff
```

**python-dotenv** for loading environment variables from a `.env` file:

```bash
uv add python-dotenv
```

Both commands automatically update [pyproject.toml](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/pyproject.toml:0:0-0:0) and [uv.lock](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/uv.lock:0:0-0:0). Your config will look something like this:

```toml
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "python-dotenv>=1.0.0",
    "ruff>=0.9.0",
]
```

[uv.lock](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/uv.lock:0:0-0:0) records the exact versions of every installed package. **Commit this file** — it makes the project perfectly reproducible on any machine.

* * *

## Handling API Keys Safely

This one matters a lot. AI projects almost always need API keys — for OpenAI, Anthropic, LangSmith, etc. You must **never** commit these to git.

My approach uses two files:

*   [**.env.example**](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/.env.example:0:0-0:0) — committed to the repo, contains placeholder values showing what keys are needed
    
*   `.env` — your real local file with actual secrets, never committed
    

Start by copying the example:

```bash
cp .env.example .env
```

Then open `.env` and fill in your real keys:

```bash
OPENAI_API_KEY="your-real-key-here"
ANTHROPIC_API_KEY="your-real-key-here"
```

### Why is this safe?

The [.gitignore](cci:7://file:///Users/rob.mcbryde/code/ai-notebook/.gitignore:0:0-0:0) file contains `.env`, which instructs git to completely ignore that file. It never gets staged, never gets committed, never ends up on GitHub. Your secrets stay local.

### Loading the keys in Python

With `python-dotenv` installed, two lines at the top of any file is all you need:

```python
from dotenv import load_dotenv
import os

load_dotenv()

api_key = os.getenv("OPENAI_API_KEY")
```

`load_dotenv()` reads the `.env` file and makes those variables available via `os.getenv()`.

* * *

## Running Your Code

Use `uv run` instead of calling `python` directly:

```bash
uv run main.py
```

`uv run` automatically picks up the virtual environment — no activation step needed.

* * *

## What You End Up With

After following these steps, your project looks like this:

```plaintext
my-project/
├── .env              # ← your secrets (git-ignored, never commit this)
├── .env.example      # ← template showing required variables (commit this)
├── .gitignore        # ← tells git what to ignore
├── .python-version   # ← pins Python 3.12
├── .venv/            # ← virtual environment (git-ignored)
├── main.py
├── pyproject.toml    # ← project config and dependencies
└── uv.lock           # ← exact dependency versions (commit this)
```

Clean, reproducible, and safe. Every example in my [AI Notebook repo](https://github.com/rob212/ai-notebook) follows this exact structure.

* * *

## Quick Reference

| Task | Command |
| --- | --- |
| Create new project | `uv init my-project` |
| Pin Python version | `uv python pin 3.12` |
| Install / sync dependencies | `uv sync` |
| Add a dependency | `uv add <package>` |
| Run a script | `uv run main.py` |
| Copy env template | `cp .env.example .env` |

* * *

This is my personal starting point for every AI learning experiment I run. It's opinionated, but it's fast to set up and gets out of the way so I can focus on what actually matters — the code.

Always open to feedback and suggestions for alternatives or improvements. But so far, this setup has been working well for me. 🚀

*This post is part of my* [*AI Notebook series*](https://robmcbryde.hashnode.dev) *— documenting my journey learning AI and agentic systems, one step at a time.*
