Run Python Script in venv via Alfred

A shell script triggered by the Alfred keyword rp that reads a Python file path from the clipboard, detects its project venv, and runs it in a new Terminal window with the correct virtual environment activated.

Overview

This script bridges Alfred and Terminal to quickly run any Python file in its project's virtual environment. The workflow is:

  1. Copy a .py file path to the clipboard (e.g. from Finder or a file manager)
  2. Trigger Alfred with the rp keyword
  3. A new Terminal window opens, activates the correct venv, and runs the script

How it works

Clipboard input

The script reads the file path from pbpaste rather than taking a positional argument, which makes it convenient for Alfred integration — just copy the path and fire the keyword.

Project detection

The sed expression extracts the project root by matching the pattern:

/Users/<user>/Python/<project>/...

This assumes all Python projects live under ~/Python/ with one level of nesting. The venv is then expected at <project>/venv/bin/activate.

Execution

An osascript block tells Terminal.app to open a new window and run:

source '<venv>/bin/activate' && python3 '<file>'

This keeps the Terminal window open after execution so you can see output or errors.

The script

#!/bin/bash
FILE=$(pbpaste)
if [ -z "$FILE" ]; then
  echo "Usage: $0 /path/to/project/script.py"
  exit 1
fi
PROJECT=$(echo "$FILE" | sed 's|\(/Users/[^/]*/Python/[^/]*\)/.*|\1|')
VENV="$PROJECT/venv/bin/activate"
if [ ! -f "$VENV" ]; then
  echo "Error: venv not found at $VENV"
  exit 1
fi
osascript <<EOF
tell application "Terminal"
  activate
  do script "source '$VENV' && python3 '$FILE'"
end tell
EOF

Limitations and possible improvements

Area Current behaviour Possible improvement
Project root Hardcoded to ~/Python/<project>/ structure Walk up directories looking for venv/ or .venv/
Venv folder name Expects venv/ Also check .venv/, env/, or read from pyproject.toml
Terminal emulator Uses Terminal.app via osascript Support iTerm2 or kitty via a flag
Input method Clipboard only Accept a positional argument as fallback
Error feedback echo to stdout (invisible in Alfred) Use osascript dialog or Alfred notification

links

social