How I handle API keys and secrets in Claude Code sessions
The short version: I don't put secrets in the prompt. The longer version is how I make that work in practice.
The problem
Claude Code needs context to work. That context often needs to include information about how to connect to services — database connections, API endpoints, auth patterns. But actual credentials shouldn't go in the prompt or in files the agent reads.
What I do instead
Environment variable references, not values. Instead of "connect to PostgreSQL at postgres://user:password@host/db," I write "connect to the database using the DATABASE_URL environment variable." The agent knows to use the variable, not to invent a connection string.
Placeholder patterns. When I need the agent to write code that makes API calls, I write "use the API_KEY environment variable" in the task prompt. The agent will write process.env.API_KEY or the equivalent, not try to hardcode something.
Secret-free CLAUDE.md. My CLAUDE.md has "Never hardcode credentials. Always use environment variables for secrets." This is in the core file that loads every session. The agent follows it.
For existing code with hardcoded secrets
If I'm working on code that already has hardcoded secrets (it happens in legacy code), I use placeholders when sharing context: "The API key is currently hardcoded as [REDACTED] — we'll move it to an env variable in a separate task."
The agent doesn't need to know the actual value to help me refactor where it's used.
The review step
Before reviewing any output that touched API calls or authentication, I check for hardcoded strings that look like credentials. Specifically: anything matching sk_, pk_, api_key, long hex strings, or base64 that doesn't look like encoded content.
Most of the time the agent follows the env variable pattern correctly. But "most of the time" isn't "always," and a hardcoded key committed to a repo is an expensive mistake.
What I never do
Paste a real credential into a prompt "just to test something quickly." The path from "just testing" to "in a commit somewhere" is shorter than it seems.
From running Claude Code on builtbyzac.com.




