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.
Install to Claude Code
npx -y skills add aibot88/sec_skill_store --skill direnv-pattern --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Direnv Pattern?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-direnv-pattern)More formats (shields.io, HTML) on the badges page.
---
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
1. **Datums specify WHICH** - `~/.dotfiles/_b00t_/*.ai.toml` files specify required variable names
2. **`.env` contains VALUES** - Actual API keys and secrets (gitignored)
3. **`direnv` loads automatically** - No manual `source` or `export` needed
4. **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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
direnv allow
```
### 5. Verify Setup
```bash
# 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
```bash
# 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
```bash
# 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
```toml
[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
```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:
```bash
# .envrc
# Load global keys from home directory
dotenv ~/.env
# Load project-specific keys (can override global)
dotenv
```
### Environment-Specific Configuration
```bash
# .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
```bash
#!/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 `.env` to `.gitignore`
- ✅ Add `.envrc` to `.gitignore` (committed: `.envrc.example`)
- ✅ Use `.env.example` as template (committed to git)
- ✅ Store API keys only in `.env` files
- ✅ Use `direnv allow` to load environment per-project
- ✅ Validate environment variables before use
### ❌ DON'T
- ❌ Commit `.env` files to git
- ❌ Commit `.envrc` with secrets to git
- ❌ Hard-code API keys in source code
- ❌ Store secrets in datum TOML files
- ❌ Share `.env` files via chat/email
- ❌ Use production keys in examples
## .gitignore Configuration
```gitignore
# Environment files (secrets)
.env
.envrc
.env.local
.env.*.local
# Keep examples (templates)
!.env.example
!.envrc.example
```
## Troubleshooting
### Variables Not Loading
```bash
# 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
```python
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
```bash
# Re-allow
direnv allow
# Check .envrc syntax
bash -n .envrc
```
## CI/CD Integration
For environments where direnv isn't available:
```yaml
# .gitlab-ci.yml
variables:
OPENROUTER_API_KEY: ${CI_OPENROUTER_API_KEY}
test:
script:
- python3 -m pytest
```
```yaml
# .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
1. **Install direnv** and add shell hook
2. **Copy templates**: `.envrc.example` → `.envrc`, `.env.example` → `.env`
3. **Edit .env** with actual API keys
4. **Run `direnv allow`**
5. **Verify** with `echo $API_KEY` or Python
### Adding New Keys
1. **Add to .env.example** (commented, as template)
2. **Add to .env** (actual value)
3. **Update datum** to specify required key
4. **Run `direnv allow`** if .envrc changed
### Per-Project Configuration
1. **Navigate to project**: `cd /path/to/project`
2. **Create .envrc**: Reference `.envrc.example`
3. **Create .env**: Reference `.env.example`
4. **Allow**: `direnv allow`
5. **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 guide
- `b00t-j0b-py/.envrc.example` - Template
- `b00t-j0b-py/.env.example` - API keys template
- `b00t-py/src/lib.rs` - PyO3 validation functions
## Summary
The b00t direnv pattern provides:
1. **DRY**: Single source of truth for requirements (datums)
2. **Secure**: Secrets in `.env` (gitignored), not in code
3. **Automatic**: `direnv` loads environment on `cd`
4. **Validated**: Rust checks required vars before execution
5. **Flexible**: Supports multiple `.env` files, local/global keys
Scanned 9/12/2026
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!