| name | direnv-pattern |
| description | Implements the b00t environment management pattern: direnv → .envrc → dotenv → .env where datums specify WHICH environment variables are required and .env contains the actual secret VALUES. Ensures automatic environment loading per-project. |
| version | 1.0.0 |
| allowed-tools | Read, Write, Edit, Bash |
What This Skill Does
The b00t direnv pattern provides secure, automatic environment variable management for projects. This skill helps you:
- Set up direnv + .envrc + .env configuration
- Follow the b00t pattern: WHICH (datums) vs VALUES (.env)
- Validate environment variables before execution
- Support multiple environments (dev, staging, prod)
- Integrate with b00t datum system
When It Activates
Activate this skill when you see phrases like:
- "setup environment variables"
- "configure direnv"
- "create .envrc file"
- "add API keys"
- "environment not loading"
- "missing environment variables"
- "configure .env file"
- "setup direnv pattern"
The b00t Pattern Flow
Developer enters directory
↓
direnv detects .envrc file
↓
.envrc calls: dotenv
↓
dotenv loads .env file
↓
Environment variables available
↓
Rust validates via datum
↓
✅ Agent runs
Key Principles
- Datums specify WHICH -
~/.dotfiles/_b00t_/*.ai.tomlfiles specify required variable names .envcontains VALUES - Actual API keys and secrets (gitignored)direnvloads automatically - No manualsourceorexportneeded- Rust validates - Via PyO3 bindings, DRY approach
File Structure
project/
├── .envrc # ← Loaded by direnv (calls dotenv)
├── .env # ← Contains actual API keys (GITIGNORED!)
├── .envrc.example # ← Template for .envrc (committed)
├── .env.example # ← Shows required keys (committed)
└── .gitignore # ← Must include .env and .envrc
Setup Instructions
1. Install direnv
# macOS
brew install direnv
# Ubuntu/Debian
sudo apt-get install direnv
# Add to shell (choose one):
# bash:
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
# zsh:
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
# fish:
echo 'direnv hook fish | source' >> ~/.config/fish/config.fish
2. Create .envrc
# b00t direnv configuration
# This file demonstrates the b00t pattern: direnv → .envrc → dotenv → .env
# Load project .env file (contains API keys)
dotenv
# Optionally load home directory .env for global keys
# dotenv ~/.env
# Optionally load environment-specific configs
# dotenv .env.local
# dotenv .env.development
3. Create .env with API Keys
# OpenRouter (200+ models via single API)
OPENROUTER_API_KEY=sk-or-v1-abc123...
# Anthropic (Claude)
ANTHROPIC_API_KEY=sk-ant-api03-xyz789...
# OpenAI
OPENAI_API_KEY=sk-proj-def456...
# HuggingFace
HF_TOKEN=hf_ghi789...
# Groq (ultra-fast inference)
GROQ_API_KEY=gsk_jkl012...
4. Allow direnv
direnv allow
5. Verify Setup
# Check environment variables are loaded
echo $OPENROUTER_API_KEY
# Test with Python
python3 -c "import os; print('✅ Loaded' if os.getenv('OPENROUTER_API_KEY') else '❌ Not loaded')"
.envrc.example Template
# b00t direnv configuration
# Setup:
# 1. Copy: cp .envrc.example .envrc
# 2. Copy: cp .env.example .env
# 3. Edit .env with your actual API keys
# 4. Enable: direnv allow
# Load project .env file (contains API keys)
dotenv
# Optionally load home directory .env for global keys
# dotenv ~/.env
# Optionally load environment-specific configs
# dotenv .env.local
# Layout python - ensures direnv works with Python virtual environments
# Uncomment if using a venv:
# layout python python3.12
.env.example Template
# b00t Environment Configuration
# ==========================================
# API keys are loaded via direnv → .envrc → dotenv → .env pattern.
#
# Setup:
# 1. Copy: cp .env.example .env
# 2. Fill in your actual API keys in .env
# 3. Enable: direnv allow (after copying .envrc.example to .envrc)
#
# The b00t pattern:
# - Datums (~/.dotfiles/_b00t_/*.ai.toml) specify WHICH vars are required
# - This .env file contains the actual VALUES
# - direnv loads them automatically when entering the directory
# OpenAI (gpt-4, gpt-3.5-turbo, etc.)
# OPENAI_API_KEY=sk-proj-...
# Anthropic (claude-3.5-sonnet, claude-3-opus, etc.)
# ANTHROPIC_API_KEY=sk-ant-api03-...
# Google Gemini
# GOOGLE_API_KEY=...
# Groq (llama-3.1, mixtral, etc.)
# GROQ_API_KEY=gsk_...
# OpenRouter (200+ models via single API)
# OPENROUTER_API_KEY=sk-or-...
# HuggingFace
# HF_TOKEN=hf_...
# Ollama (local models)
# OLLAMA_BASE_URL=http://localhost:11434
Integration with Datums
Provider Datum Example
[env]
# Required: Must be present in .env file
required = ["OPENROUTER_API_KEY"]
# Optional: Default values for non-secret configuration
defaults = { OPENROUTER_API_BASE = "https://openrouter.ai/api/v1" }
Validation in Python
import b00t_py
import os
# Ensure direnv loaded the environment
assert os.getenv('OPENROUTER_API_KEY'), "Run 'direnv allow' first!"
# Validate via datum system
validation = b00t_py.check_provider_env("openrouter", "~/.dotfiles/_b00t_")
if validation["available"]:
print("✅ OpenRouter environment ready")
else:
print(f"❌ Missing: {validation['missing_env_vars']}")
print("Add them to your .env file and run 'direnv allow'")
Advanced Patterns
Multiple Environment Files
Load both global and project-specific keys:
# .envrc
# Load global keys from home directory
dotenv ~/.env
# Load project-specific keys (can override global)
dotenv
Environment-Specific Configuration
# .envrc
# Load base environment
dotenv
# Load environment-specific overrides
if [ "$ENVIRONMENT" = "production" ]; then
dotenv .env.production
elif [ "$ENVIRONMENT" = "staging" ]; then
dotenv .env.staging
else
dotenv .env.development
fi
Custom Validation in .envrc
#!/usr/bin/env bash
# Load environment
dotenv
# Validate required keys are present
required_vars=("OPENROUTER_API_KEY" "ANTHROPIC_API_KEY")
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
echo "❌ Missing: $var"
echo " Add it to your .env file"
return 1
fi
done
echo "✅ All required environment variables loaded"
Security Best Practices
✅ DO
- ✅ Add
.envto.gitignore - ✅ Add
.envrcto.gitignore(committed:.envrc.example) - ✅ Use
.env.exampleas template (committed to git) - ✅ Store API keys only in
.envfiles - ✅ Use
direnv allowto load environment per-project - ✅ Validate environment variables before use
❌ DON'T
- ❌ Commit
.envfiles to git - ❌ Commit
.envrcwith secrets to git - ❌ Hard-code API keys in source code
- ❌ Store secrets in datum TOML files
- ❌ Share
.envfiles via chat/email - ❌ Use production keys in examples
.gitignore Configuration
# Environment files (secrets)
.env
.envrc
.env.local
.env.*.local
# Keep examples (templates)
!.env.example
!.envrc.example
Troubleshooting
Variables Not Loading
# Check if direnv is hooked
direnv status
# Re-allow .envrc
direnv allow
# Check what direnv loaded
direnv export bash | grep API_KEY
Missing Required Variables
import b00t_py
# List available providers
providers = b00t_py.list_ai_providers("~/.dotfiles/_b00t_")
print(f"Available: {providers}")
# Check specific provider
validation = b00t_py.check_provider_env("openrouter", "~/.dotfiles/_b00t_")
if not validation["available"]:
print(f"Missing: {validation['missing_env_vars']}")
Permission Denied
# Re-allow
direnv allow
# Check .envrc syntax
bash -n .envrc
CI/CD Integration
For environments where direnv isn't available:
# .gitlab-ci.yml
variables:
OPENROUTER_API_KEY: ${CI_OPENROUTER_API_KEY}
test:
script:
- python3 -m pytest
# .github/workflows/test.yml
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: python3 -m pytest
Workflow
Initial Setup
- Install direnv and add shell hook
- Copy templates:
.envrc.example→.envrc,.env.example→.env - Edit .env with actual API keys
- Run
direnv allow - Verify with
echo $API_KEYor Python
Adding New Keys
- Add to .env.example (commented, as template)
- Add to .env (actual value)
- Update datum to specify required key
- Run
direnv allowif .envrc changed
Per-Project Configuration
- Navigate to project:
cd /path/to/project - Create .envrc: Reference
.envrc.example - Create .env: Reference
.env.example - Allow:
direnv allow - Test: Python imports should have env vars
Related Skills
- datum-system: Specifies WHICH env vars are required
- dry-philosophy: Rust validates env, Python just uses it
- justfile-usage: Add environment setup commands
References
b00t-j0b-py/docs/ENVIRONMENT_SETUP.md- Complete guideb00t-j0b-py/.envrc.example- Templateb00t-j0b-py/.env.example- API keys templateb00t-py/src/lib.rs- PyO3 validation functions
Summary
The b00t direnv pattern provides:
- DRY: Single source of truth for requirements (datums)
- Secure: Secrets in
.env(gitignored), not in code - Automatic:
direnvloads environment oncd - Validated: Rust checks required vars before execution
- Flexible: Supports multiple
.envfiles, local/global keys