OCDevel
WalkPodcast
The logo for OCDevel Claude Code features clean, modern typography paired with minimalist developer-centric iconography representing the Claude command-line interface.
OCDevel Claude Code Podcast
The OCDevel Claude Code Podcast is a technical show for software developers using Anthropic's Claude Code CLI and developer tools in production. Over a structured 30-episode series, the show teaches you how to move from running a single manual terminal session to orchestrating fully automated pipelines. Learn how to configure CLAUDE.md, manage permissions in settings.json, build custom slash commands, connect MCP servers, and set up autonomous review-and-fix loops. Subscribe to learn how to build a system where Claude safely implements features, runs tests, and deploys to production for you.
CTA
Generated with OCDevel PodcasterMade with OCDevel Podcaster
This show was made with OCDevel Podcaster — turn any topic or text into an AI-narrated podcast episode that drops right into your feed.Turn any topic into an AI-narrated episode in your feed.Create your own →Create your own →

Permissions, settings.json, and plan mode: making one Claude Code session safe

3h ago

You can't automate a tool you don't trust. This episode is the control surface: where settings live and which file wins, how to write tight allow/ask/deny permission rules (the real fence, not CLAUDE.md), the permission modes and the Shift+Tab plan-to-act toggle, and the slash commands a power user reaches for first, including the /rewind safety net. Plus the one pitfall everyone hits: the overly broad Bash(*) allow rule.

Show Notes

Episode 1 got a session running. This one makes it safe to leave running. We cover the control surfaces that turn Claude Code from a sharp tool you babysit into one you actually trust.

Settings files and precedence. The four scopes you touch (~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json, and enterprise-managed settings), which file wins when they collide, and the catch that permission rules merge across layers instead of overriding, with deny always winning. See the settings reference.

The permission grammar. Why rules are enforced by Claude Code, not the model, so CLAUDE.md is advice and permission rules are the fence. The allow/ask/deny lists and their deny-first evaluation order. Bash glob patterns and the space-before-star word boundary, compound-command parsing, wrapper stripping (and the devbox run footgun), and gitignore-style path anchors for Read/Edit/Write. From the permissions reference.

Modes and the plan-to-act toggle. default, acceptEdits, plan, plus auto, dontAsk, and the genuinely dangerous bypassPermissions (--dangerously-skip-permissions). The Shift+Tab cycle, the plan-mode workflow, and editing a proposed plan with Ctrl+G. See the permission modes reference.

Slash commands a power user hits early. /clear vs /compact, /context, /config (where the removed /vim moved), /model, /permissions, /cost (now an alias for /usage), /review and /code-review, and the safety net of the episode: /rewind and double-Esc, plus the checkpointing gotcha that bash-modified files aren't tracked.

The pitfall: the overly broad Bash(*) allow rule, why argument-constraining Bash patterns are fragile, and the deny-curl-use-WebFetch pattern instead. If you've stopped seeing prompts but never wrote specific allow rules, that's your cue to open /permissions and find what's too wide.

Transcript

In the first episode we got a session running and pointed it at a repo. You learned the core loop, you wrote a CLAUDE.md so Claude knows your project, you ran /init to generate one, and you used /resume to pick a conversation back up. That's enough to be productive. It is not enough to be comfortable.

Because here's what happens next. You let Claude run for an afternoon, and somewhere in there it runs a command you didn't expect, or it edits a file you wanted to protect, or you get so tired of approving every single shell command that you reach for the one flag that turns all the prompts off, and now it's writing wherever it wants. The thing standing between "this is a sharp tool I trust" and "this thing scares me a little" is configuration. Today is about the control surfaces.

So this whole show is about one climb, from you driving a single session by hand all the way up to a pipeline that ships code while you're at the beach. You can't automate something you don't trust. And you can't trust something whose blast radius you can't describe. So before we ever talk about loops and fleets, you need to be able to answer three questions cold. What can Claude touch without asking? What will it stop and check with me about? And when it does something I didn't want, how do I roll it back? Settings, permissions, modes, and a handful of slash commands answer all three. Let's go.

Where settings live, and who wins

Claude Code reads its configuration from layered JSON files, and the layering is the part people trip on, so let's get it straight up front. There are four files you'll actually touch, plus a fifth tier your IT department might control.

Start with the two project files, because they live in your repo and they cause the most confusion. There's a file at dot claude slash settings dot json, your project settings, and that one is meant to be committed to git and shared with your whole team. Right next to it is dot claude slash settings dot local dot json, with the word local in the name, and that one is personal. Claude Code adds it to your gitignore automatically. So the rule is simple. The plain settings file is the team's. The local settings file is yours, and your teammates never see it. When you want an allow rule that's just for you, the local file is where it goes. When you want a rule the whole team should share, the committed file is where it goes. Mixing those two up is the single most common settings mistake, and we'll come back to it.

Above the project, there's your user settings, at tilde slash dot claude slash settings dot json, in your home directory. Those are your personal defaults across every project on your machine. And above everything, there's a managed settings file that an enterprise can deploy, in a system location, that nobody can override. Most of you won't have that one, but it matters for one reason I'll get to in a second.

Now, precedence. When the same setting is defined in more than one place, who wins? From the top down, it goes like this. Managed enterprise settings beat everything, including command line flags. Then command line arguments you pass when you launch, things like dash dash model or dash dash permission dash mode, which act as temporary overrides for that session. Then your local project settings. Then the shared project settings. And at the bottom, your user settings. So a flag beats a file, and a more specific file beats a more general one. That's the mental model for most settings.

But permissions are special, and this is the nuance worth slowing down for. Permission rules don't override across layers. They merge. The allow list, the deny list, the hooks, all of those array fields get concatenated together from every file and deduplicated, not replaced. So a deny rule in the team's project file and an allow rule in your personal user file both apply at the same time. And as we'll see, when an allow and a deny collide, the deny always wins. Anthropic's settings reference says it flatly. If a tool is denied at any level, no other level can allow it. That's a safety property you actually want. Your security team can put a deny in the managed file, and nothing you write in your own settings can punch a hole through it.

One more practical thing about these files. Most settings reload live while you're in a session. Change a permission rule, change an environment variable, and it takes effect without a restart. But a couple are read once at startup. The model is the big one, so if you want to switch models mid session you use the slash model command instead of editing the file. And while we're here, there's a separate file, tilde slash dot claude dot json, sitting in your home directory, not inside the dot claude folder. That one is not your settings. It holds login state, your MCP server config, and per project caches. People find it, assume it's where settings go, and get confused. It isn't. Leave it alone.

So what's actually in a settings file? At the top you'll often see a schema line, which just points your editor at autocomplete so you get suggestions as you type. Then a model name. Then the big one, a permissions block, which we're about to spend real time on. There's an env block for environment variables that get passed to every session and every subprocess Claude spawns. There's a cleanup period in days, which controls how long old session files stick around before they're deleted, thirty by default. And there's an editor mode setting, which can be normal or vim, and that last one matters because of a change I'll flag later. For now, the shape is what counts. A model, a permissions block, some environment, some housekeeping.

The permission grammar

This is the safety core of the whole episode, so let me start with the one sentence that reframes everything. Permission rules are enforced by Claude Code itself, the program, not by the model. Anthropic's permissions reference is emphatic about this. Instructions in your prompt or your CLAUDE.md shape what Claude tries to do, but they don't change what Claude Code allows. So your CLAUDE.md is advice. It's a strong nudge, and Claude generally follows it. But it is not a fence. The permission rules are the fence. If you write "never touch the production database" in CLAUDE.md, that's a suggestion the model can drift away from. If you write a deny rule, that's a wall the program enforces no matter what the model decides. Hold onto that distinction. It's the reason this section exists.

Inside the permissions block there are three lists. Allow, which runs without asking. Ask, which prompts you for confirmation every single time. And deny, which blocks outright. When Claude wants to use a tool, the lists are checked in a specific order. Deny first, then ask, then allow, and the first match wins. Deny always takes precedence. So if a command matches both an allow rule and a deny rule, it's denied, full stop.

There's a subtle behavior here worth a beat. If you put a bare tool name in the deny list, just the word Bash with nothing after it, you don't only block shell commands, you remove the shell from Claude's view entirely. Claude never even sees it as an option. But if you write a scoped deny, Bash with something in parentheses like remove space star, the tool stays available and only the matching commands get blocked. Bare Bash and Bash open paren star close paren mean the same thing, total removal. Sometimes that total removal is exactly what you want. Often it isn't, because you still want Claude running your tests.

Now the rule format itself. Every rule is either a plain tool name, or a tool name with a specifier in parentheses. Let's walk the tools you'll write rules for most.

Bash rules use glob patterns, with a star as the wildcard, and the star can sit anywhere. So a rule that reads Bash, open paren, npm run test, space, star, matches any command that starts with npm run test. A rule of npm space star matches anything starting with npm and a space. Star space install matches anything ending in space install. And here is the gotcha that bites everyone exactly once. The space before the star is doing real work. A rule of ls space star, with the space, matches ls dash l a, but it does not match the command lsof, because the space is a word boundary. Drop the space, write ls star with no gap, and now it matches both ls and lsof and anything else that starts with those two letters. There's also a shorthand, a colon star at the end of a pattern, which means the same thing as a trailing space star. So ls colon star equals ls space star. But that shorthand only works at the very end of a pattern.

Here's the reassuring part, and it's a genuinely good piece of engineering. Claude Code parses your shell commands, it doesn't just string match them. So a rule that allows some safe command does not automatically allow that safe command chained with something dangerous using a double ampersand or a semicolon or a pipe. It recognizes all the shell separators, and each piece of a compound command has to match a rule on its own. So you can't sneak a destructive command in by gluing it onto an approved one. When you do approve a compound command with "yes, and don't ask again," it actually saves a separate rule for each piece, up to five of them.

It also strips a handful of harmless wrappers before matching. If you allow npm test, that rule still matches when the command is prefixed with timeout, or time, or nice, or nohup. Those are recognized as wrappers and peeled off. But, and this is a footgun, environment runners are not peeled off. Things like npx, docker exec, or devbox run are treated as part of the command. So if you write an allow rule for devbox run space star, thinking you're allowing your task runner, you have actually allowed devbox run remove dash r f dot, because everything after devbox run is just arguments as far as the pattern is concerned. Narrow rules around a runner are wider than they look.

One more thing about Bash that saves you a lot of noise. A set of read only built in commands run without any prompt, in every mode, and you can't really make them dangerous. Listing files, printing a file, echo, head, tail, grep, find, word count, which, diff, stat, disk usage, changing directory, and the read only forms of git like git status and git diff. That set isn't configurable. If for some reason you want a prompt on one of those, you add an explicit ask or deny rule for it.

Then there are the file tools, Read and Edit and Write, and these use gitignore style path matching with four different anchors, and the anchors are where people get surprised. A path that starts with two slashes is absolute, from the root of the filesystem. A path that starts with tilde slash is relative to your home directory. A path that starts with a single slash, and this is the trap, is relative to your project root, not the filesystem root. So a rule of slash src slash star star matches source files in your project, not in the system. And a path with no leading slash, or a dot slash, is relative to the current directory. A single star matches within one directory, two stars match recursively, and a bare filename matches at any depth, so a Read rule for dot env quietly means dot env anywhere in the tree. That's good for blocking secrets, since one deny rule covers every dot env file in the project.

There's an honest limitation the docs call out here, and you should know it before you rely on these rules. Read and Edit deny rules cover Claude's own file tools, and they cover file commands it recognizes inside Bash like cat and head and tail and sed. But they do not cover an arbitrary subprocess. If Claude runs a Python script or a Node script, and that script opens a file directly, the file permission rules don't see it. For protection at that level, across every process, you need the sandbox, which is a later episode. For now, just hold the boundary in your head. File rules guard Claude's hands, not every program Claude can start.

Two more tool types worth naming quickly. Web fetch rules are scoped by domain, so you write WebFetch, open paren, domain colon, then the domain. But allowing web fetch doesn't lock down the network, because if Bash is allowed, Claude can still curl or wget any URL it likes. And the MCP server tools, which a later episode owns, use a double underscore naming scheme, where mcp underscore underscore then the server name matches every tool from that server, and adding another double underscore and a tool name targets just one. I'm planting that flag now so it's familiar when we get to MCP.

So how do you manage all this without hand editing JSON? You run the slash permissions command. It opens an interactive dialog where you can see your rules grouped by scope, add and remove them, manage your working directories, and review what got denied recently. And every time you answer a prompt with "yes, and don't ask again," Claude writes one of these rules for you, automatically, into your local settings. That's actually how most of your allow list gets built over time. You approve things as you hit them, and the rules accumulate.

The modes, and the plan to act toggle

Permission rules are the fence. The mode you're in sets the baseline behavior, what happens by default before any rule is checked. There are six of them, from Anthropic's permission modes reference, and you'll live in three.

Default mode is where you start. It prompts you the first time Claude uses each kind of tool, reads run free, and it's the right mode for sensitive work and for getting your bearings. Accept edits mode is the workhorse of a focused coding session. It auto accepts file edits, and it auto accepts the common filesystem commands like making a directory, touching a file, moving and copying, for paths inside your working directory. Other shell commands still prompt, and anything reaching outside your project still prompts. Your status bar shows a little double arrow and the words "accept edits on" so you always know you're in it. This is the mode for when you're iterating on code that you're going to review afterward with git diff anyway, so the per edit prompts are just friction.

Plan mode is the third one you'll use constantly, and it's the heart of today's workflow. In plan mode, Claude can read files and run read only commands to explore your codebase, and it writes up a plan for what it intends to do, but it does not edit your source. It looks before it touches. That's the whole point.

The other three modes are situational. There's an auto mode, newer, that auto approves everything but runs a separate classifier model that reviews each action before it happens and blocks anything that escalates past what you asked for, or targets infrastructure it doesn't recognize, or looks like it's being driven by hostile content in a web page. It needs a recent enough version and a recent model, and it's API only right now, and it's explicitly a research preview, so it reduces prompts, it does not promise safety. There's a don't ask mode that does the opposite, it auto denies everything you haven't pre approved, fully non interactive, which is what you'd want in a locked down script. And then there's bypass permissions mode, the dangerous one.

Let me spend a real moment on bypass, because it's the trap you'll be tempted by around week two. Bypass permissions skips all prompts and all the safety checks. The flag for it is dash dash dangerously dash skip dash permissions, and they named it that on purpose. As of a recent version it even allows writes to protected paths. The only circuit breaker that survives is that remove dash r f of your root or your home directory still prompts. There's no protection against prompt injection in bypass, none, so if Claude reads a malicious instruction off a web page or a file, there's nothing to catch it. The honest use for this mode is an isolated container or a throwaway VM, a machine with nothing on it worth damaging. It refuses to even start as root. And if you want to make sure nobody on your team, including future you on a tired afternoon, can use it, there's a setting to disable bypass mode entirely. The point I want to leave you with is this. When you're reaching for that flag on your actual laptop because you're sick of the prompts, that's the recognition cue that you've taken a wrong turn. The right answer for prompt fatigue is accept edits plus a few targeted allow rules, not turning the safety off.

Now the workflow that ties modes together, and it's something you do with one keystroke. In the CLI, you press shift and tab to cycle through modes. It goes default, then accept edits, then plan, and back around. The current mode shows in your status bar so you always know where you are. The optional modes, bypass and auto, only slot into that cycle after plan when you've enabled them, and don't ask never joins the cycle at all. So the everyday rhythm is, shift tab to drop into plan mode, let Claude explore and propose, read the plan, and then approve it, which kicks you into a mode that actually does the work.

That approve step is the plan to act transition, and it's worth describing because it's the spine of how a careful developer drives this tool. You enter plan mode with shift tab, or you can prefix a single prompt with slash plan to enter and start in one move. Claude researches and comes back with a plan and a set of choices. You can approve it and let it run in auto mode. You can approve and accept edits. You can approve but review each edit by hand. You can keep planning and give feedback. Approving exits plan mode and switches you into whichever mode that choice described, and that's the moment Claude goes from thinking to doing. If you don't like the plan, shift tab again backs you out without approving anything. And there's a nice touch, you can press control g to open the proposed plan in your own editor and rewrite it directly before Claude proceeds, so you're not stuck accepting the plan exactly as written.

That loop, plan, read, edit the plan if you need to, then approve into action, is the single most valuable habit from this episode. It's the difference between Claude surprising you and Claude doing roughly what you already agreed to. Build the muscle memory now, because every later episode, the orchestration, the autonomous loops, all of it, is built on this same plan then act shape, just with more of it running unattended.

The slash commands you'll actually use

You met a few commands in episode one. Let's fill out the set a power user reaches for in the first week. You can always type a single slash to see the whole list, and a command is only recognized at the very start of a message, with anything after it passed along as arguments.

Start with the two that manage your conversation, because people constantly use the wrong one. Slash clear starts a completely fresh conversation with empty context. The old one isn't gone, it's still there under slash resume, but your new conversation starts clean. Slash compact does something different. It summarizes the conversation so far to free up room, optionally with instructions about what to focus the summary on, and then keeps going in the same conversation. So the rule of thumb is, compact when you want to keep working on the same task but you're running low on context, clear when you're switching to a new task. Paired with those is slash context, which draws your context window usage as a colored grid and tells you when you're getting full. Glance at it, and when it's filling up, compact.

For configuration, slash config opens the settings interface, where you set your theme, your model, your output style, and your editor mode. And that editor mode is worth a callout, because the old slash vim command was removed earlier this year, in an early-2026 release. So if you go looking for slash vim to turn on vim keybindings and it's gone, that's why. It moved into the config screen, or you set editor mode to vim in your settings file directly. Slash model switches your model and saves it as the default, or you can press a key to make the switch session only.

Then the commands that surface what's happening. Slash permissions, which we already covered, your allow and ask and deny manager. Slash cost, and here's another rename to know about, slash cost is now just an alias for slash usage, which shows your session cost, your plan usage against your limits, and on paid plans a breakdown by skill and subagent and MCP server. So if a teammate says slash cost and you only find slash usage, they're the same thing now.

A few that point forward to later episodes, so I'll just name them. Slash agents manages your subagent configurations, which is the subagents episode. Slash mcp manages your MCP server connections, which is the MCP episode. Slash hooks shows your hook configuration, and hooks get their own episode too. I'm naming them so they're not strangers when we arrive, not teaching them today.

And the review commands, which you'll grow into. Slash review reviews a pull request right inside your current session. That's distinct from slash code dash review, which is a bundled skill that looks at your current diff for bugs and cleanups, and it takes options, including one to apply the fixes for you and one to post the findings as inline comments. There's also a deep cloud based version of that review you invoke by adding the word ultra. And there's slash security dash review, which scans your branch's changes specifically for vulnerabilities. You don't need these in week one, but know they exist, because review running locally is the seed of the review and fix loops we build in act two.

Now the command that turns this whole tool from scary into safe, and it's the one I most want you to remember from today. Slash rewind. It rewinds your conversation, or your code, or both, to an earlier checkpoint. You open it with slash rewind, or just by pressing escape twice on an empty prompt. Here's why it matters. Every time you send a prompt, Claude Code automatically creates a checkpoint, per the checkpointing docs. So when Claude goes three steps down a wrong path and mangles a file, you don't panic and you don't dig through git. You rewind to before it started, and you can choose to restore just the code, just the conversation, or both. Checkpoints persist across sessions and get cleaned up after thirty days.

But, and this is the pitfall attached to the command, checkpointing only tracks files that Claude changed through its own editing tools. It does not track files changed by a bash command. So if Claude moved or deleted or overwrote a file by running a shell command rather than by editing it, rewind will not bring that file back. Git is still your real safety net for anything that happened through the shell. Rewind is fast and convenient for the common case, edits gone wrong, and it is not a substitute for committing your work.

A handful more you'll meet early and should recognize. Slash doctor diagnoses your install and your settings, and it can offer to fix what it finds. Slash status shows your version, model, account, and connectivity, and it works even while Claude is mid response. Slash diff is an interactive viewer for your uncommitted changes. Slash export saves the conversation as plain text. And one more rename to file away, custom slash commands have merged into skills, so while a markdown file in dot claude slash commands still creates a command, skills are the forward looking form, and that's the skills episode.

The pitfall to leave with

If you take one warning from this episode, make it this one. The overly broad allow rule. It is so tempting, around your second week, to just write an allow rule of Bash open paren star, or bare Bash, and make all the prompts go away. Don't. That hands Claude every shell command there is, including piping a downloaded script straight into a shell, force pushing, removing files, all of it, with no prompt and no record that you ever decided to allow it.

And here's the part that makes it worse than it looks. Trying to write a narrow Bash rule by constraining the arguments is genuinely fragile, and the docs are honest about this. A rule meant to allow curl to one specific URL won't catch a different flag order, or the https version, or a redirect, or the URL stuffed into a variable first, or even just extra spaces. So the right pattern, straight from Anthropic's guidance, is to deny curl and wget in Bash outright, and use web fetch scoped to the domains you actually trust, or reach for a hook. Allow the specific commands you run all day, your linter, your tests, your build, by name. Deny the sharp things explicitly. And let everything else prompt.

The recognition cue is simple and you can check it right now. If you've stopped seeing permission prompts entirely, and you never sat down and wrote specific allow rules for the commands you run, then something too broad is in your allow list, and you should open slash permissions and find it. A session you trust isn't one that never asks. It's one where you know exactly why it's quiet.

That's the control surface. You know where settings live and which file wins. You know that permission rules, not your CLAUDE.md, are the real fence, and how to write them tightly. You know the modes, and the shift tab rhythm of planning before acting. And you know that when it all goes sideways, escape escape gets you back. Next time we start turning these controls into automation you can walk away from. But it starts here, with a session you can describe down to the command. Put the broad allow rule down, write the narrow ones, and you've earned the right to trust what comes next.