March 13, 2025

How I’ve Set Up My Local Python + LLM Stack for Content & Automation

This isn’t a how-to. This is just how I roll. My dev environment isn't a tutorial—it’s an extension of my brain. Built for speed, isolation, and sanity. Here's the exact way I structure and boot up my stack when I'm in flow, writing automation for content, SEO audits, or scraping SERP data for LangChain.

Why I Don’t Globally Install Python Stuff

Globally installing Python packages like Pandas or LangChain? That’s just begging for dependency hell. I use isolated virtual environments (venv) for each project type: notebooks, checkers, cron jobs, etc. This keeps every tool in its lane and avoids package collisions.

Folder Structure

Everything sits under ~/Documents/projects. Inside that:

  • notebooks: JupyterLab + LLM prototyping
  • checkers: health audits, crawl/indexation analysis
  • scripts: cron-ready automation (GSC, GSheet, scraping)
  • jl: the virtual environment (venv) with all dependencies

The `.zprofile`: My On/Off Switch

Here’s the magic that makes my terminal spin up the whole setup in one command. It's all inside ~/.zprofile.

# Set up Python 3.13 PATH
export PATH="/Library/Frameworks/Python.framework/Versions/3.13/bin:$PATH"
export PATH="$HOME/Library/Python/3.13/bin:$PATH"

# Alias python/pip to Python 3
alias python="python3"
alias pip="pip3"

# Set default working directory
cd ~/Documents/projects

# Load Homebrew (for things like fzf)
eval "$(/opt/homebrew/bin/brew shellenv)"

# Alias to launch JupyterLab from selected folder using fzf
alias jlon="jupyter_lab_launch"

# Alias to kill JupyterLab and deactivate the virtual environment
alias jloff='deactivate 2>/dev/null; pkill -f jupyter-lab'

# Function that powers 'jlon'
jupyter_lab_launch() {
  source ~/Documents/projects/jl/bin/activate

  # Define selectable folders
  folders=(notebooks scripts checkers cron)

  # Folder picker using fzf
  selected=$(printf "%s\n" "${folders[@]}" | fzf --prompt="📁 Choose folder: ") || selected="notebooks"

  cd "$HOME/Documents/projects/$selected"

  # Launch JupyterLab in background on port 8888
  nohup jupyter lab --no-browser --port=8888 > /dev/null 2>&1 &

  # Open the lab manually since '--browser' is deprecated
  sleep 2 && open "http://localhost:8888/lab"
}

What Happens When I Type jlon

- I get a folder picker (fzf UI)
- I pick notebooks, scripts, or any other folder
- It activates my venv
- It launches JupyterLab in the background
- It auto-opens in the browser
- My terminal stays free. I can keep working.

To Kill Everything Cleanly: jloff

When I’m done, I just type jloff. That safely:

  • Deactivates the virtual environment
  • Kills the background JupyterLab instance

What’s in My LLM Stack

The venv (~/Documents/projects/jl) includes everything I need for scraping, prompting, generating content, and automating CMS pushes:

  • langchain
  • chromadb
  • openai
  • google-api-python-client
  • pandas, requests, bs4, etc.

This gives me a clean environment to run prompt chains, parse Google Search Console exports, convert scraped content into Strapi-ready HTML, and run evaluations—all without polluting global Python.

No More Friction

This setup is fast, clean, and aligned with how I work across multiple content systems. It’s not for everyone—but it makes my stack predictable, self-contained, and always ready to execute.

If you’re constantly juggling LLM workflows, SEO automations, or anything Python-heavy for marketing ops—go modular. Build once, switch on, go.

Dan.marketing is the personal website of Daniel (Dan) Antony, a digital marketer passionate about business and technology
© Copyright 2025 - All Rights Reserved
envelopephone-handsetmap-marker
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram