Technical leads succeed when the dev environment disappears into the background and the team moves quickly with confidence. This guide shows you how to build a seamless AI development environment end-to-end—combining IDE integrations and CLI tools—so your team ships reliable models and services faster.
What you’ll get:
- A repeatable, cross-platform setup (macOS, Linux, Windows + WSL) that works locally and remotely
- Tight IDE integrations (VS Code, JetBrains, Neovim) with linters, debuggers, notebooks, and test explorers
- Command-line tooling for dependency management, testing, linting, experiment tracking, containers, and CI/CD
- Practical, copy-paste configuration files and commands
By the end, you’ll have a production-grade template you can roll out to your team in hours, not weeks.
The Pillars of a Seamless AI Dev Environment
- Consistency: same results across laptops, containers, and CI
- Productivity: IDEs wired for instant feedback and automation
- Reproducibility: pinned dependencies, lockfiles, containerized dev and runtime
- Quality: pre-commit hooks, tests, type checking, security scanning
- Observability: logging, metrics, and profiling from dev to prod
- Compliance: secrets management and permissioned data access
Step 0: Decide on Your Stack and Constraints
Answer these up front:
- Languages: Python primarily? Any TypeScript for APIs or tools?
- Hardware: CPU-only, CUDA (NVIDIA), or ROCm (AMD)? Local vs remote GPU?
- OS: macOS/Linux/Windows (with WSL2 for Linux compatibility on Windows)?
- Where will code live? GitHub, GitLab, or Bitbucket? Monorepo or polyrepo?
- Data location: S3/GCS/Azure Blob? On-prem? Any privacy constraints?
Recommended defaults for most teams:
- Python 3.11+ with uv as the Python package and environment manager
- Docker (and Dev Containers) for reproducible dev, plus NVIDIA Container Toolkit if using GPUs
- VS Code for broad team adoption; JetBrains or Neovim supported as alternatives
- DVC for data versioning, MLflow or Weights & Biases for experiment tracking
- GitHub Actions for CI/CD
Step 1: Provision the Base System
- Install a package manager:
- macOS: brew
- Ubuntu/Debian: apt
- Windows: winget or scoop (use WSL2 for a Linux-like setup)
- Install baselines:
- git, curl, unzip, make or just (task runner), Docker Desktop or Docker Engine
- GPU? Install NVIDIA drivers and nvidia-container-toolkit (Linux) or enable GPU support in Docker Desktop (Windows/macOS with supported hardware)
- Install uv (Python toolchain):
curl -LsSf https://astral.sh/uv/install.sh | sh # Then open a new shell; uv is typically installed to ~/.cargo/bin or ~/.local/bin uv --version
Optional global tools with pipx (isolated CLI installations):
brew install pipx # or: python3 -m pip install --user pipx
pipx ensurepath
pipx install pre-commit
pipx install ruff
pipx install mypy
pipx install detect-secrets
Step 2: Create the Project Skeleton
Use Cookiecutter (or your internal template) to standardize structure. Example installation:
pipx install cookiecutter
Run it:
cookiecutter gh:audreyfeldroy/cookiecutter-pypackage
Or scaffold manually:
ai-project/
├─ src/ai_project/
│ ├─ __init__.py
│ ├─ data/
│ ├─ models/
│ ├─ pipelines/
│ └─ cli.py
├─ notebooks/
├─ tests/
├─ .vscode/
├─ .devcontainer/
├─ docker/
├─ data/ # .gitignore or DVC-managed
├─ .gitignore
├─ .pre-commit-config.yaml
├─ pyproject.toml
├─ Makefile
├─ dvc.yaml
├─ mlflow/
└─ README.md
Step 3: Initialize Python with uv (Fast, Modern, Reproducible)
Create and lock your environment in seconds.
- Initialize:
uv init ai-project cd ai-project - Add runtime dependencies (adjust to your stack):
uv add numpy pandas scikit-learn uv add "transformers>=4.43" "torch>=2.4" --extra cpu # GPU example (CUDA-specific wheels may vary by platform): # uv add torch --extra cuda118 - Add dev tooling:
uv add --dev ruff pytest pytest-cov mypy pre-commit ipykernel types-requests - Create a kernel for Jupyter:
uv run python -m ipykernel install --user --name ai-project
Your pyproject.toml will contain unified configuration. Add/adjust:
[project]
name = "ai-project"
version = "0.1.0"
requires-python = ">=3.11"
[tool.ruff]
line-length = 100
select = ["E", "F", "I", "UP", "B"]
ignore = ["E203", "W503"]
[tool.ruff.lint]
extend-select = ["I"]
[tool.mypy]
python_version = "3.11"
ignore_missing_imports = true
strict_optional = true
check_untyped_defs = true
[tool.pytest.ini_options]
addopts = "-q --maxfail=1 --disable-warnings --cov=src --cov-report=term-missing"
testpaths = ["tests"]
Run everything via uv:
- Run a script: uv run python src/ai_project/cli.py
- Sync fresh machine: uv sync
- Add/remove deps: uv add/remove package
Tip: Enforce CPU/GPU parity with separate extras or environment markers, and document which profiles are supported.
Step 4: Wire Up Your IDE for Instant Feedback
VS Code
Recommended extensions:
- Python, Jupyter, Pylance, Ruff, YAML, GitLens, Docker, Remote – Containers
- GitHub Copilot or Codeium for AI-assisted coding (optional)
- Makefile Tools or Task Explorer
.vscode/settings.json:
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests"],
"editor.formatOnSave": true,
"ruff.enable": true,
"ruff.formatting.provider": "ruff",
"notebook.formatOnSave.enabled": true,
"jupyter.jupyterServerType": "local",
"files.exclude": {
"**/__pycache__": true,
"**/.pytest_cache": true,
".venv": true
}
}
.vscode/launch.json (debug a module and tests):
{
"version": "0.2.0",
"configurations": [
{
"name": "Run CLI",
"type": "python",
"request": "launch",
"module": "ai_project.cli",
"justMyCode": true
},
{
"name": "Pytest",
"type": "python",
"request": "launch",
"module": "pytest",
"args": ["-q"],
"justMyCode": true
}
]
}
JetBrains (PyCharm)
- Set Python interpreter to the project’s uv virtualenv or to Docker.
- Enable “Black/Ruff” formatting and “Type Checking” (Mypy or Pyright plugin).
- Configure notebook support and test runner (pytest).
Neovim (for power users)
- Use mason.nvim to install pyright, ruff-lsp.
- Add null-ls for formatting via ruff.
- Use nvim-dap for Python debugging (debugpy) and overseer/telescope for task running.
Step 5: Git Hygiene with Pre-commit and Conventional Commits
Install hooks:
pre-commit install
pre-commit install --hook-type commit-msg
.pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.8
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/psf/black
rev: 24.8.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
hooks:
- id: mypy
additional_dependencies: [types-requests]
- repo: https://github.com/kynan/nbstripout
rev: 0.6.1
hooks:
- id: nbstripout
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
- repo: https://github.com/commitizen-tools/commitizen
rev: v3.28.0
hooks:
- id: commitizen
Enforce conventional commits:
pipx install commitizen
cz init
This enables semantic versioning and automated changelog generation later.
Step 6: Reproducible Dev with Dev Containers and Docker
Devcontainer for VS Code to unify environments:
.devcontainer/devcontainer.json:
{
"name": "AI Dev",
"build": { "dockerfile": "../docker/Dockerfile.dev" },
"features": { "ghcr.io/devcontainers/features/common-utils:2": {} },
"postCreateCommand": "uv sync && pre-commit install",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-toolsai.jupyter",
"charliermarsh.ruff",
"ms-azuretools.vscode-docker"
]
}
},
"remoteUser": "vscode"
}
docker/Dockerfile.dev (CPU example):
FROM python:3.11-slim
RUN apt-get update && apt-get install -y git build-essential curl && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir uv
WORKDIR /workspace
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen
COPY . .
RUN pre-commit install
CMD ["bash"]
GPU variant (Linux) requires the NVIDIA Container Toolkit:
- Install on host: sudo apt-get install -y nvidia-container-toolkit
- Run with: docker run --gpus all ...
Tip: Use a separate Dockerfile for runtime (thin image) vs dev (tools installed).
Step 7: Data and Experiment Management
DVC for data versioning
Initialize DVC and connect a remote (e.g., S3):
pipx install dvc[s3]
dvc init
git commit -m "chore: init dvc"
dvc remote add -d s3remote s3://your-bucket/ai-project
aws configure # or use environment variables
Track large files and models:
git lfs install
git lfs track "*.bin" "*.pt"
echo "data/" >> .gitignore
dvc add data/raw
git add data/raw.dvc .gitignore .gitattributes
git commit -m "data: track raw dataset with dvc"
Define pipelines in dvc.yaml to codify preprocessing/training steps.
Experiment tracking
- MLflow (self-host): spin up quick server with Docker Compose.
- Weights & Biases (hosted): simplest to start.
MLflow quick local:
pipx install mlflow
mlflow ui --backend-store-uri sqlite:///mlflow/mlflow.db --default-artifact-root ./mlruns
Code integration (example):
import mlflow
mlflow.set_experiment("baseline")
with mlflow.start_run():
mlflow.log_params({"lr": 1e-3, "epochs": 10})
# train...
mlflow.log_metrics({"val_acc": 0.91})
mlflow.sklearn.log_model(model, "model")
Step 8: Productive Notebook Workflow
Best practices:
- Always attach your project kernel: ai-project
- Keep notebooks lightweight; move reusable logic to src/ and import it
- Strip outputs before commit (nbstripout hook does this)
- For parameterized runs, use papermill or jupytext
Install:
uv add --dev papermill jupytext
Convert notebook to a Python module with Jupytext pairing:
- Pair notebook to .py: Jupyter command palette -> “Pair Notebook with Percent Script”
- Execute parameterized runs:
papermill notebooks/train.ipynb notebooks/train_out.ipynb -p epochs 10 -p lr 0.001
Step 9: LLM Tooling and Local Services
You’ll likely need to integrate external APIs and/or run local models.
- APIs: Use environment variables for keys, e.g., OPENAI_API_KEY
- Proxy and compatibility: LiteLLM provides a unified OpenAI-compatible gateway
- Local inference: Ollama for quick local LLMs; vLLM for high-throughput; text-generation-inference for production-grade hosting
- Vector DB: Qdrant or Milvus via Docker
Example: Running Qdrant locally with Docker:
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant:latest
Example: Ollama local model:
curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3
ollama run llama3
Simple retrieval chain (Python with LangChain + Qdrant):
uv add langchain qdrant-client openai tiktoken
Example snippet:
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams
client = QdrantClient(host="localhost", port=6333)
COLL = "docs"
try:
client.get_collection(COLL)
except:
client.create_collection(COLL, vectors_config=VectorParams(size=1536, distance=Distance.COSINE))
embed = OpenAIEmbeddings() # Needs OPENAI_API_KEY
vectors = embed.embed_documents(["AI development environments are reproducible...", "Dev containers rock."])
client.upsert(collection_name=COLL, points=[{"id": 1, "vector": vectors[0]}, {"id": 2, "vector": vectors[1]}])
llm = ChatOpenAI(model="gpt-4o-mini")
# Query flow: embed query -> search Qdrant -> send context to LLM...
For prompt evaluation, explore Ragas or DeepEval to score retrieval quality and response correctness in CI.
Step 10: Secrets and Configuration Management
- Use a .env file for local development; never commit it.
- Use direnv to auto-load env vars per project.
- For shared secrets, consider sops with age GPG keys, or your cloud’s secret manager.
Example .env:
OPENAI_API_KEY=...
WANDB_API_KEY=...
MLFLOW_TRACKING_URI=http://localhost:5000
Load automatically with direnv:
brew install direnv
echo 'layout python' > .envrc
echo 'dotenv .env' >> .envrc
direnv allow
For CI, store secrets in your provider’s encrypted store (GitHub Actions Secrets) and inject as environment variables.
Step 11: Testing, Types, and Quality Gates
Create tests/tests_basic.py:
from ai_project.pipelines.train import train_model
def test_train_small_dataset(tmp_path):
model, metrics = train_model(data_dir="tests/data", epochs=1)
assert metrics["val_acc"] > 0.5
Run locally:
uv run pytest
Type check:
uv run mypy src
Coverage:
uv run pytest --cov=src --cov-report=html
Security scanning:
- Static: bandit for Python
- Containers: trivy or grype to scan images
Install and run:
pipx install bandit
bandit -r src
pipx install trivy
trivy image your-registry/ai-project:latest
Step 12: Developer Task Automation
A Makefile or justfile saves your team hundreds of clicks. Makefile example:
PY = uv run python
.PHONY: setup lint test type format data build run clean
setup:
uv sync
pre-commit install
lint:
uv run ruff check .
format:
uv run ruff format .
type:
uv run mypy src
test:
uv run pytest
data:
dvc pull
build:
docker build -f docker/Dockerfile.dev -t ai-dev:latest .
clean:
find . -name "__pycache__" -exec rm -rf {} +
On Windows, prefer justfile or PowerShell scripts for compatibility.
Step 13: CI/CD with GitHub Actions
.github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh && echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Sync deps
run: uv sync --frozen
- name: Lint
run: uv run ruff check .
- name: Type check
run: uv run mypy src
- name: Test
run: uv run pytest
build-image:
runs-on: ubuntu-latest
needs: test
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.dev
push: false
Add separate workflows for release (version bump via Commitizen, publish package, deploy service) and for scanning (trivy).
Step 14: Observability, Logging, and Performance
- Logging: use structured logging with the standard logging module or structlog
- Metrics/tracing: OpenTelemetry to instrument services consistently
- Profiling: scalene or py-spy, line_profiler for hotspots; snakeviz to visualize
Install:
uv add --dev scalene py-spy line-profiler snakeviz
Example structured logging:
import logging, json, sys
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter('%(message)s'))
logger = logging.getLogger("ai")
logger.setLevel(logging.INFO)
logger.addHandler(handler)
def log_event(event: str, **fields):
logger.info(json.dumps({"event": event, **fields}))
Profiling example:
uv run scalene src/ai_project/pipelines/train.py
Add lightweight OpenTelemetry only to service boundaries (API endpoints, inference calls) to avoid training slowdowns.
Step 15: Handling GPUs and Performance Libraries
- Confirm BLAS backend (OpenBLAS/MKL) is installed for numpy/scipy
- Configure PyTorch to use CUDA if present; document version matrix (CUDA version ↔ PyTorch)
- For Docker: base on nvidia/cuda images for GPU builds
- Cache model and dataset artifacts locally (e.g., Hugging Face cache: HF_HOME or HF_DATASETS_CACHE)
Example environment variables:
export HF_HOME=~/.cache/huggingface
export TRANSFORMERS_CACHE=~/.cache/huggingface/transformers
Step 16: Governance and Team Onboarding
- CODEOWNERS for critical paths
- Pull request templates with checklists (tests, docs, data changes)
- Security and data handling guidelines in CONTRIBUTING.md
- Onboarding script to bootstrap a new machine quickly
scripts/bootstrap.sh:
#!/usr/bin/env bash
set -euo pipefail
echo "Installing uv..."
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "Syncing dependencies..."
uv sync
echo "Installing pre-commit hooks..."
pre-commit install
echo "Creating Jupyter kernel..."
uv run python -m ipykernel install --user --name ai-project
Step 17: Optional Enhancements for a Mature Workflow
- Renovate or Dependabot to keep dependencies fresh
- Semantic-release or Commitizen for automated versioning and changelogs
- Task runners like nox or tox for matrix testing
- Feature flags to toggle model variants
- Registry and artifact storage (e.g., GHCR/ECR + S3/GCS) with retention policies
- Template generator: cookiecutter internal template for new projects
- Remote dev: GitHub Codespaces or JetBrains Gateway for heavy workloads
Step 18: End-to-End Example: From Zero to First Experiment
- Clone and bootstrap:
git clone https://github.com/your-org/ai-project.git
cd ai-project
uv sync
pre-commit install
- Set secrets:
cp .env.example .env
# Add OPENAI_API_KEY/WANDB_API_KEY, etc.
- Spin up local services:
docker compose -f docker/compose.dev.yml up -d # qdrant, mlflow, postgres, etc.
- Pull data and run a training pipeline:
dvc pull
uv run python -m ai_project.pipelines.train --epochs 1 --lr 0.001
- Track the run:
- Open MLflow UI at http://localhost:5000 or W&B dashboard
- Inspect metrics and artifacts
- Run tests and lint:
uv run ruff check .
uv run mypy src
uv run pytest
- Build image and run inference locally:
docker build -t ai-project:dev -f docker/Dockerfile.dev .
docker run -p 8080:8080 ai-project:dev
- Open VS Code in Dev Container:
- Command Palette → “Dev Containers: Reopen in Container”
- Debug, test, and notebook inside an identical environment to CI
Troubleshooting Tips
- Mismatched CUDA: align your PyTorch version with your driver and CUDA runtime. Validate with python -c "import torch; print(torch.cuda.is_available())".
- Pre-commit is slow: run pre-commit run --all-files once; subsequent runs are cached. Use ruff for fast lint + format in one.
- Notebook diffs noisy: use jupytext paired scripts or nbstripout hook.
- CI failures due to secrets: use repository actions secrets, never commit .env files.
- Docker file bloat: multi-stage builds and .dockerignore; pin base images to digests for reproducibility.
- Windows path issues: prefer WSL2; keep line endings consistent (.gitattributes).
A First-Week Checklist for Technical Leads
- Day 1: Roll out the repo template, devcontainer, and uv-based environment
- Day 2: Enable pre-commit across the team; add CI workflow and protected branches
- Day 3: Stand up experiment tracking and data versioning (MLflow + DVC)
- Day 4: Add vector DB/Qdrant and minimal retrieval pipeline; wire an LLM provider
- Day 5: Add profiling and OpenTelemetry to your inference service; set up Renovate
- Day 6: Add container scanning (trivy) and bandit; finalize CODEOWNERS and PR templates
- Day 7: Document runbooks and record a 10-minute walkthrough video
Conclusion
Integrating IDEs and CLI tools into a cohesive AI development environment is the difference between friction and flow. With uv for blazing-fast, reproducible Python; pre-commit for quality gates; Dev Containers and Docker for parity; DVC and MLflow for data and experiments; and tight IDE integrations, your team will spend less time wrestling with environments and more time delivering value.
Start with the template above, tailor it to your GPU and cloud reality, and automate everything you can. Your environment should feel invisible—allowing your engineers to iterate quickly, confidently, and collaboratively.