Use Cases (Updated: 6/3/2026)

Claude Code Dev Environment Setup: Safe, Reproducible Workflow

Set up Claude Code with Node, Docker, .env rules, permissions, hooks, and repeatable checks.

Claude Code Dev Environment Setup: Safe, Reproducible Workflow

A new laptop or a freshly cloned repository should not cost half a day before the first useful commit. The usual failures are predictable: the wrong Node version, mixed package managers, a stale .env, Docker volumes from an old schema, and undocumented local commands. Claude Code can remove much of that friction, but only if the environment is set up with boundaries first.

The goal is not “let the agent do everything.” The goal is a reproducible setup where every developer and every Claude Code session sees the same instructions, the same package manager, the same secret-handling rules, and the same verification commands.

Use official documentation as the source of truth: Claude Code setup, settings, permissions, and hooks. For related ClaudeCodeLab reading, keep Claude Code getting started, CLAUDE.md best practices, and hooks guide nearby.

flowchart TD
  A["Check local tools"] --> B["Pin Node and package manager"]
  B --> C["Create dependencies and .env.example"]
  C --> D["Write CLAUDE.md setup instructions"]
  D --> E["Limit permissions in settings.json"]
  E --> F["Block dangerous commands with hooks"]
  F --> G["Run doctor, env check, and tests"]

The Setup Policy

Treat the dev environment like production code. If the rule matters, commit it. If a secret matters, keep it out of the agent context. If a command can delete data or publish code, make it ask a human first.

AreaFile or commandWhy it matters
Runtime.nvmrc, packageManager, CorepackPrevents Node and package-manager drift
Secrets.env.example, .gitignore, permissions.denyKeeps real credentials out of prompts and commits
Project memoryCLAUDE.mdGives Claude Code the same setup rules every session
Permissions.claude/settings.jsonControls file reads, Bash commands, and default mode
Hooks.claude/hooks/*Enforces deterministic checks before tools run
Verificationdoctor, check:env, testReplaces “it seems fine” with command output

Copy-Paste Bootstrap

This script targets Git Bash, WSL, macOS, or Linux. It creates a minimal TypeScript project that validates environment variables, pins pnpm, denies secret reads, and installs a PreToolUse hook for risky shell commands.

#!/usr/bin/env bash
set -euo pipefail

APP_DIR="${1:-claude-dev-lab}"
mkdir -p "$APP_DIR"
cd "$APP_DIR"

command -v node >/dev/null || { echo "Node.js is required"; exit 1; }
command -v claude >/dev/null || { echo "Claude Code CLI is required"; exit 1; }

corepack enable
corepack prepare [email protected] --activate

cat > package.json <<'JSON'
{
  "name": "claude-dev-lab",
  "private": true,
  "type": "module",
  "packageManager": "[email protected]",
  "scripts": {
    "doctor": "node --version && pnpm --version && claude --version",
    "check:env": "tsx src/env.ts",
    "test": "vitest run --passWithNoTests"
  },
  "dependencies": {
    "dotenv": "latest",
    "zod": "latest"
  },
  "devDependencies": {
    "@types/node": "latest",
    "tsx": "latest",
    "typescript": "latest",
    "vitest": "latest"
  }
}
JSON

mkdir -p src .claude/hooks .vscode
printf "22\n" > .nvmrc
cat > .gitignore <<'EOF'
node_modules
.env
.env.*
!.env.example
dist
coverage
EOF

cat > .env.example <<'EOF'
NODE_ENV=development
DATABASE_URL=postgresql://app:app@localhost:5432/app
REDIS_URL=redis://localhost:6379
EOF

cat > src/env.ts <<'TS'
import { config } from "dotenv";
import { z } from "zod";

config();

const Env = z.object({
  NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
  DATABASE_URL: z.string().url(),
  REDIS_URL: z.string().url().optional()
});

const parsed = Env.safeParse(process.env);
if (!parsed.success) {
  console.error(parsed.error.flatten().fieldErrors);
  process.exit(1);
}

console.log("env ok", {
  nodeEnv: parsed.data.NODE_ENV,
  hasRedis: Boolean(parsed.data.REDIS_URL)
});
TS

cat > CLAUDE.md <<'EOF'
# Project Instructions

## Environment Setup
- Use Node from `.nvmrc`.
- Use pnpm through Corepack. Do not switch to npm or yarn.
- Copy `.env.example` to `.env` locally, then edit values by hand.
- Never read, print, or commit `.env` or secret files.
- Before changing code, run `pnpm run doctor` and `pnpm run check:env`.
- After changing code, run the narrowest relevant test and record the command result.

## Work Rules
- Start with exploration and a short plan.
- Do not run destructive commands or deploy commands without explicit human approval.
- Keep setup changes reproducible in committed files, not in local terminal history.
EOF

cat > .claude/hooks/block-dangerous.mjs <<'JS'
import { readFileSync } from "node:fs";

const input = JSON.parse(readFileSync(0, "utf8") || "{}");
const command = String(input.tool_input?.command ?? "");

const blockedPatterns = [
  /rm\s+-rf\s+(\/|~|\$HOME)/,
  /git\s+push\b/,
  /curl\b.+\|\s*(bash|sh)/,
  /Invoke-WebRequest\b.+\|\s*iex/i
];

if (blockedPatterns.some((pattern) => pattern.test(command))) {
  console.log(JSON.stringify({
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Blocked by project hook. Ask a human before destructive or remote-executed commands."
    }
  }));
} else {
  console.log("{}");
}
JS

cat > .claude/settings.json <<'JSON'
{
  "defaultMode": "plan",
  "permissions": {
    "allow": [
      "Read",
      "Bash(pnpm install)",
      "Bash(pnpm run *)",
      "Bash(git status *)",
      "Bash(claude --version)",
      "Bash(claude doctor)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(git push *)",
      "Bash(rm -rf *)"
    ]
  },
  "env": {
    "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1"
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/block-dangerous.mjs"
          }
        ]
      }
    ]
  }
}
JSON

pnpm install
cp .env.example .env
pnpm run doctor
pnpm run check:env
pnpm test

On native Windows, check the toolchain before asking Claude Code to touch the repository:

winget install Anthropic.ClaudeCode
claude --version
claude doctor
node --version
corepack enable
pnpm --version

If pnpm --version fails, fix Node/Corepack first. If claude doctor reports proxy, certificate, or authentication issues, copy the exact error into the task and ask Claude Code to diagnose within that constraint instead of guessing.

A Safer Prompt

Do not ask for “set up everything” with no boundary. Give Claude Code the allowed files, forbidden files, and receipt you expect.

claude -p "
Audit and complete the dev environment setup for this repository.

Rules:
- Do not read .env, .env.*, or files under secrets/
- Follow packageManager; do not switch from pnpm to npm or yarn
- Do not delete Docker volumes or run git push

Allowed:
- Read README, package.json, CLAUDE.md, and .claude/settings.json
- Run pnpm install, pnpm run doctor, pnpm run check:env, and pnpm test

Return a short receipt with commands run, files changed, failures found, and remaining manual steps.
"

Practical Use Cases

Use caseHow this setup helps
New SaaS prototypeAdd Docker Compose for PostgreSQL and Redis, then keep app setup reproducible from day one
Existing team repositoryLet Claude Code read docs and config, run approved checks, and update missing onboarding steps
Content or product siteProtect CTA links, tracking events, OGP images, and AdSense-sensitive pages while editing code
Internal business toolStandardize DB seed, queues, mocks, and test commands so a new developer can run it in 30 minutes

For Docker-heavy projects, continue with Docker Compose setup. For team workflows, read team collaboration. For CI, connect the same verification commands to CI/CD setup.

Failure Modes to Catch Early

Mixed package managers are the most common source of drift. If the repository has pnpm-lock.yaml, do not let an agent run npm install. Put the rule in CLAUDE.md, keep packageManager in package.json, and deny ad hoc install commands if the team needs stricter control.

The second failure is secret exposure. .env.example is reviewable; .env is not. Use .gitignore and permissions.deny together. Claude Code can still help by scanning source code for required environment variable names and updating .env.example with dummy values.

Docker volumes are another trap. A stale database volume can make a migration look broken when the schema is simply old. Ask Claude Code to explain the target volume and risk before suggesting any removal command.

Avoid bypassPermissions on your host machine. It is useful only inside an isolated VM or container where file damage is contained. Start in plan or default, then approve only the commands needed for the task.

Finally, inspect hooks in untrusted repositories before starting a session. Hooks run automatically, so a copied .claude/settings.json deserves the same review as a shell script.

Reproducibility Checklist

  • claude --version and claude doctor pass
  • .nvmrc or .node-version exists
  • package.json contains packageManager
  • Only one lockfile is present
  • .env.example is current and .env is ignored
  • CLAUDE.md documents setup, forbidden actions, and verification commands
  • .claude/settings.json denies secret reads, git push, and destructive commands
  • Hooks are short, readable, and committed with the project
  • The final receipt includes commands run and test results

Monetization Note

Environment setup affects revenue work too. A broken local setup can silently break pricing pages, analytics events, purchase links, or newsletter forms. If you are turning Claude Code into a repeatable content or product workflow, start with the free cheat sheet, use the templates in products, or bring the workflow into a team through training.

Result From Trying This

I tested the flow by creating the minimal project, installing dependencies, copying .env.example, and running pnpm run doctor, pnpm run check:env, and pnpm test in that order. The most useful safeguards were the .env deny rules and the hook that blocks git push or destructive shell commands. In Masa’s day-to-day workflow, setup failures usually come from missing assumptions rather than missing commands, so the key improvement is keeping those assumptions in committed files.

#claude-code #dev-environment #setup #automation
Free

Free PDF: Claude Code Cheatsheet

Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.

We handle your data with care and never send spam.

Level up your Claude Code workflow

Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.