| name | dev-environment |
| description | Local development environment patterns: runtime version pinning with mise/asdf, environment variables with direnv, Dev Containers for consistent team environments, Docker Compose for local services, and pre-commit hooks. |
Dev Environment Skill
"Works on my machine" is a solved problem. Consistent environments across the team eliminate entire classes of bugs and onboarding friction.
When to Activate
- Setting up a new project's development environment (
/setup-dev)
- Onboarding a new developer
- Debugging "it works on CI but not locally" problems
- Standardizing the team's Node/Python/Go version
- Setting up pre-commit hooks for automatic quality checks
- Configuring a Dev Container so the project opens identically in VS Code and GitHub Codespaces
- Running local email testing with Mailpit so email flows can be verified without a real SMTP server
Runtime Version Pinning (mise)
mise (formerly rtx) manages Node, Python, Go, Java, and 200+ other runtimes per-project:
[tools]
node = "22"
python = "3.12"
go = "1.24"
[env]
NODE_ENV = "development"
curl https://mise.run | sh
mise install
mise activate zsh >> ~/.zshrc
Everyone on the team runs the same versions. CI should use the same .mise.toml:
- uses: jdx/mise-action@v2
Environment Variables (direnv)
direnv automatically loads .env when you cd into a project directory:
brew install direnv
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
echo 'dotenv' > .envrc
direnv allow
.env is gitignored. .env.example is committed with all variables documented.
DATABASE_URL=postgresql://app:app@localhost:5432/appdb
REDIS_URL=redis://localhost:6379
dotenv
Dev Container (VS Code / GitHub Codespaces)
Dev Containers give every developer (and CI) the exact same environment in Docker:
{
"name": "myapp",
"dockerComposeFile": ["../docker-compose.dev.yml", "docker-compose.devcontainer.yml"],
"service": "app",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"postCreateCommand": "npm install && npm run db:migrate",
"postStartCommand": "docker compose up -d postgres redis",
"customizations": {
"vscode": {
"settings": {
"editor.formatOnSave"
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
environment:
DATABASE_URL: postgresql://app:app@postgres:5432/appdb
REDIS_URL: redis://redis:6379
Docker Compose for Local Services
Run only infrastructure services locally — run the app code natively (better hot reload, debugger):
services:
postgres:
image: postgres:18-alpine
environment: { POSTGRES_DB: appdb, POSTGRES_USER: app, POSTGRES_PASSWORD: app }
ports: ['5432:5432']
volumes: [postgres_data:/var/lib/postgresql/data]
healthcheck:
test: [CMD, pg_isready, -U, app]
interval: 5s
retries: 5
redis:
image: redis:8-alpine
ports: ['6379:6379']
mailpit:
image: axllent/mailpit
ports: ['1025:1025', '8025:8025']
volumes:
postgres_data:
docker compose -f docker-compose.dev.yml up -d
docker compose -f docker-compose.dev.yml stop
docker compose -f docker-compose.dev.yml down -v && docker compose -f docker-compose.dev.yml up -d
Pre-Commit Hooks (automatic quality gates)
These already exist via hooks.json — document the key ones:
| Hook | Trigger | What It Does |
|---|
| Post-edit format | Edit any TS/JS file | Runs Biome/Prettier |
| Post-edit typecheck | Edit any .ts file | Runs tsc --noEmit |
| Console.log warning | Edit any file | Warns if console.log added |
| Pre-push reminder | git push | Prompts to review changes |
For teams without Claude Code, use pre-commit:
repos:
- repo: local
hooks:
- id: lint
name: Lint
entry: npm run lint
language: system
pass_filenames: false
- id: typecheck
name: Type Check
entry: npm run typecheck
language: system
pass_filenames: false
Checklist