DEV Community

Naimul Karim
Naimul Karim

Posted on Edited on

A Practical Guide to CLAUDE.md, Permissions, Plan Mode, Skills, and Sub-Agents

If your Claude Code routine is "type a feature request, hit enter, hope for the best," you're leaving most of the tool on the table. Typing build this feature works, but it's the shallowest way to use an agent that can read your repo, run your tests, and check its own work.

The difference between "I use AI to code" and "I work well with an AI agent" comes down to a handful of features: CLAUDE.md, permissions, plan mode, skills, and sub-agents. The trick is not to switch them all on at once. Each one earns its place when a real problem shows up. This post walks through them in the order you'd naturally need them.

First, what makes Claude Code different from chatting with Claude?

In a normal chat, you paste code in and paste answers out. Claude Code lives inside your project. It can read files, search the codebase, edit code, run terminal commands, use git, and run your tests to check whether its own change worked.

So instead of copying a service class into a chat window and explaining the surrounding system, you can say:

"Invoices can be marked as paid twice. Find out why and fix it."

and it will go hunting through the invoice and payment code on its own, change what needs changing, and run the tests.

Under the hood it follows a simple loop: gather context → take action → verify. Watch the tool calls scroll by (Read, Grep, Glob, Edit, Bash) and you'll know exactly what it's investigating. And if it's heading the wrong way, hit Esc and correct it mid-flight rather than waiting for the whole thing to finish.

A quick privacy note: "runs locally" doesn't mean nothing ever leaves your machine. Relevant file contents still get sent to the model so it can reason about them. If it's your employer's code, check the data policy of the account you're using.

Step 1: Give it a memory with CLAUDE.md (or AGENTS.md)

Close your session, come back tomorrow, and Claude has forgotten how you run the tests, that you chose Entity Framework Core, and that you already corrected it twice about the same thing. The fix is a markdown file at the root of your project that gets loaded at the start of every session.

Claude Code reads CLAUDE.md, and it now falls back to AGENTS.md if there isn't one, which is nice because that's the convention many other coding tools already use.

A few things worth knowing:

  • It's an attention budget. Everything in that file competes for space in the context window. Keep it lean. Under 200 lines is the usual advice, and 30 to 40 is even better.
  • Be specific, not inspirational. "Write clean code" tells Claude nothing. "Controllers live in src/Api/Controllers" and "run dotnet test before finishing" do.
  • Only include what Claude can't discover itself. It can see you use EF Core from the .csproj. It can't know that money is always stored as integer cents, or that every endpoint needs an authorization policy.
  • There are layers. Personal rules in your home .claude folder, shared project rules in the repo root, and a local file for your own sandbox URLs that stays out of git. Big monorepos can have nested files that only load for the area you're working in.
  • Start with /init, then actually read what it generates and trim it.
  • Keep it honest. A stale file that points to folders you moved is worse than no file at all.

One more concept that's easy to underestimate: context rot. Output quality can start slipping long before the window is full. A model with a 200k window might already show degradation around 50k tokens. So when you move to something unrelated, run /clear. Use /compact only when you're continuing the same work but want a smaller footprint. And /context shows you where your space is going.

Step 2: Control what it can do with permissions

Here's the catch with CLAUDE.md: it's guidance. If you write "never read the production settings file," Claude will probably obey, but nothing technically stops it. For hard boundaries you need permissions, which the tool itself enforces.

There are three rule types, checked in the order deny → ask → allow:

{
  "permissions": {
    "allow": ["Bash(dotnet build)", "Bash(dotnet test)", "Bash(git status)"],
    "ask": ["Bash(git push:*)", "Bash(dotnet ef database update:*)"],
    "deny": ["Read(./**/appsettings.Production.json)", "Read(./**/secrets.json)"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Save that as .claude/settings.json and you've got a sensible baseline: routine builds and tests run without nagging you, pushes and database updates always need your approval, and production config is off limits.

Then test it. Drop a dummy appsettings.Production.json into the project, ask Claude to read it, and confirm the request gets refused. Claude should tell you the read was blocked instead of hunting for a workaround. Don't assume a rule works just because you wrote it.

You'll also meet different modes along the way (manual, auto-edit, plan, auto), which you can cycle through with Shift+Tab. Manual is great while you're learning what Claude does. Once you trust the setup, a more automatic mode removes the boring prompts. The goal isn't zero prompts. It's zero pointless prompts, while keeping a human in the loop for things that matter.

One habit worth building: put real connection strings into user secrets or environment variables yourself. Never paste them into the chat.

Step 3: Use plan mode when the decision is expensive

Early features like a new endpoint or a UI tweak are easy to review and easy to undo. If you don't like the result, you change it. A database schema is a different animal. Migrations, relationships, and how something like invoice status is represented are costly to rework once code is built on top of them.

That's what plan mode is for. Claude can read, search and research, but it can't touch your source until you approve a plan. Imagine asking for a PostgreSQL + Entity Framework Core setup with only customers, invoices and line items, and explicitly ruling out recurring billing, tax rules and multi-currency for now. Claude would spin up an exploring sub-agent, ask a few clarifying questions (should payment status be stored or derived from payments? where do line items live?), and come back with a plan.

The lesson that matters most: read the plan. Approving without reading gains you nothing. A weak plan says "add database, add invoices, update API." A good one names tables, relationships, files to change, the migration approach, and how it'll verify the result. You can even open it in an editor with Ctrl+G and edit it directly.

Catching "you're over-engineering this" in the plan takes seconds. Catching it after the entities, migrations and API changes exist takes a lot longer.

Two other pointers:

  • Don't use plan mode for everything. Changing a heading doesn't need a ceremony.
  • After a big decision, update CLAUDE.md with only the conventions future sessions need to remember, such as the migration command and where entity configurations live.

Step 4: Turn repeated processes into skills

By the time you've added a handful of API endpoints, you notice you keep saying the same things: look at how existing controllers are structured, reuse the validation and error-handling patterns, write tests alongside, verify when done. Pasting that checklist into every prompt gets old.

A skill is a folder with a SKILL.md that Claude loads only when relevant. The rule of thumb is simple:

  • Project fact ("run tests with dotnet test", "use Entity Framework Core for data access") → CLAUDE.md
  • Repeatable process ("inspect, reuse, build, verify") → a skill
  • One-off task → just ask
---
name: add-endpoint
description: Add or modify a REST API endpoint following the project's controller, validation, error-handling and testing conventions. Use when creating a new endpoint or significantly changing an existing one.
---

Add or update the following endpoint: $ARGUMENTS

1. Inspect an existing, similar endpoint and its tests first.
2. Reuse the existing request/response models, validators and error format.
3. Keep business logic in the service layer, not the controller.
4. Add unit and integration tests, run `dotnet test`, then summarize.
Enter fullscreen mode Exit fullscreen mode

The description is the most important line. Claude uses it to decide whether the skill applies. A vague one means it won't trigger when you expect it to.

After that, something like /add-endpoint GET /invoices/{id}/pdf gives you a result that matches your existing code, and /add-endpoint POST /customers follows right after with the same process. Same workflow, different feature.

A few more skill tips:

  • Skills load in layers (metadata first, then the main file, then extra reference files only when needed), which keeps your context light.
  • For anything with side effects, like deploy or commit, you can disable automatic invocation so only you can trigger it.
  • Don't hoard them. Every skill adds metadata Claude has to consider.
  • Read third-party skills and plugins before installing. They can contain scripts and tool access.
  • Don't try to write the perfect skill on day one. Use it, notice where Claude still slips, then sharpen it.

Library maintainers and vendors can ship their own skills and plugins too. A skill is one reusable process, while a plugin is a package that can bundle skills plus other capabilities such as MCP servers.

Step 5: Hand off investigations to sub-agents

Eventually the codebase is big enough that, before building something like an audit log, Claude would need to understand your entities, how the current user flows through a request, background jobs, error handling and the test setup. If it researches all of that in your main conversation, every file read and search result piles up in the same context you need for the actual build.

A sub-agent is a separate Claude instance with its own context window. It takes a focused task, explores, and reports back only the useful findings. That's the entire value: context isolation. It's not a smarter Claude, and it doesn't gain expertise from a fancy job title. "Senior staff elite security architect" is just decoration. The useful question is: what work can happen separately that my main conversation doesn't need to carry?

For the audit-log idea, you could ask for five independent investigations, with an explicit "don't implement anything yet":

  1. The entity model and DbContext
  2. How authentication and the current user identity are resolved
  3. Existing background jobs
  4. The logging and error-handling middleware
  5. The test fixtures and conventions

None of these depend on each other, so they can run in parallel and come back as one combined summary. That's usually faster than a single agent working through them one after another, and your main context only receives the conclusions.

Claude Code also has built-in agent types such as Explore (read-only investigation), Plan, and a general-purpose one. You don't have to call anything special. Just tell Claude what to delegate.

Afterward, scope the first version tightly: record who changed what and when for create, update and delete on invoices, and nothing else yet, so no retention policies, search UI or export. And remember that identity must come from the server. The user ID in an audit entry should be taken from the authenticated principal, never from a value the client sends. That's exactly the sort of thing to verify in the plan.

Step 6: Spawn a sub-agent to review the code

Sub-agents aren't only for research. One of the most useful jobs you can give one is reviewing what the main session just wrote.

Why not just ask the same session to "check your work"? Because it's carrying the whole conversation: every assumption, every shortcut, every reason it chose approach A over B. It tends to agree with its own decisions. A fresh sub-agent starts with a clean context and sees the diff the way a new teammate would, with no attachment to how it got there.

You can do it with a plain prompt:

"Spawn a sub-agent to review the changes on this branch against main. It should check correctness and edge cases, security (authorization, input validation, secrets in logs), missing tests, and whether the code follows the conventions in CLAUDE.md. It must not modify any files. Return findings grouped by severity, with file and line references."

If you do this often, define a reusable reviewer in .claude/agents/code-reviewer.md:

---
name: code-reviewer
description: Reviews code changes for bugs, security issues, missing tests and convention violations. Use after finishing a feature or before opening a pull request.
tools: Read, Grep, Glob, Bash
---

You are a careful code reviewer. Review the current branch's diff against main.

Focus on:
- Logic errors and unhandled edge cases
- Authorization gaps and unvalidated input
- N+1 queries and missing transactions in data access
- Missing or weak tests
- Violations of the conventions in CLAUDE.md

Do not edit files. Report findings by severity (high, medium, low) with file and line,
a one-sentence explanation of the risk, and a suggested fix.
Enter fullscreen mode Exit fullscreen mode

Notice the tools line. A reviewer shouldn't be able to edit anything, so you leave out Edit and Write. That's a small guardrail that keeps the agent doing exactly one job.

Triage before you fix

The findings come back, and the temptation is to say "fix everything." Don't. For each one, decide whether it's real, whether it's relevant, and whether it's worth fixing now:

  • Verify first. Ask Claude to confirm the finding against your actual code and explain the risk in the context of this app, without changing anything. Reviewers can be wrong, or flag a problem that doesn't apply to your setup.
  • Fix now what is real and cheap, especially anything touching auth, data access or money.
  • Write down for later what is real but out of scope. A low-severity finding whose proper fix needs a whole new subsystem shouldn't hijack the current task.
  • Never silently ignore a finding. "Not now" is fine. "Never looked at it" isn't.

A reviewer sub-agent doesn't replace your own review, and it isn't a substitute for dedicated security tooling on sensitive areas like authentication or payments. Think of it as a second pair of eyes that happens to be cheap and fast. You're still the one who decides.

The progression that matters

Looking back, the arc is worth remembering:

  1. Start in an empty folder and give Claude a small, bounded task.
  2. Add project context (CLAUDE.md) once you're tired of repeating yourself.
  3. Add permissions when approval prompts get annoying or secrets need protecting.
  4. Use plan mode when decisions become expensive to reverse.
  5. Write skills when you spot a repeating process.
  6. Use sub-agents when investigation starts crowding your main context.
  7. Use a separate reviewer sub-agent before you trust what was just written.

Don't switch everything on at once. Let the problem you have create the reason to use the feature.

Key take aways

  • Give Claude good context, keep tasks small, and review what it does.
  • Test your guardrails instead of assuming they work.
  • The cheapest place to fix a bad decision is the plan.
  • Have a fresh sub-agent review what the main session wrote, then triage the findings instead of auto-fixing them.
  • Keep your project instructions current, and delete stale ones.
  • Give it more freedom gradually, as you learn how it behaves on your projects.

Beyond these sit parallel agents on isolated git worktrees, external tools through MCP, and hooks that automate checks. Those are next on my list.

Top comments (1)

Collapse
 
laogedev2 profile image
laogedev2 •

Your distinction between project facts in CLAUDE.md and repeatable processes in skills is the part I would push further: a skill description should also state when not to trigger, not only what it does, because vague or overly broad descriptions are what turn a useful skill into background noise. That is especially important once a team shares skills, since the same description will be read in very different codebases and the failure mode is silent non-use rather than an error. One practical habit is to review the description whenever the workflow changes, in the same change as the workflow itself, so the trigger stays aligned with reality. A Chinese-language example of this pattern is the review and README material in the collection at github.com/laolaoshiren/claude-cod..., which treats review as a repeatable checklist rather than a one-off prompt. It is a useful reminder that a skill is only as good as the conditions under which it decides to stay quiet.