Skip to content

vocino/dotfiles

Repository files navigation

Dotfiles

Cross-platform development environment configuration for Windows 11 Pro and MacOS.

This repository uses symlinks to keep configuration files in version control while maintaining their expected locations in your system. Changes made to configs in this repo automatically reflect in your system, and vice versa.

Prerequisites

Windows

Ensure your PowerShell execution policy allows scripts:

# Check current policy
Get-ExecutionPolicy

# If needed, allow local scripts to run (requires Administrator)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Note: The installer may require Administrator privileges for certain paths (like Windows Terminal settings). You'll be prompted if elevation is needed.

macOS

Install Homebrew if not already present:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Structure

dotfiles/
├── cursor/              # Cursor IDE configuration (shared)
│   ├── mcp.json         # MCP server definitions
│   ├── settings.json    # Cursor settings
│   ├── keybindings.json # Custom keyboard shortcuts
│   ├── cli-config.json  # Cursor CLI configuration (agent modes, permissions)
│   ├── snippets/        # Custom code snippets (if used)
│   └── rules/           # Global cursor rules
├── claude/              # Claude Code global settings (shared)
│   └── settings.json    # Model, plugins, and permission rules
├── vscode/              # VS Code configuration (shared)
│   ├── settings.json    # VS Code settings
│   ├── keybindings.json # Custom keyboard shortcuts
│   └── snippets/        # Custom code snippets (if used)
├── shell/               # Shared shell config (sourced by bash/zsh)
│   └── common.sh        # Aliases, functions, secrets loading
├── git/                 # Git configuration (shared)
│   ├── .gitconfig
│   ├── .gitignore_global
│   └── hooks/           # Global git hooks
├── npm/                 # npm configuration (shared)
│   └── .npmrc
├── starship/            # Starship cross-shell prompt (shared)
│   └── starship.toml    # Catppuccin Mocha powerline preset
├── zsh/                 # Zsh profile (macOS)
│   └── .zshrc           # Sources shell/common.sh, adds zsh config
├── macos/               # macOS-specific
│   └── Brewfile         # Homebrew packages
├── powershell/          # PowerShell profile (Windows)
│   └── profile.ps1
├── git-bash/            # Git Bash profile (Windows, Cursor terminal)
│   ├── .bashrc          # Sources shell/common.sh, adds bash config
│   ├── .bash_profile    # Login shell: sources .bashrc
│   └── .inputrc         # Readline settings
├── windows-terminal/    # Windows Terminal settings (Windows)
│   └── settings.json
├── winget/              # WinGet package manager (Windows)
│   ├── settings.json    # WinGet behavior settings
│   └── packages.json    # Curated list of dev tools & apps
├── wsl/                 # WSL-specific configs (if used)
│   └── .bashrc
├── scripts/             # Installation and utility scripts
│   ├── install.ps1      # Windows symlink installer
│   ├── install.sh       # macOS/Linux symlink installer
│   ├── sync-secrets.ps1 # Sync secrets to Windows user environment
│   └── winget-packages.ps1 # Import/export WinGet packages
├── secrets/             # Local secrets (git-ignored)
│   ├── .env.cloudflare.example  # Cloudflare API template
│   ├── .env.github.example      # GitHub token template
│   └── .env.*           # Your actual secrets (not in git)
└── .cursorrules         # Rules for editing THIS repo

Quick Start

Windows

# Clone the repo
git clone https://github.com/vocino/dotfiles.git ~/dotfiles

# Run the installer
cd ~/dotfiles
.\scripts\install.ps1

From Git Bash you can run the installer with:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File ~/dotfiles/scripts/install.ps1

macOS

# Clone the repo
git clone https://github.com/vocino/dotfiles.git ~/dotfiles

# Run the installer
cd ~/dotfiles
./scripts/install.sh

# Install Homebrew packages
brew bundle --file=~/dotfiles/macos/Brewfile

The installer will:

  1. Create symbolic links from system paths to files in this repo
  2. Ask for confirmation before overwriting existing files (unless using -Force)

What Gets Configured

Both Platforms

  • Cursor IDE: Settings, MCP servers, keybindings, CLI config, snippets, global rules
  • VS Code: Settings, keybindings, snippets
  • Claude Code: Global settings with generous permissions for autonomous hobby development
  • Starship: Cross-shell prompt with Catppuccin Mocha powerline preset
  • Git: Global config, aliases, ignore patterns, hooks
  • npm: Global npm configuration
  • Secrets Management: Service-organized dotenv files with automatic shell loading
  • Shell aliases: Shared git/npm shortcuts via shell/common.sh (gst, gco, gaa, gcm, gp, gl, nr, ni, etc.)

Windows Only

  • Git Bash: Shell profile sourcing shared config + Starship. Used by Cursor's integrated terminal.
  • PowerShell: Custom profile with aliases, functions, secrets loading, Starship prompt
  • Windows Terminal: Settings with Catppuccin Mocha theme
  • WinGet: Package manager settings and curated package list

macOS Only

  • Zsh: Shell profile sourcing shared config + Starship + zsh-specific settings
  • Homebrew: Brewfile with curated package list

MCP Servers (Cursor)

Cursor reads MCP config from cursor/mcp.json (symlinked to %USERPROFILE%\.cursor\mcp.json). This repo configures:

Server Type Purpose
openai-docs HTTP Read-only OpenAI developer docs (API, SDK, etc.) — docs
fetch stdio (npx) Fetch URLs and extract content as markdown for LLM context
filesystem stdio (npx) Read/write files under a configurable directory
Cloudflare HTTP Access Cloudflare APIs and services
github HTTP Access GitHub APIs (requires GITHUB_MCP_TOKEN)

Customize: Edit cursor/mcp.json. For filesystem, set the args path to your allowed directory (e.g. C:\Users\YourName or a project root). Use double backslashes in JSON.

Tokens: MCP servers that require authentication use environment variables (e.g., ${GITHUB_MCP_TOKEN}). Add tokens to secrets/.env.github or other service files, run .\scripts\sync-secrets.ps1, then restart Cursor.

More servers: MCP Registry, modelcontextprotocol/servers (Git, Brave Search, etc.). Use url for HTTP servers, command/args for stdio. Restart Cursor after changes.

Theming

All applications are configured to use Catppuccin Mocha where available. Catppuccin is a community-driven pastel theme available for 400+ applications, providing a consistent, warm color scheme across the entire development environment.

Shell prompts use Starship with the Catppuccin powerline preset for a unified cross-shell experience (Git Bash, PowerShell, and Zsh).

Prerequisites: Install the Catppuccin theme extension (Catppuccin.catppuccin-vsc) in Cursor and VS Code. Install Starship via winget install --id Starship.Starship (Windows) or brew install starship (macOS).

Installation Options

Windows

# Full install (all configs)
.\scripts\install.ps1

# Selective install (only specific configs)
.\scripts\install.ps1 -Only cursor,git

# Force mode (overwrites existing files without prompting)
.\scripts\install.ps1 -Force

Selective Install: Use -Only to install specific configs. Available options: vscode, cursor, claude, powershell, git-bash, git, npm, windows-terminal, winget, starship, wsl.

macOS

# Full install (all configs)
./scripts/install.sh

# Selective install (only specific configs)
./scripts/install.sh --only cursor,git

# Force mode (overwrites existing files without prompting)
./scripts/install.sh --force

Selective Install: Use --only to install specific configs. Available options: git, npm, starship, claude, shell, cursor, vscode, zsh.

WinGet Packages

The winget/packages.json file contains a curated list of dev tools and apps. Use the helper script to manage packages:

# Install all packages from the curated list (skips already installed)
.\scripts\winget-packages.ps1 import

# Re-export current packages (overwrites packages.json - review afterward)
.\scripts\winget-packages.ps1 export

Updating

After making changes to config files in this repo:

# Symlinks automatically reflect changes - no reinstall needed!
# The repo files are already linked, so edits appear immediately

# However, if you need to re-link (e.g., after structure changes):
.\scripts\install.ps1 -Force

Since configs are symlinked, edits in either location (repo or system) are immediately reflected in both. No reinstall needed for content changes.

Secrets (.env)

This repository includes a secure secrets management system that keeps tokens and API keys out of version control while making them available to your development tools and applications.

Organization

Secrets are organized by service using separate .env.* files in the secrets/ directory:

  • Service-based organization: Each service gets its own file (e.g., .env.cloudflare, .env.github, .env.aws)
  • Related credentials together: All credentials for a service are kept in one place
  • Easy to manage: Add or remove services without affecting others
  • Git-ignored: All .env.* files (except .example templates) are ignored by git

Setup

  1. Copy example files to create your local secret files:

    Copy-Item secrets\.env.cloudflare.example secrets\.env.cloudflare
    Copy-Item secrets\.env.github.example secrets\.env.github
  2. Add your actual values to the .env.* files:

    # Edit with your preferred editor
    code secrets\.env.cloudflare
    code secrets\.env.github
    # or
    notepad secrets\.env.cloudflare
    notepad secrets\.env.github
  3. Format: Each file uses standard dotenv format:

    # Example: secrets/.env.cloudflare
    CLOUDFLARE_ACCOUNT_ID=your_actual_account_id
    CLOUDFLARE_API_TOKEN=your_actual_token
    
    # Example: secrets/.env.github
    GITHUB_TOKEN=your_github_token_here
    GITHUB_MCP_TOKEN=your_github_mcp_token_here
    

How Secrets Are Loaded

PowerShell Shell Sessions

The PowerShell profile automatically loads all .env.* files from secrets/ on every shell startup. This means:

  • CLI tools (git, npm, wrangler, etc.) launched from PowerShell have access
  • Terminal-based workflows automatically get the environment variables
  • No manual loading required - it happens automatically

Git Bash / Zsh Shell Sessions

The shared shell config (shell/common.sh) sources and exports all secrets/.env.* files (excluding .example) on every shell startup. Both Git Bash (Windows) and Zsh (macOS) source this file, so:

  • CLI tools and terminal sessions automatically get environment variables
  • No manual loading required - it happens when you open a new terminal
  • GUI applications on Windows still need secrets in the Windows user environment; use sync-secrets.ps1 and restart the app

GUI Applications (Cursor, VS Code, etc.)

GUI applications need secrets in the Windows user environment variables. Use the sync script:

# Preview what will be synced (dry run)
.\scripts\sync-secrets.ps1 -WhatIf

# Actually sync secrets to Windows user environment
.\scripts\sync-secrets.ps1

Important: After syncing, restart the application (e.g., Cursor) to pick up the new environment variables.

Using Secrets in Cursor

Cursor can access secrets in several ways:

  1. Environment Variables (recommended for GUI):

    • Run .\scripts\sync-secrets.ps1 to sync secrets to Windows user env
    • Restart Cursor
    • Cursor's terminal, agents, and code can now access $env:CLOUDFLARE_API_TOKEN, etc.
  2. Terminal Commands in Cursor:

    • Cursor's default terminal is Git Bash. The Git Bash profile loads secrets automatically on each new terminal.
    • If you launch Cursor from PowerShell (e.g., cursor .), it inherits the shell's environment; the PowerShell profile loads secrets there too.
  3. Agent Operations:

    • When Cursor agents run terminal commands, they use the environment variables
    • Commands like curl with API tokens work seamlessly

Example: Using Cloudflare API token in Cursor:

# In Cursor's terminal or agent commands:
curl "https://api.cloudflare.com/client/v4/accounts/$env:CLOUDFLARE_ACCOUNT_ID/tokens/verify" `
  -H "Authorization: Bearer $env:CLOUDFLARE_API_TOKEN"

Adding New Services

To add secrets for a new service:

  1. Create an example file:

    # Create secrets\.env.newservice.example
    @"
    # NewService API Configuration
    NEWSERVICE_API_KEY=your_api_key_here
    NEWSERVICE_SECRET=your_secret_here
    "@ | Out-File -FilePath secrets\.env.newservice.example -Encoding utf8
  2. Copy and fill in values:

    Copy-Item secrets\.env.newservice.example secrets\.env.newservice
    # Edit secrets\.env.newservice with your actual values
  3. Add to sync allowlist (if you want it synced to Windows user env):

    # Edit scripts\sync-secrets.ps1
    # Add "NEWSERVICE_API_KEY", "NEWSERVICE_SECRET" to the $AllowList array
  4. The PowerShell and Git Bash profiles automatically load it - no changes needed!

Managing Secrets

  • Update a secret: Edit the appropriate .env.* file, then run .\scripts\sync-secrets.ps1 if it's synced to user env
  • Add a new service: Create .env.servicename file - it's automatically loaded
  • Remove a service: Delete the .env.* file and remove from sync allowlist if needed
  • View loaded secrets: In PowerShell, run Get-ChildItem Env: | Where-Object { $_.Name -like "*CLOUDFLARE*" -or $_.Name -like "*GITHUB*" }

Security Notes

  • ✅ All .env.* files are git-ignored (never committed)
  • ✅ Only .example template files are tracked in git
  • ✅ Secrets are stored locally on your machine
  • ✅ Sync script only writes to Windows user environment (not system-wide)
  • ⚠️ Keep your secrets/ directory secure and don't share it
  • ⚠️ Rotate tokens if they're ever exposed or shared

Adding New Configs

  1. Add the config file to the appropriate directory
  2. Update scripts/install.ps1 (Windows) and/or scripts/install.sh (macOS) with the symlink mapping
  3. For new shell aliases/functions, add to shell/common.sh (shared) rather than individual profiles
  4. Document in this README (structure, What Gets Configured, Key Paths Reference, and any secrets/verification steps)

Verification

After installation, verify symlinks were created correctly:

# Check if files are symlinks (returns True if symlink, False if regular file)
(Get-Item $env:USERPROFILE\.gitconfig).LinkType -eq 'SymbolicLink'
(Get-Item $env:APPDATA\Cursor\User\settings.json).LinkType -eq 'SymbolicLink'

# View symlink targets
Get-Item $env:USERPROFILE\.gitconfig | Select-Object LinkType, Target

Quick Checklist:

  • Symlinks created (check with commands above)
  • Cursor IDE settings load correctly
  • PowerShell profile loads on new session (pwsh)
  • Git config is active (git config --list --show-origin)
  • Windows Terminal uses new settings (if installed)

Design Decisions

Cross-platform shells: Shared aliases, functions, and secrets loading live in shell/common.sh, sourced by both git-bash/.bashrc (Windows) and zsh/.zshrc (macOS). PowerShell has its own implementation. On Windows, Cursor's default terminal is Git Bash.

Dual installers: scripts/install.ps1 (Windows) and scripts/install.sh (macOS) are separate scripts with platform-idiomatic implementations. Both follow the same pattern: define symlink mappings, create links, handle conflicts.

Why Symlinks?

  • Single source of truth: configs live in this repo
  • Automatic sync: changes in repo or system reflect immediately
  • Easy updates: edit once, works everywhere
  • Version controlled: all config changes are tracked in git

What Happens to Existing Files?

  • If a file already exists and isn't a symlink, you'll be prompted (unless using -Force)
  • You can always restore previous versions from git history if needed

Administrator Requirements

  • Some paths (like Windows Terminal) require admin privileges to create symlinks
  • The installer will request elevation only when needed
  • Most user profile paths don't require admin

Platform-Specific Notes

Windows

  • Some system paths require Administrator privileges (installer handles this)
  • Paths use PowerShell environment variables: $env:APPDATA, $env:USERPROFILE, $env:LOCALAPPDATA
  • GUI apps need secrets synced via sync-secrets.ps1

macOS

  • All symlinks are created in user space (no sudo required)
  • Paths use $HOME and ~/Library/Application Support/
  • GUI apps pick up environment from shell profile (launchctl may be needed for some cases)

Key Paths Reference

Windows

Config Path
Cursor Settings %APPDATA%\Cursor\User\settings.json
Cursor Keybindings %APPDATA%\Cursor\User\keybindings.json
Cursor MCP %USERPROFILE%\.cursor\mcp.json
Cursor CLI Config %USERPROFILE%\.cursor\cli-config.json
Cursor Snippets %APPDATA%\Cursor\User\snippets\
Claude Code Settings %USERPROFILE%\.claude\settings.json
VS Code Settings %APPDATA%\Code\User\settings.json
VS Code Keybindings %APPDATA%\Code\User\keybindings.json
VS Code Snippets %APPDATA%\Code\User\snippets\
PowerShell Profile %USERPROFILE%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Git Bash rc %USERPROFILE%\.bashrc
Git Config %USERPROFILE%\.gitconfig
npm Config %USERPROFILE%\.npmrc
Starship Config %USERPROFILE%\.config\starship.toml
Windows Terminal %LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json
WinGet Settings %LOCALAPPDATA%\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\settings.json

macOS

Config Path
Cursor Settings ~/Library/Application Support/Cursor/User/settings.json
Cursor Keybindings ~/Library/Application Support/Cursor/User/keybindings.json
Cursor MCP ~/.cursor/mcp.json
Cursor CLI Config ~/.cursor/cli-config.json
Claude Code Settings ~/.claude/settings.json
VS Code Settings ~/Library/Application Support/Code/User/settings.json
VS Code Keybindings ~/Library/Application Support/Code/User/keybindings.json
Zsh Profile ~/.zshrc
Git Config ~/.gitconfig
npm Config ~/.npmrc
Starship Config ~/.config/starship.toml

Note: These paths are where symlinks are created. The actual config files remain in this repository.

About

AI-first personal development environment dotfiles for my Windows and MacOS machines.

Resources

Stars

Watchers

Forks

Contributors