Streamlining Work Repository Management with Raycast
Too Many Repositories
Working in software development means juggling an ever-growing collection of Git repositories. For me, it became overwhelming - I was constantly:
Finding repositories, checking if they were already on my machine, cloning them when needed, and then opening them in VS Code. Each time I switched contexts, I'd repeat this process.
What started as a minor annoyance grew into a significant time sink. I needed a better way to manage my workspace.
Automation to the Rescue
I built a solution around a simple idea: what if one command could handle the entire repository workflow?
My Python script integrated with Raycast now:
- Checks if the repository exists locally
- Clones it automatically when needed
- Opens it directly in VS Code
- Remembers it for next time with a shortcut
The script also maintains the shortcuts automatically - removing ones for deleted repositories and adding new ones as I work with them.
The result is a frictionless workflow where I can instantly access any work repository with just its name.
How It Works
Setting Up the Environment
The script first ensures the necessary directories exist and defines some constants:
# Get the home directory and create the full paths
home_dir = str(pathlib.Path.home())
WORK_REPOS_DIRECTORY = os.path.join(home_dir, "Work-Repos")
RAYCAST_REPO_SCRIPTS_DIRECTORY = os.path.join(home_dir, "Nextcloud/Applications/Raycast/Scripts/repo_shortcuts/work")
# Default settings - hardcoded
DEFAULT_ORGANIZATION = "organization"
GITHUB_DOMAIN = "github.com"
# Ensure both directories exist
os.makedirs(WORK_REPOS_DIRECTORY, exist_ok=True)
os.makedirs(RAYCAST_REPO_SCRIPTS_DIRECTORY, exist_ok=True)
Repository Management Logic
The main function handles checking for the repository, cloning it if needed, and opening it in VS Code:
def main():
# Check if repo name was provided
if len(sys.argv) < 2:
print("Please provide a repository name.")
sys.exit(1)
repo_name = sys.argv[1]
# Check if organization was provided as second argument
organization = DEFAULT_ORGANIZATION
if len(sys.argv) > 2 and sys.argv[2]:
organization = sys.argv[2]
print(f"Using specified organization: {organization}")
repo_path = os.path.join(WORK_REPOS_DIRECTORY, repo_name)
# Check if directory exists
if not os.path.isdir(repo_path):
print(f"Repository not found, cloning from {organization}...")
try:
clone_url = f"git@{GITHUB_DOMAIN}:{organization}/{repo_name}.git"
subprocess.run(["git", "-C", WORK_REPOS_DIRECTORY, "clone", clone_url], check=True)
print(f"Cloning complete from {organization}.")
except subprocess.CalledProcessError:
print(f"{repo_name} could not be cloned from {organization}.")
sys.exit(1)
The script allows specifying an organization as an optional parameter, which overrides the default. For repositories that already exist locally, it detects the organization from the remote URL:
def get_repo_organization(repo_path):
"""Get the organization from a repository's remote URL"""
try:
result = subprocess.run(
["git", "-C", repo_path, "remote", "get-url", "origin"],
capture_output=True,
text=True,
check=True
)
remote_url = result.stdout.strip()
# Parse organization from URL (handles SSH and HTTPS URLs)
if ":" in remote_url:
# SSH format: git@github.com:organization/repo.git
parts = remote_url.split(":")
if len(parts) > 1:
org_repo = parts[1].split("/")
if len(org_repo) > 0:
return org_repo[0].replace(".git", "")
# ... more parsing logic
Generating Raycast Shortcuts
For each repository, the script creates a Raycast shortcut that includes the organization name:
def generate_script(repo_name, organization):
"""
Generate a Raycast script to open a specific repository
"""
script_path = os.path.join(RAYCAST_REPO_SCRIPTS_DIRECTORY, f"open-{repo_name}.sh")
script_content = f"""#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Open {repo_name} in VS Code
# @raycast.mode silent
# Optional parameters:
# @raycast.icon 📂
# @raycast.packageName vs {repo_name}
# Documentation:
# @raycast.description Opens the {repo_name} repository ({organization}) in VS Code
# ... more script content
Keeping Everything in Sync
The script includes a function to prune shortcuts for repositories that no longer exist:
def update_scripts():
"""Update all scripts and prune those for repos that no longer exist"""
print("Updating Raycast scripts...")
# Keep track of valid repos using a set
valid_repos = set()
# Find all repos in the WORK_REPOS_DIRECTORY
for item in os.listdir(WORK_REPOS_DIRECTORY):
repo_dir = os.path.join(WORK_REPOS_DIRECTORY, item)
if os.path.isdir(repo_dir) and os.path.isdir(os.path.join(repo_dir, ".git")):
repo_name = os.path.basename(repo_dir)
valid_repos.add(repo_name)
# Get the organization from the repo
organization = get_repo_organization(repo_dir) or DEFAULT_ORGANIZATION
# Prune scripts for repos that no longer exist
for script_path in glob.glob(os.path.join(RAYCAST_REPO_SCRIPTS_DIRECTORY, "open-*.sh")):
if os.path.isfile(script_path):
script_basename = os.path.basename(script_path)
script_repo_name = script_basename.replace("open-", "").replace(".sh", "")
if script_repo_name not in valid_repos:
print(f"Removing script for deleted repo: {script_repo_name}")
os.remove(script_path)
Setting It Up with Raycast
The script itself is set up as a Raycast command that accepts two arguments:
@raycast.title Open Work Repo
@raycast.argument1 { "type": "text", "placeholder": "Repository Name" }
@raycast.argument2 { "type": "text", "placeholder": "Organization (default: organization)", "optional": true }
This allows me to:
- Press Alt+Space to open Raycast
- Type "open work repo"
- Enter the repository name
- Optionally specify an organization (or use the default)
- Press Enter
The script handles everything else. For repositories I access frequently, dedicated shortcuts are created that I can access directly by typing the repository name.
Results
This approach has saved me countless hours managing repositories. The benefits include:
- Simplicity: One command to handle the entire workflow
- Speed: Instant access to any repository I've worked with before
- Flexibility: Easy to work with repositories from different organizations
- Discoverability: Repository shortcuts appear in Raycast search results
- Organization: All work repositories are in a dedicated directory
- Cleanliness: Shortcuts for deleted repositories are automatically pruned
Future Improvements
I'm considering a few enhancements for this system:
- Add support for different Git hosting services beyond GitHub
- Include branch information in the shortcuts
- Add status indicators to show which repositories have uncommitted changes
- Integrate with project-specific tooling or environments
- Create a companion script to batch update all repositories
Full script
The full script is available below. You can customize the paths and settings to fit your own environment.
#!/usr/bin/env python3
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Open Work Repo
# @raycast.mode silent
# Optional parameters:
# @raycast.icon 🤖
# @raycast.argument1 { "type": "text", "placeholder": "Repository Name" }
# @raycast.argument2 { "type": "text", "placeholder": "Organization (default: organization)", "optional": true }
# @raycast.packageName wr
# Documentation:
# @raycast.description Opens or clones a Work Repo
import os
import sys
import pathlib
import stat
import subprocess
import glob
# Get the home directory and create the full paths
home_dir = str(pathlib.Path.home())
WORK_REPOS_DIRECTORY = os.path.join(home_dir, "Work-Repos")
RAYCAST_REPO_SCRIPTS_DIRECTORY = os.path.join(home_dir, "Nextcloud/Applications/Raycast/Scripts/repo_shortcuts/work")
DEFAULT_ORGANIZATION = "organization"
# Ensure both directories exist
os.makedirs(WORK_REPOS_DIRECTORY, exist_ok=True)
os.makedirs(RAYCAST_REPO_SCRIPTS_DIRECTORY, exist_ok=True)
def generate_script(repo_name, organization):
"""
Generate a Raycast script to open a specific repository
Args:
repo_name (str): Repository name
organization (str): GitHub organization name
"""
script_path = os.path.join(RAYCAST_REPO_SCRIPTS_DIRECTORY, f"open-{repo_name}.sh")
script_content = f"""#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Open {repo_name} in VS Code
# @raycast.mode silent
# Optional parameters:
# @raycast.icon 📂
# @raycast.packageName vs {repo_name}
# Documentation:
# @raycast.description Opens the {repo_name} repository ({organization}) in VS Code
WORK_REPOS_DIRECTORY=~/Work-Repos
RAYCAST_REPO_SCRIPTS_DIRECTORY=~/Nextcloud/Applications/Raycast/Scripts/Repos
# Function to update all scripts
update_scripts() {{
# Create a temporary file to keep track of valid repos
local temp_file=$(mktemp)
# Find all repos in the WORK_REPOS_DIRECTORY
for repo_dir in "$WORK_REPOS_DIRECTORY"/*; do
if [ -d "$repo_dir" ] && [ -d "$repo_dir/.git" ]; then
local repo_name=$(basename "$repo_dir")
echo "$repo_name" >> "$temp_file"
fi
done
# Prune scripts for repos that no longer exist
for script in "$RAYCAST_REPO_SCRIPTS_DIRECTORY"/open-*.sh; do
if [ -f "$script" ]; then
local script_repo_name=$(basename "$script" | sed 's/^open-//;s/\.sh$//')
if ! grep -q "^$script_repo_name$" "$temp_file"; then
rm "$script"
fi
fi
done
rm "$temp_file"
}}
# Check if directory exists before opening
if [ ! -d "$WORK_REPOS_DIRECTORY/{repo_name}" ]; then
echo "Repository {repo_name} not found."
exit 1
fi
# Update scripts to remove any that no longer exist
update_scripts
# Open the repository in VS Code
code -n "$WORK_REPOS_DIRECTORY/{repo_name}"
"""
# Write the script file
with open(script_path, 'w') as f:
f.write(script_content)
# Make the script executable (chmod +x)
current_permissions = os.stat(script_path).st_mode
os.chmod(script_path, current_permissions | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
print(f"Created script for {repo_name} ({organization})")
def update_scripts():
"""Update all scripts and prune those for repos that no longer exist"""
print("Updating Raycast scripts...")
# Keep track of valid repos using a set
valid_repos = set()
# Find all repos in the WORK_REPOS_DIRECTORY
for item in os.listdir(WORK_REPOS_DIRECTORY):
repo_dir = os.path.join(WORK_REPOS_DIRECTORY, item)
if os.path.isdir(repo_dir) and os.path.isdir(os.path.join(repo_dir, ".git")):
repo_name = os.path.basename(repo_dir)
valid_repos.add(repo_name)
# Get the organization from the repo
organization = get_repo_organization(repo_dir) or DEFAULT_ORGANIZATION
# Generate script if it doesn't exist
script_path = os.path.join(RAYCAST_REPO_SCRIPTS_DIRECTORY, f"open-{repo_name}.sh")
if not os.path.exists(script_path):
generate_script(repo_name, organization)
# Prune scripts for repos that no longer exist
for script_path in glob.glob(os.path.join(RAYCAST_REPO_SCRIPTS_DIRECTORY, "open-*.sh")):
if os.path.isfile(script_path):
script_basename = os.path.basename(script_path)
script_repo_name = script_basename.replace("open-", "").replace(".sh", "")
if script_repo_name not in valid_repos:
print(f"Removing script for deleted repo: {script_repo_name}")
os.remove(script_path)
print("Scripts updated successfully.")
def get_repo_organization(repo_path):
"""Get the organization from a repository's remote URL"""
try:
result = subprocess.run(
["git", "-C", repo_path, "remote", "get-url", "origin"],
capture_output=True,
text=True,
check=True
)
remote_url = result.stdout.strip()
# Parse organization from URL (handles SSH and HTTPS URLs)
if ":" in remote_url:
# SSH format: git@github.com:organization/repo.git
parts = remote_url.split(":")
if len(parts) > 1:
org_repo = parts[1].split("/")
if len(org_repo) > 0:
return org_repo[0].replace(".git", "")
elif "/" in remote_url:
# HTTPS format: https://github.com/organization/repo.git
parts = remote_url.split("/")
for i, part in enumerate(parts):
if part in ["github.com", "gitlab.com", "bitbucket.org"] and i + 1 < len(parts):
return parts[i + 1]
except Exception:
pass
return None
def main():
# Check if repo name was provided
if len(sys.argv) < 2:
print("Please provide a repository name.")
sys.exit(1)
repo_name = sys.argv[1]
# Check if organization was provided as second argument
organization = DEFAULT_ORGANIZATION
if len(sys.argv) > 2 and sys.argv[2]:
organization = sys.argv[2]
print(f"Using specified organization: {organization}")
repo_path = os.path.join(WORK_REPOS_DIRECTORY, repo_name)
# Check if directory exists
if not os.path.isdir(repo_path):
print(f"Repository not found, cloning from {organization}...")
try:
clone_url = f"git@github.com:{organization}/{repo_name}.git"
subprocess.run(["git", "-C", WORK_REPOS_DIRECTORY, "clone", clone_url], check=True)
print(f"Cloning complete from {organization}.")
except subprocess.CalledProcessError:
print(f"{repo_name} could not be cloned from {organization}.")
sys.exit(1)
else:
# Get the actual organization from the repo if it exists
existing_org = get_repo_organization(repo_path)
if existing_org:
organization = existing_org
print(f"Using existing repository's organization: {organization}")
# Open the repository in VS Code
subprocess.run(["code", "-n", repo_path])
# Generate script for this specific repo
generate_script(repo_name, organization)
# Update all scripts (including pruning)
update_scripts()
if __name__ == "__main__":
main()