DEV Community

Conor Dobbs
Conor Dobbs

Posted on • Originally published at tools.thesoundmethod.me

Claude Code's hidden config: what the docs don't tell you (and what to ignore)

A developer recently sat down and read through Claude Code's source, then wrote up everything they found that the official docs gloss over. It hit the front page of Hacker News with a few hundred points, and the comment section did the thing every "I read the source" post does. Half the room was delighted, the other half pointed out that "undocumented" and "you should rely on this" are not the same sentence.

Both reactions are right. There genuinely is a layer of Claude Code configuration that most people never touch, and most of it is documented. It's just buried, or split across the settings page and the hooks reference where you'd never connect the two. A smaller slice is reverse-engineered from the source and should be treated as exactly that: interesting, not load-bearing. Here's the honest version of what's worth knowing, and where the line sits.

The config layers nobody reads past

Almost everyone configuring Claude Code stops at three things: a CLAUDE.md file with project instructions, maybe a permission allowlist so it stops asking before every npm command, and the model picker. That's the 90% case and it's fine.

The official settings documentation goes a fair bit deeper than that, and this is the part people miss. Every environment variable you can set on the command line can also live in settings.json under the env key. That means you can roll a setting out to a whole team by committing it to the project's .claude/settings.json instead of asking everyone to export it in their shell. Permissions are the other underused piece. They don't override across scopes the way most config does. They merge. Your user-level rules, your project rules, and any managed settings all stack. That's why a permission you "removed" sometimes still applies: it's set somewhere else in the stack.

If you've ever wondered why your teammate's Claude Code behaves differently from yours on the same repo, this is usually the answer. It's not the model. It's three settings files merging in an order nobody mapped out.

Hooks are where the real power is, and the real footguns

Hooks are the feature that separates people who think Claude Code is a chat box from people who've turned it into a build system. They run your code at specific lifecycle points: before a tool runs, after an edit, when the session starts, when Claude is waiting on you.

The official hooks reference now documents several hook types, and this is genuinely worth internalizing. A command hook runs a shell command. A prompt hook sends a single-turn question to a model and gets back a yes/no JSON decision, which is useful when "should this be allowed" is a judgment call rather than a regex. An agent hook spawns a subagent that can read files with Grep and Glob before it decides. That progression from regex, to a quick model call, to a full agent is the part the docs do explain, and it's the part most people don't know exists.

The reverse-engineering write-up goes a step further and claims hooks can return richer JSON to steer behavior mid-run: a PreToolUse hook handing back a permissionDecision to force allow or deny, an additionalContext field to inject text, or updatedInput to rewrite a command before it executes. Some of this maps cleanly onto documented behavior. Some of it, like background async hooks or a once flag that fires a hook a single time and then removes itself, is the author's reading of internal fields. Treat that tier as a lead to verify, not a config you ship to production. The whole reason the docs draw a line is that internal field names change between releases without warning, and a hook that silently stops firing is worse than no hook at all.

There's also a security dimension here that's easy to skip past. HTTP hooks can interpolate environment variables into request headers, and the settings now let you restrict which variable names a hook is allowed to read. If you're wiring Claude Code into anything that touches a real secret, that allowlist is not optional. It's the difference between a hook that sends an auth token to one endpoint and a hook that can read your whole environment.

Why this matters more than it looks

I spend a lot of time in the weeds of tools like this, comparing what a product claims it does against what it actually does when you run it, and Claude Code is a near-perfect case study in a pattern I see constantly: the gap between the deck and the deployment. The marketing surface is "it writes code." The actual product is a configurable runtime with a permissions model, a lifecycle hook system, and a settings hierarchy that merges across three scopes. Most of the value is in that second description, and almost none of it is in the onboarding.

The "I read the source" genre exists because of that gap. When the documented surface is smaller than the real one, somebody eventually goes spelunking and writes up what they find. That's healthy. But the takeaway isn't "go set the undocumented flags." It's "the documented-but-buried 80% is already more than you're using." Get your permission rules merging the way you intend. Move your team's env config into the committed settings file. Replace one brittle regex hook with a prompt hook. That's a week of real workflow improvement before you ever need to touch anything reverse-engineered.

If you want the version that doesn't require reading either the source or a 3,000-word teardown, that's exactly the kind of thing I keep collecting: the configs, hook patterns, and CLAUDE.md setups that actually move the needle, written down so you can paste them in and move on. There's a running set of Claude Code recipes and a tools directory over at tools.thesoundmethod.me if that's useful to you.

The short version: Claude Code is more configurable than its docs make it look, the best wins are in the documented-but-overlooked layer, and "undocumented" is a reason to verify, not a reason to trust. Read the official references first. Save the source-diving for when you've already outgrown them.

Sources

Top comments (0)