Skip to content

yulonglin/dotfiles

Repository files navigation

dotfiles

Highly opinionated development environment for AI safety research. ZSH, Tmux, Vim, SSH, and AI coding assistants across macOS, Linux, and cloud containers.

This setup reflects workflows optimized for ML research: reproducibility, experiment tracking, async API patterns, and rigorous methodology. The AI assistant configurations enforce research discipline—interview before planning, plan before implementing, skepticism of surprisingly good results.

Key highlights:

  • 🤖 AI Coding Assistants - Extensively configured Claude Code, plus Codex CLI and Gemini CLI support
  • 👻 Ghostty - Fast, GPU-accelerated terminal with sensible defaults
  • 📊 htop - Dynamic CPU meter configuration that adapts to your core count
  • 🦀 Rust-powered CLI tools - Modern, blazing-fast replacements for standard Unix utilities
  • 🧹 Automatic cleanup - Scheduled cleanup of Downloads/Screenshots (macOS, moves to trash)

Originally forked from jplhughes/dotfiles - thanks John for the solid foundation!

Quickstart

This project offers two quickstart paths: Local and Cloud.


Local Quickstart

For setting up on your personal machine (macOS, Linux, desktop/laptop):

git clone https://github.com/yulonglin/dotfiles.git && cd dotfiles

# 1. Install dependencies (zsh, tmux, CLI tools, AI assistants)
./install.sh

# 2. Deploy configurations (symlinks, shell config, secrets, automation)
./deploy.sh

# 3. Restart your shell
source ~/.zshrc
  • install.sh installs required software.
  • deploy.sh deploys config files and settings.
  • Both scripts are idempotent and safe to re-run.

All configuration options are stored in config.sh. Flags are additive (e.g., --mouseless adds that feature to defaults). Use --minimal to disable most options.


Cloud Quickstart

For cloud environments (RunPod, Hetzner, Lambda Labs, etc):

  1. SSH into your new remote machine as root.
  2. Run the one-liner:
    # RunPod (fresh pod)
    curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/setup.sh | bash
    
    # Hetzner / standard VPS (persistent /home)
    curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/setup.sh | USER_HOME=/home bash
    This creates a non-root user, installs dependencies, clones dotfiles, and runs install.sh + deploy.sh automatically. It will prompt for GitHub auth and an optional age key (for encrypted secrets).
  3. Reconnect as your user:
    ssh yulong@<ip>
  4. (Optional) After pod restart (RunPod recreates /etc/passwd):
    curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/restart.sh | bash
  5. (Optional) Customize components: Edit config.sh to disable resource-intensive options (AI assistants, cleanup automation, etc.) before running install/deploy.

Tip: The setup auto-detects cloud providers and adjusts accordingly (persistent storage paths, SSH config, no macOS-only features). See scripts/cloud/README.md for details.

Table of Contents

Adopting These Dotfiles

This repo is highly personal — it reflects one person's workflow, opinions, and tooling choices. The best way to use it is to point a coding agent at this repo and ask it to extract the parts you find useful into your own dotfiles.

What's generalizable vs personal:

Generalizable (worth extracting) Personal (skip or replace)
Shell config (zsh/tmux/p10k) Claude Code plugins/agents/skills
Modern CLI tools (bat, eza, fd, rg, etc.) Website alias, SSH host colors
Git config + global gitignore/gitattributes Mouseless config
Editor settings (VSCode/Cursor merge logic) Ghostty theme aliases
Cleanup automation (Downloads/Screenshots) Specific API keys and gist IDs
Gist sync (bidirectional SSH config/identity sync) Cloud setup scripts (RunPod user)
SOPS + age encrypted secrets workflow Plugin marketplace selections

All personal values are centralized in [config.sh](./config.sh) — edit DOTFILES_USERNAME, DOTFILES_REPO, GIST_SYNC_ID, GIT_USER_NAME, and GIT_USER_EMAIL to make it yours.

Rust CLI Tools

These modern alternatives are installed by default and significantly faster than their traditional counterparts:

Tool Replaces Why it's better
[bat](https://github.com/sharkdp/bat) cat Syntax highlighting, line numbers, git integration
[eza](https://github.com/eza-community/eza) ls Colors, icons, git status, tree view built-in
[fd](https://github.com/sharkdp/fd) find Intuitive syntax, respects .gitignore, 5x faster
[ripgrep](https://github.com/BurntSushi/ripgrep) (rg) grep Recursive by default, respects .gitignore, 10x+ faster
[delta](https://github.com/dandavison/delta) diff Side-by-side, syntax highlighting, line numbers
[zoxide](https://github.com/ajeetdsouza/zoxide) cd Learns your habits, jump with z dirname
[dust](https://github.com/bootandy/dust) du Intuitive visualization of disk usage
[jless](https://github.com/PaulJuliusMartinez/jless) less (JSON) Interactive JSON viewer with vim keybindings

Extras (--extras flag):

  • [hyperfine](https://github.com/sharkdp/hyperfine) — statistical benchmarking with warmup and multiple runs
  • [gitui](https://github.com/extrawurst/gitui) — TUI for git
  • [code2prompt](https://github.com/mufeedvh/code2prompt) — generate LLM prompts from codebases

Installation

Step 1: Install dependencies

Install dependencies (e.g. oh-my-zsh and related plugins). The installer auto-detects your OS and applies sensible defaults.

# Install with defaults (recommended)
./install.sh

# Install only specific components
./install.sh --minimal --tmux --zsh  # --minimal disables all defaults

Defaults by platform:

Platform Defaults
macOS zsh, tmux, AI tools, cleanup + Rust CLI tools via Homebrew
Linux zsh, tmux, AI tools, create-user + Rust CLI tools via mise

Installation on macOS requires Homebrew - install from brew.sh first if needed.

Step 2: Deploy configurations

Deploy configurations (sources aliases for .zshrc, applies oh-my-zsh settings, etc.). All settings live in [config.sh](./config.sh) — edit once, deploy everywhere.

# Deploy with defaults (recommended)
./deploy.sh

# Profiles
./deploy.sh --profile=server    # Safe base for shared machines
./deploy.sh --profile=minimal   # Nothing enabled — specify what you want

# Deploy only specific components
./deploy.sh --only vim claude   # Only vim and claude, nothing else

# Add to defaults
./deploy.sh --mouseless         # Defaults + mouseless

Default components:

  • Shell: ZSH, tmux, vim, Powerlevel10k
  • Editors: VSCode/Cursor settings (merged, not overwritten), .editorconfig, .curlrc, .inputrc
  • AI tools: Claude Code, Codex CLI, Ghostty terminal
  • Git: gitconfig, global gitignore/gitattributes, global git hooks (secret detection)
  • Dev tools: htop, pdb++, matplotlib styles
  • Secrets: GitHub gist sync, SOPS-encrypted API keys
  • Automation: file cleanup (macOS), Claude Code session cleanup, AI tools auto-update, package auto-update, keyboard repeat enforcement (macOS)

Flags are additive — e.g., ./deploy.sh --mouseless deploys defaults + mouseless. Use --minimal to disable all defaults, then specify only what you want.

AI Assistants

Claude Code (Primary AI Assistant)

This setup includes extensive Claude Code customization optimized for AI safety research:

./deploy.sh --claude  # Symlinks claude/ → ~/.claude

What's included:

  • **CLAUDE.md** - Global instructions enforcing research discipline:
    • Zero-tolerance rules (no mock data, no fabrication, no destructive git)
    • Research methodology (interview → plan → implement, change one variable at a time)
    • Performance patterns (async API calls, caching, 100+ concurrent requests)
    • Context management (subagents for large files, efficient exploration)
  • **agents/** - Specialized subagents for different tasks:
    • code-reviewer, research-engineer, debugger, performance-optimizer
    • experiment-designer, research-skeptic, data-analyst
    • literature-scout, paper-writer, clarity-critic
  • **skills/** - Custom slash commands:
    • /commit, /run-experiment, /spec-interview-research
    • /read-paper, /review-draft, /reproducibility-report
  • **hooks/** - Auto-logging to ~/.claude/logs/, desktop notifications, file read warnings
  • **templates/** - Reproducibility reports, research specs

Smart merge preserves your data - if ~/.claude already exists, credentials, history, and cache are automatically restored after symlinking.

Claude Code Plugin Marketplaces

Claude Code supports community plugin marketplaces. These are worth exploring independently:

Marketplace What's in it
superpowers (official) TDD, brainstorming, code review, agent teams, worktree workflows
ui-ux-pro-max 50 design styles, 21 palettes, production-grade frontend
ai-safety-plugins Research experiments, paper writing, literature review
productivity-tools Hookify, plugin dev tools

Profiles are managed via the claude-tools context CLI — compose multiple profiles to control which plugins load per-project:

claude-tools context code               # Software projects
claude-tools context code frontend python    # Compose multiple profiles
claude-tools context --list             # Show active plugins and available profiles

Codex CLI (OpenAI)

Codex CLI configuration that reuses Claude Code's skills:

./deploy.sh --codex  # Symlinks codex/ → ~/.codex

What's included:

  • **AGENTS.md** - Global instructions (references CLAUDE.md as source of truth)
  • **config.toml** - Model settings and per-project trust levels
  • **skills/** - Symlinked to Claude Code's skills for consistency

The configuration follows the same research discipline as Claude Code but adapted for Codex's execution model.

Gemini CLI (Google)

Gemini CLI can sync with Claude Code configurations:

./scripts/sync_claude_to_gemini.sh  # Syncs skills/agents/permissions

What it does:

  • Symlinks Claude Code skills to ~/.gemini/skills/
  • Converts Claude agents to Gemini skill format
  • Syncs permissions from .claude/settings.json to Gemini policies
  • Creates GEMINI.md pointer to CLAUDE.md

Note: Gemini CLI uses a different skills format. The sync script adapts Claude's configuration but some features may not translate directly.

Terminal & Shell

Ghostty (Terminal Emulator)

Ghostty is a fast, GPU-accelerated terminal written in Zig. Config is symlinked to the platform-specific location:

./deploy.sh --ghostty  # Part of defaults

Key settings in config/ghostty.conf:

  • Cmd+C triggers shell-based copy (integrates with tmux)
  • Shift+Enter for multiline input
  • Sensible font and color defaults

Config location: macOS ~/Library/Application Support/com.mitchellh.ghostty/config, Linux ~/.config/ghostty/config

Theme Aliases

Launch new Ghostty windows with different color themes - useful for visually distinguishing contexts:

Alias Theme Character
g1 Catppuccin Mocha Warm purple/pink
g2 TokyoNight Cool blue
g3 Gruvbox Dark Retro orange/brown
g4 Nord Arctic icy blue
g5 Dracula Purple accents
g6 Rose Pine Muted rose tones
g1                        # Launch Ghostty with Catppuccin Mocha
gtheme "Tomorrow Night"   # Launch with any theme
ghostty +list-themes      # See all available themes

Each alias opens a single fresh window (no tab restoration) with the specified theme.

SSH Color Switching

Terminal colors automatically change when SSH-ing to help identify which machine you're on. Colors revert when the session ends.

ssh myserver     # In Ghostty: colors change automatically
sshc myserver    # Explicit color-changing SSH (works in any terminal)

Configure per-host colors by editing SSH_HOST_COLORS in config/aliases.sh:

# Format: "background:foreground:cursor" in hex
SSH_HOST_COLORS[prod*]="#3d0000:#ffffff:#ff6666"      # Red-tinted for production
SSH_HOST_COLORS[dev*]="#002200:#ffffff:#66ff66"       # Green-tinted for dev
SSH_HOST_COLORS[gpu*]="#1a0033:#ffffff:#cc66ff"       # Purple for GPU servers
SSH_HOST_COLORS[default]="#0d1926:#c5d4dd:#88c0d0"    # Blue-gray fallback

Patterns support wildcards (prod* matches prod1, prod-web, etc.). The default key applies to any host without a specific match.

Powerlevel10k Prompt

Powerlevel10k provides a fast, feature-rich ZSH prompt. This config includes custom segments for SSH-aware machine identification.

Requirements: Install a Nerd Font for icons.

Reconfigure: Run p10k configure (when prompted, overwrite p10k.zsh but don't apply to .zshrc).

Segment Description
Remote host Machine name + emoji (SSH sessions only)
Directory Current path with git root highlighting
Git status Branch, dirty indicator, stash count
Right side Exit code, command duration, Python venv, cloud contexts

SSH-Aware Machine Identification

When SSH'd to a remote machine, the prompt shows a consistent machine name derived from your SSH config:

🌊 mats ~/code/project (main)                   # Instead of: user@ip-172-31-42-17

Each machine gets a unique emoji based on its name hash, so you can visually distinguish machines at a glance.

How it works:

  1. Looks up your public IP against ~/.ssh/config HostName entries
  2. Uses the matching Host alias as the display name
  3. Falls back to abbreviated hostname if no match
  4. Hashes the name to assign a stable emoji from a curated palette

Example SSH config:

Host mats
    HostName 203.0.113.42
    User yulong

Host hetzner-gpu
    HostName 198.51.100.10
    User root

SSH to 203.0.113.42 → prompt shows 🌊 mats instead of the IP or hostname.

Customization:

  • SERVER_NAME env var overrides everything
  • MACHINE_EMOJI env var overrides the auto-assigned emoji

Claude Code Statusline

Claude Code displays a custom statusline with session info. Configuration: claude/settings.json (statusLine.command = "claude-tools statusline").

🌊 mats [code python] ~/code/project (main*) · 📊 45% · $0.23 · 12m
│        │             │              │      │        │        └─ Session duration
│        │             │              │      │        └─ Session cost
│        │             │              │      └─ Context usage (color-coded)
│        │             │              └─ Branch (* = dirty)
│        │             └─ Active Claude context profiles
│        └─ Directory
└─ Machine name (SSH only, same as p10k)

Features:

  • Machine name: Uses same machine-name script as Powerlevel10k for consistency
  • Git info: Branch with dirty indicator
  • Context %: Color-coded usage (green <70%, yellow 70-89%, red 90%+)
  • Cost: Running session total in USD
  • Duration: Session runtime in minutes/hours

ccusage statusline is not wired into the live Claude hook path because it can OOM on large local histories; guard logic still uses lightweight ccusage blocks --active --json where available.

Both the shell prompt and Claude Code statusline use your SSH config aliases, so machine identification is consistent across tools.

Ignore Pattern Management

claude-tools ignore manages per-repo .gitignore and .ignore patterns interactively.

claude-tools ignore                    # Launch TUI (same as `ignore apply`)
claude-tools ignore apply              # Interactive pattern selection
claude-tools ignore apply --dry-run    # Preview without writing
claude-tools ignore apply --non-interactive  # Apply defaults without TUI
claude-tools ignore status             # Show current managed patterns

The TUI shows patterns grouped by category with tri-state toggles:

  • [ ] skip — pattern not applied
  • [ G ] gitignore — added to .gitignore only
  • [G+S] gitignore + searchable — added to .gitignore AND negated in .ignore

Patterns in [G+S] state are git-ignored but remain searchable by rg, fd, Claude Code, and Cursor. Pattern definitions live in config/ignore/patterns.

Codex Statusline

Codex uses built-in status items configured in codex/config.toml under [tui].status_line (for example: model, current dir, git branch, weekly/5h limits, context remaining).

SSH Key Management

Automatically adds your SSH key to ssh-agent on shell startup:

# Automatically enabled when you deploy ZSH config
./deploy.sh  # (default: includes ZSH)

How it works:

  • Checks for ~/.ssh/id_ed25519 (customizable via SSH_KEY_PATH env var)
  • Prompts to generate if key doesn't exist (never overwrites existing keys)
  • Adds to macOS Keychain (--apple-use-keychain) or Linux ssh-agent
  • Only runs in interactive shells
  • Skips if key already loaded in agent

First-time setup flow:

  1. Shell starts → detects no key → prompts "Generate a new ed25519 SSH key now? [y/N]"
  2. If yes → generates key → shows command to copy public key
  3. Automatically adds to agent on this and future shell sessions

Custom key path:

export SSH_KEY_PATH=~/.ssh/id_rsa  # Use RSA key instead

Configuration: [config/ssh_setup.sh](config/ssh_setup.sh)

Dev Tools

htop (Process Monitor)

Dynamic htop configuration that adapts CPU meters to your core count:

./deploy.sh --htop  # Part of defaults

The config in config/htop/htoprc uses a dynamic layout that works across machines with different CPU counts—no manual adjustment needed.

pdb++ (Python Debugger)

High-contrast color scheme for pdb++, the enhanced Python debugger:

./deploy.sh --pdb  # Part of defaults

Global config works with per-project installations. The config is deployed to ~/.pdbrc.py (symlinked), but pdb++is installed per-project via uv add --dev pdbpp. This works because pdb++ reads the global config at runtime.

Auto-detects terminal background using OSC 11 escape sequence:

  • Light terminals: Dark colors on light background (solarized-light theme)
  • Dark terminals: Bright colors on dark background (monokai theme)
  • Fallback: Defaults to dark theme if detection fails (SSH, older terminals)

Detection succeeds in modern terminals (iTerm2, Ghostty, Kitty, Alacritty) and fails gracefully elsewhere.

Test it works:

cd /path/to/project
uv add --dev pdbpp
python -c "import pdb; pdb.set_trace()" <<< "c"
# Should show high-contrast colors

Per-project override (advanced): Create .pdbrc.py in project root. It takes precedence over the global config. See pdb++ docs for details.

Automation

Automatic Cleanup (macOS)

Scheduled cleanup of old files from ~/Downloads and ~/Screenshots:

./deploy.sh --cleanup  # Part of macOS defaults

How it works:

  • Moves files older than 180 days (configurable) to Trash (not permanent delete)
  • Runs monthly via launchd
  • Only deletes files not accessed AND not modified in retention period
# Preview what would be cleaned
./scripts/cleanup/cleanup_old_files.sh --dry-run

# Custom retention (90 days) and schedule (weekly)
./scripts/cleanup/install.sh --days 90 --schedule weekly

See [scripts/cleanup/README.md](./scripts/cleanup/README.md) for full documentation.

Claude Code Session Cleanup (both platforms)

Automatically kills idle Claude Code processes daily at 17:00:

./deploy.sh --claude-cleanup  # Part of defaults (both macOS and Linux)

How it works:

  • Only kills processes with no output activity for 24h (preserves active + tmux sessions)
  • Runs daily via launchd (macOS) or cron (Linux)
  • Manual control via clear-claude-code command (aliases: ccl, cci, ccf)
# Check status
clear-claude-code --list

# Uninstall
./scripts/cleanup/setup_claude_cleanup.sh --uninstall

AI Tools Auto-Update (both platforms)

Daily automatic updates for Claude Code, Gemini CLI, and Codex CLI at 06:00:

./deploy.sh --ai-update  # Part of defaults

Runs via launchd (macOS) or cron (Linux). Uninstall with scripts/cleanup/setup_ai_update.sh --uninstall.

Package Auto-Update (both platforms)

Weekly package upgrade + cleanup on Sundays at 05:00:

./deploy.sh --brew-update  # Part of defaults

Supports Homebrew (macOS), apt, dnf, and pacman (Linux). Includes cleanup of stale caches.

Text Replacements (macOS)

Bidirectional sync between macOS text replacements and Alfred snippets. Runs daily at 09:00:

./deploy.sh --text-replacements  # macOS only, part of defaults

macOS uses raw shortcuts; Alfred applies a collection prefix at runtime (e.g., fm.hi). Requires Full Disk Access for your terminal app.

Secrets & Security

Encrypted Secrets (SOPS + age)

SOPS (Secrets OPerationS, by Mozilla) encrypts file values while keeping keys/structure visible — you can git diff and review encrypted files. age provides the keypair (modern, simple alternative to PGP). Works offline, git-versioned, no service dependency.

How it works:

age keypair (one-time setup)
├── Private key: ~/.config/sops/age/keys.txt   ← secret, stored in Bitwarden
└── Public key:  extracted from private key     ← stored in private secrets repo .sops.yaml

Encryption:  plaintext env vars  →  sops -e  →  ~/.config/dotfiles-secrets/secrets.env.enc (private git repo)
Decryption:  private secrets repo  →  sops -d  →  process memory / repo-scoped .envrc exports

File locations:

File Location Purpose Git status
DOTFILES_SECRETS_DIR ~/.config/dotfiles-secrets by default Private repo/path for the encrypted dotfiles secrets store Private
.sops.yaml $DOTFILES_SECRETS_DIR/.sops.yaml SOPS config for the private secrets repo Private
secrets.env.enc $DOTFILES_SECRETS_DIR/secrets.env.enc Encrypted API keys (values encrypted, key names visible) Private
keys.txt ~/.config/sops/age/keys.txt age private key (paste from Bitwarden on new machines) Not in repo

.secrets is now treated as a legacy migration artifact rather than the normal runtime path. The intended flow is encrypted-at-rest plus on-demand decryption.

Commands:

secrets-init             # First-time setup: generate age keypair + initialize $DOTFILES_SECRETS_DIR
secrets-edit             # Edit the encrypted dotenv file in place (no plaintext runtime file needed)
secrets-paths            # Show the resolved private secrets repo paths
secrets-init-project     # Bootstrap per-project: .sops.yaml + secrets.env.enc + .envrc

New machine setup:

  1. Install sops + age (./install.sh handles this)
  2. Clone or create your private secrets repo at $DOTFILES_SECRETS_DIR (default ~/.config/dotfiles-secrets)
  3. Paste age private key from Bitwarden: secrets-init (or manually to ~/.config/sops/age/keys.txt)
  4. Run ./deploy.sh — verifies the encrypted store can be decrypted on demand

Least-privilege hardening now runs automatically in secrets-init, secrets-edit, secrets-updatekeys, secrets-rotate-data-key, setup-envrc, and deploy.sh. secrets-fix-perms remains available as a manual repair command for the private secrets repo (700 dir, 600 files) and repo-local secret state (.env, .envrc, .claude/channels/telegram/, local .sops.yaml, secrets.env.enc).

Per-project usage: Run setup-envrc in any repo to create a .envrc that selectively exposes only the secrets that repo should see. It supports direct exports (KEY), renamed exports (ENV_VAR=SECRET_NAME), and a repo-specific Telegram plugin binding (--telegram-secret SECRET_NAME) that materializes .claude/channels/telegram/.env only when Claude launches. If local .env files already exist, the TUI scans the repo root recursively, flags drift against the encrypted store, and can offer to delete selected files. Use secrets-init-project only when the repo needs its own SOPS-managed secrets file.

setup-envrc tries direnv allow automatically. If that cannot update direnv's allowlist (for example in a sandboxed or read-only environment), it now prints the manual direnv allow . command and still completes the rest of the setup.

Further reading: SOPS README · age README · SOPS + age tutorial

Gist Sync Automation (both platforms)

Automatically sync config with GitHub gist daily at 08:00:

./deploy.sh --secrets  # Part of defaults

How it works:

  • Bidirectional sync with GitHub gist (SSH config, authorized_keys, git identity)
  • Auto-adds local public key to authorized_keys (enables SSH between your machines)
  • Last-modified wins: compares local vs gist timestamps
  • Requires gh auth login (run once for authentication)
  • Runs daily via launchd (macOS) or cron (Linux)
# Manual sync
sync-gist

# Uninstall automation
./scripts/cleanup/setup_gist_sync.sh --uninstall

Note: Secret gists are unlisted, not encrypted. Only non-secret config (SSH config, authorized_keys, git identity) should be synced via gist.

Global Git Hooks

Pre-commit hooks for secret detection across all repositories:

./deploy.sh --git-hooks  # Part of defaults

Scans staged files for API keys, tokens, and credentials before each commit.

Supply Chain Defense

Multi-layer defense against npm/PyPI supply chain attacks (axios 2026, litellm 2026, shai-hulud 2025). Deployed automatically with ./deploy.sh.

What it does:

Layer Defense What it blocks
7-day quarantine min-release-age on all package managers Freshly-published malicious versions (caught within days)
Script blocking ignore-scripts=true in npm/pnpm Postinstall scripts that exfiltrate secrets or install RATs
Credential isolation API keys scoped per-project via direnv Compromised package in project A can't read project B's keys
Lockfile scanning Pre-commit hook checks changed lockfiles Known-bad packages entering your lockfile
Weekly audit Scans all repos for known-bad IOCs Packages you already have that were later found compromised
Claude Code hook Warns before any npm install / pip install AI assistant installing packages without checking them first

Day-to-day workflow:

# Installing packages works normally — quarantine is transparent
npm install express          # Works (express is >7 days old)
bun add zod                  # Works
uv add httpx                 # Works

# New packages published <7 days ago are blocked (intentional)
npm install some-brand-new-pkg
# Error: min-release-age — package was published 2 days ago

# Override for a specific install (after checking it's safe)
npm install --min-release-age=0 some-brand-new-pkg   # npm
bun add --minimumReleaseAge=0 some-brand-new-pkg      # bun
UV_EXCLUDE_NEWER= uv pip install some-brand-new-pkg   # uv

Credential isolation:

API keys stay in $DOTFILES_SECRETS_DIR/secrets.env.enc and are NOT globally exported. Each project gets only the keys it needs:

# Interactive picker (fzf)
cd ~/code/my-project
setup-envrc                  # Select keys with TAB, confirm with ENTER
# → Creates .envrc with eval-based exports, direnv auto-loads on cd

# Non-interactive
setup-envrc ANTHROPIC_API_KEY OPENAI_API_KEY

# Map a namespaced secret into the env var your app expects
setup-envrc ANTHROPIC_API_KEY TELEGRAM_BOT_TOKEN=NUDGE_TELEGRAM_BOT_TOKEN

# Claude Telegram plugin: keep the token canonical in dotfiles-secrets,
# and generate .claude/channels/telegram/.env only at launch time
setup-envrc --telegram-secret AMBASSADOR_TELEGRAM_BOT_TOKEN

# Check what's configured
setup-envrc --list           # Show keys in current .envrc
setup-envrc --clean          # Remove .envrc

# One-off command with selected keys (no .envrc needed)
with-secrets ANTHROPIC_API_KEY OPENAI_API_KEY -- python my_script.py

Manual audit:

dep-audit                    # Scan all repos for known-bad packages now
# Runs automatically every Sunday at 10 AM

Config files deployed:

File Deployed to Purpose
config/npmrc ~/.npmrc ignore-scripts=true + min-release-age=7
config/bunfig.toml ~/.bunfig.toml minimumReleaseAge=604800 (seconds)
config/pnpmrc ~/Library/Preferences/pnpm/rc minimum-release-age=10080 (minutes)
config/uv.toml ~/.config/uv/uv.toml exclude-newer (via UV_EXCLUDE_NEWER env var)

Selective deploy:

./deploy.sh --only pkg-configs    # Just package manager configs
./deploy.sh --no-pkg-configs      # Everything except package configs
./deploy.sh --only dep-audit      # Just the weekly audit

Getting to know these dotfiles

  • Any software or command line tools you need, add them to the install.sh script. Try adding a new command line tool to the install script.
  • Any new plugins or environment setup, add them to the config/zshrc.sh script.
  • Any aliases you need, add them to the config/aliases.sh script. Try adding your own alias to the bottom of the file. For example, try setting cd1 to your most used git repo so you can just type cd1 to get to it.
  • Utility functions in config/modern_tools.sh: mkd (mkdir+cd), cdf (cd to Finder window, macOS), targz (smart compression), dataurl, digga (DNS lookup), getcertnames (SSL certs), o (cross-platform open), server (quick HTTP server)
  • System aliases in config/aliases.sh: flush (DNS cache), afk (lock screen, macOS), week (ISO week number)

Cloud Setup (RunPod, Hetzner, etc.)

One-command setup for cloud VMs and containers:

# RunPod (fresh pod, as root)
curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/setup.sh | bash

# After pod restart (recreates user entry)
curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/restart.sh | bash

# Hetzner / standard VPS (persistent /home)
curl -fsSL https://raw.githubusercontent.com/yulonglin/dotfiles/main/scripts/cloud/setup.sh | USER_HOME=/home bash

Then SSH as yulong@<ip> (not root). See [scripts/cloud/README.md](./scripts/cloud/README.md) for details.

What it does:

  • Creates non-root user in persistent storage (/workspace/yulong on RunPod)
  • Installs uv, dotfiles, Claude Code
  • Copies SSH keys for direct access

About

Highly-opinionated setup for AI safety research with coding agents (Claude Code, Codex, Gemini CLI)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors