This is reported when your login shell is zsh and sandbox.enabled is true. The workaround is one line:
SHELL=/bin/bash claude
The reported symptom is that "every sandboxed Bash tool call fails with Exit code 126 and zero bytes of stdout/stderr, in ~1.3s — including shell builtins (true, type echo)". Shell builtins such as true failing is the tell: it means nothing about your particular command or configuration is at fault.
According to the reporter, the script that runs inside the sandbox uses the bash-only form exec 3<&- || exit 126. Closing an already-closed file descriptor is tolerated by bash but fails under zsh, so the script exits 126 before it ever evaluates your command. That is the reporter's analysis, not documented behaviour.
Aspect
Detail
Conditions
Linux, zsh as the login shell, sandbox.enabled: true
Symptom
Every Bash tool call exits 126 in about 1.3s with no output
Working versions
The reporter verified 2.1.270, 2.1.286, 2.1.289 and 2.1.291
Failing versions
The reporter reproduced it on 2.1.302 and 2.1.309
Workaround
Launch with SHELL=/bin/bash claude
Check the shell before you suspect your settings
The reporter says it reproduces in interactive mode and under -p, in fresh sessions, and with permissions.deny emptied — so trimming permission rules will not help. When you see exit 126 with zero output, check echo $SHELL first.
A commandPrefix deny rule blocks a command name, not an effect. The documentation defines commandPrefix as "A string or array of strings that a shell command must start with" — a prefix filter on the name.
So a deny with commandPrefix = "rm" matches commands starting with rm, but not:
/bin/rm, which starts with an absolute path
xargs rm, which starts with a different command
eval "rm ...", likewise
unlink, a different command with the same effect
The reporter tried 45 rewrites of commands they had forbidden and found that deny rules for six commands let 38 of them (84%) through. Forms such as true; rm file and echo $(cat secret) were caught, so the policy engine behaves as documented. The gap is not in the behaviour but in what readers expect a deny rule to guarantee.
For unattended runs, list what may run rather than what may not, and let everything else fall through to deny or ask_user. In non-interactive mode ask_user is treated as deny, so that fallback fails safe.
A string, or array of strings, the command must start with
commandRegex
A regex against the whole command; cannot be combined with commandPrefix
decision
allow, deny or ask_user
priority
0 to 999; higher wins
commandRegex is tested against the JSON representation
Per the documentation, commandRegex is tested against the JSON form of the arguments, {"command":"<your_command>"}. Because "command":" is prepended, anchors such as ^ and $ apply to the full JSON string, and the docs advise against using ^ here.
A global deny rule — one without an argsPattern — does something stronger as well: the denied tool is completely excluded from the model's memory, so the model never sees it as an option at all. For a tool you want genuinely unavailable, that is the firmer lever.
Q. The desktop app's Authenticate button never saves OAuth tokens for my pre-registered MCP client, though codex mcp login works. Which is the supported path?
The documented way to perform an OAuth login is the CLI command: "For a server that supports OAuth, run codex mcp login <server-name>." The docs say nothing about a button in the desktop app. If the CLI works for you, treat it as the supported path.
Configuration is shared between the three clients — the ChatGPT desktop app, Codex CLI and the IDE extension — and lives in ~/.codex/config.toml by default. A login you complete from the CLI is therefore usable from the other clients that read the same configuration.
For a pre-registered client, pass the client ID when you add the server:
codex mcp add example --url https://mcp.example.com --oauth-client-id my-client
For a confidential client, pass the secret too, read from an environment variable:
The documentation is explicit: "Codex saves the secret as mcp_servers.example.oauth.client_secret in config.toml. Keep that file private and out of version control."
The default callback is http://127.0.0.1/callback. Override the port or URL with mcp_oauth_callback_port and mcp_oauth_callback_url. To pick a registration method for one login, use codex mcp login <server-name> --oauth-client-registration cimd (or dcr); the default is auto, and the choice is not stored in config.toml.
codex mcp list shows configured servers, and /mcp shows their status during a session. For adding servers in the first place, see Adding an MCP server to Codex CLI.
Q. Gemini CLI says a node_modules path "resolves outside the allowed workspace directories" when I run list_directory on it, but it is inside my project. Why?
The message does not describe the actual cause, which is why changing your workspace configuration does not help.
The error reads:
Path not in workspace: Attempted path "/home/you/node_modules" resolves outsidethe allowed workspace directories
It says the path is outside the workspace, but the reported case is a node_modules directory inside the project. Tracing the source, the reporter found that any path containing a node_modules, .git or .env segment is blocked unconditionally, after which the workspace containment check returns false and the tool falls back to the "outside workspace" message. That is the reporter's analysis, not documented behaviour.
Adding directories to the workspace will not fix it, because the cause is different. The documented way to add directories exists for directories genuinely outside your workspace:
gemini --include-directories ../lib,../docs
If you need the agent to look at a dependency's contents, the options today are:
Approach
What to do
Don't pass the path
Ask about the dependency's implementation and let the model locate it
Copy the file in
Copy the specific file into your working directory first
The same message can also mean what it says
If you see this error for a path that contains none of node_modules, .git or .env, it is literally outside the workspace, and --include-directories is the fix. Whether those three names appear in the path is how you tell the two cases apart.
The scope depends on the tool type, and the documentation's table answers it directly.
Tool type
What "Yes, and don't ask again" does
Read-only (file reads, Grep)
N/A — it doesn't prompt in the first place
Bash commands
Permanently per repository and command
File modification (Edit / Write)
Until session end
WebFetch
Permanently per repository and domain
WebSearch
Permanently per repository
When the approval does save permanently, it goes to .claude/settings.local.json at the root of the git repository, resolved through worktrees to the main checkout. A file-modification approval is not written to the file at all; as the table says, it lasts until the session ends.
On the permission mode: no official documentation says that "don't ask again" changes it. There is a separate option for that, the third one on the prompt, labelled "Yes, and switch to auto mode", and the docs note it does not appear on every prompt.
You can switch modes with Shift+Tab and list your current rules with /permissions. Those two are how to check whether anything changed unexpectedly.
One behaviour worth knowing: approving a compound command saves a separate rule per subcommand that required approval. Approving git status && npm test saves a rule for npm test, so future npm test calls are recognised regardless of what precedes the &&. At most 5 rules are saved for one compound command.
For a file path, gitignore pattern characters such as [, ] and * are escaped, so the generated rule matches only the literal path you approved. Rules you write yourself are not escaped.
A rule saved from a prompt covers only what the prompt showed
Some prompts offer a one-time approval only. The documentation explains that the "don't ask again" option appears only when the prompt can show you everything it would allow. For anything broader, write the rule yourself in /permissions.
Start by measuring rather than guessing. /usage gives you the breakdown.
The Session block at the top shows token statistics for the current session. The dollar figure is computed locally from token counts at list price, unless your organization has a modelPricing table in effect, in which case the Total cost line carries the note at your organization's configured rates. For authoritative billing, use the Usage page in the Claude Console.
On a Pro, Max, Team or Enterprise plan, the same screen also breaks down what counts against your plan limits.
Section
What it shows
Attribution
Recent usage attributed to skills, subagents, plugins and individual MCP servers, each as a percentage
Behavior flags
Behaviours such as long context or cache misses, flagged when one accounts for 10% or more of recent usage
Loops
The heaviest /loop or other session-scoped scheduled tasks that ran recently, ordered by total tokens
If long output is the complaint, check first whether Behavior flags shows long context, and whether Attribution puts one MCP server or subagent far ahead of the rest. An MCP server's tool definitions consume context simply by being connected, so a large share there is common.
No documented setting caps comment volume
As of 2026-10-21 there is no settings key in the reference for "write fewer comments" or "be less verbose". The place to put that instruction is CLAUDE.md, and it works better as a concrete standard — "comment only where the intent is not obvious from the code" — than as a bare "be concise".
CLAUDE.md is reloaded from disk at session start and after compaction. An overlong file dilutes its own instructions; see How long should CLAUDE.md be for the sizing guidance.
Q. A command that moved to the background has been running for hours. Is there a setting that gives background commands a time limit in an interactive session?
As far as the official documentation goes, there is no setting that gives background commands a time limit in an interactive session. This is documented behaviour, not a bug.
The tools reference says: "In a session that runs unattended, such as a run with the -p flag, an Agent SDK application, a CI job, or a cloud session, background Bash and PowerShell commands have a time limit. A local session you work in from a terminal, the desktop app, or the VS Code extension has no time limit on background commands."
Session
Time limit on background commands
-p runs, Agent SDK, CI jobs, cloud sessions
Yes (30 minutes by default, 2 hours maximum)
Terminal, desktop app, VS Code extension
None
The split arrived in Claude Code v2.1.288. From v2.1.285 to v2.1.287 the limit applied in every session, so if you remember it behaving differently, that change is why.
On the unattended side the limit can be raised, though neither variable can shorten it:
# Replace the 30-minute default with one hour (unattended sessions only)export BASH_DEFAULT_TIMEOUT_MS=3600000# Raise the 2-hour maximum to four hoursexport BASH_MAX_TIMEOUT_MS=14400000
The one documented way to stop an interactive session running something indefinitely is to disable backgrounding itself:
export CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1
That variable disables the run_in_background parameter, auto-backgrounding at a timeout, and the Ctrl+B shortcut together. A foreground command that reaches its timeout then stops instead of moving to the background. It is a blunt instrument, so it fits poorly with work that involves genuinely long-running jobs.
backgroundDeadlineDisabled is not in the official docs
A setting named backgroundDeadlineDisabled comes up in discussions of this behaviour. As of 2026-10-19 that key appears in neither the settings reference, the environment variable list, nor the tools reference, so it could not be confirmed in the official documentation.
Q. Idle compaction never runs for me. A session well past 200K tokens sat idle for 70 minutes without being compacted, and it never happens in the desktop app's Code tab. What are the conditions?
The settings reference turns idle compaction on by default only for conversations that meet all five of its conditions. Token count and idle time are two of them, so a conversation can satisfy both and still be excluded by another.
Condition
What it requires
Session
An interactive terminal session
Prompt cache
The conversation is on the one-hour TTL
Feature flags
Claude Code can fetch feature flags from Anthropic
Size
The context has reached the threshold, 200,000 tokens by default
Idle time
About 54 minutes since the last request, with your computer awake at that point
The desktop app's Code tab is excluded by the first condition. The documentation names an "interactive terminal session" and says nothing about other session types.
The last condition is the one most easily missed: if the machine sleeps during those 54 minutes, nothing runs when it wakes.
A conversation that was actually compacted shows Compacted while idle, before the prompt cache expired, so that message tells you whether it ran.
To change the threshold or turn it off:
{ "idleCompaction": false}
# Lower the threshold to 150,000 tokensexport CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS=150000
CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS accepts a positive whole number and ignores anything else. Values below 100000 are raised to 100000, the lowest threshold. Both the key and the variable require Claude Code v2.1.290 or later; on an earlier version, setting autoCompactEnabled to false stops it. Turning auto-compact off turns idle compaction off with it.
From v2.1.302, /config has an Idle compaction row you can toggle.
Q. My Codex PreToolUse hook calls sys.exit(2) but nothing is blocked on Windows — the command runs anyway, and PowerShell seems to turn exit 2 into 1. Is there a way to deny reliably?
Codex documents two ways for a PreToolUse hook to signal a block. Use the one that does not depend on the exit code and a shell rewriting it stops mattering.
Option 1 (exit code): the documentation says "You can also use exit code 2 and write the blocking reason to stderr." The word also is a hint that this is the secondary form.
Option 2 (JSON on stdout): emit a hookSpecificOutput object. This works at exit 0.
The docs also accept an older form with a top-level decision set to "block" and a reason string. Note that for PreToolUse, "Plain text on stdout is ignored" — it has to be JSON.
There is also a Windows-specific command override. Hook configuration takes commandWindows (written command_windows in TOML), documented as "an optional Windows-only command override". The managed-hooks example uses py -3 against a script path as its Windows command. If a shell difference is what mangles your exit code, that is the right place to put an invocation that preserves it.
Which shell runs a hook is not documented
The official hooks page says only that commands "run with the session cwd as their working directory"; it does not name the shell, and it never mentions PowerShell. So "Windows PowerShell 5.1 turns exit 2 into 1" could not be confirmed in the official documentation. That uncertainty is itself the argument for the JSON form: it does not depend on how the exit code travels.
Hooks also have to be enabled. The configuration reference describes features.hooks as "Enable lifecycle hooks loaded from hooks.json or inline [hooks] config".
Q. After resuming from a compacted context, the agent starts work without reading the files CLAUDE.md tells it to read first. Are instruction files not reloaded after compaction?
Part of it is reloaded and part of it is not. The documentation describes each request in three layers, and compaction affects them differently.
Layer
Content
Changes when
System prompt
Core instructions, tool definitions
The set of loaded tool definitions changes
Project context
CLAUDE.md, auto memory, unscoped rules
Session starts, or after /clear or /compact
Conversation
Your messages, Claude's responses, tool results
Every turn
CLAUDE.md itself is reloaded. The prompt-caching documentation says of compaction: "It reloads project context from disk, which cache-hits only if CLAUDE.md and memory are unchanged since the session started." From disk, explicitly.
What is not reloaded is the files CLAUDE.md told Claude to read. Those arrived through the Read tool, so they live in the conversation layer — and "Compaction replaces your message history with a summary." The instruction survives; the content it pulled in gets folded into the summary.
Survives compaction: the CLAUDE.md line "read the memory index first"Does not survive: the actual contents of the memory index and protocol files
Subdirectory CLAUDE.md files and rules with paths: frontmatter are in the conversation layer too: "After it loads, the content is part of the conversation history."
A PostCompact hook cannot add context
If you are looking for a way to force the re-read automatically, check the hook event table first. PostCompact fires "After context compaction completes", but its exit-code-2 behavior is "Shows stderr to user only" and it has no JSON decision fields. The events that can inject context, such as SessionStart with additionalContext, do not include PostCompact.
In practice, the reliable move is one explicit instruction right after compaction: "re-read the memory index before continuing." Running /compact yourself at a break between tasks is also easier to manage than letting auto-compaction fire mid-task.
Separately, Claude Code v2.1.293 fixed a bug where Claude sometimes treated its own actions from before a compaction as done after it. If you are on an older version, update first.
Q. Auto mode blocks harmless actions, like reading project context files. I thought read-only actions never reached the classifier — why are they being denied?
The documentation's "How the classifier evaluates actions" describes auto mode as a fixed four-step decision order where the first matching step wins. Which step your read is landing on is what tells you why it stopped.
Step 2 is the behavior you were expecting: "Read-only actions and file edits in your working directory are auto-approved." A read inside the working directory does not reach the classifier at all. So if one is still being blocked, it is hitting one of that step's exceptions.
The likely causes, roughly in order:
Server-side classifier review is in effect. Listed as an exception to that same step: "In a session with server-side classifier review, read-only and sandboxed shell commands wait for that review and are blocked if it flags them." A read-only command waiting on a review and then being blocked is documented only here.
The file is outside your working directories. "The first read outside the working directories" prompts you. A context file that lives outside the repository qualifies. Adding it with /add-dir or the additionalDirectories setting changes that.
A deny rule matches. Those resolve at step 1, and deny rules block in every mode.
The read is from a network (UNC) path. That prompts you even when an allow rule matches.
Entering auto mode drops some of your allow rules
If the pattern is "this used to go through, and only auto mode stops it", this is why. On entering auto mode, broad allow rules that grant arbitrary code execution are dropped: blanket Bash(*) or PowerShell(*), wildcarded interpreters like Bash(python*), package-manager run commands, Agent allow rules, and Monitor allow rules. Narrow rules like Bash(npm test) stay in effect, and the dropped ones are restored when you leave auto mode.
There is also a documented reason why the denials read as unexplained: "If the classifier blocks, Claude receives the reason. In most sessions the reason names the rule the classifier matched, such as [Data Exfiltration], rather than giving a written explanation."
The documentation has a section called "Why usage climbs in a long session", and a code review hits most of the conditions in it.
The dominant one is context length: "Claude Code sends your full conversation with every request, and each time Claude uses tools it sends another request carrying that batch of tool results." A review reads file after file, so each tool call is another request — and that request carries the whole conversation, including every file read so far. Consumption therefore grows faster than linearly in the number of files reviewed.
Next is cache misses. The prompt cache lifetime is one hour on a subscription, dropping to five minutes once you are drawing on usage credits. Your first message after a longer break reprocesses the full context.
If subagents were involved, each sends its own requests on top of the main conversation. Agent teams are heavier still: teams whose teammates run in plan mode use approximately 7x the tokens of a standard session.
To see which of these actually applied, run /usage. On Pro, Max, Team and Enterprise it flags behaviors that account for 10% or more of recent usage — long context and cache misses among them — and d / w switch between the last 24 hours and the last 7 days.
What the documentation suggests for next time:
/clear when switching to unrelated work. /compact reads the conversation it summarizes, so it is itself a large request
Delegate verbose operations to subagents, so the output stays in their context and only a summary returns
Lower the effort level with /effort or in /model — thinking tokens are billed as output tokens
Match the model to the job: Sonnet handles most coding work and costs less than Opus
注意
Whether that 5% is correct for your plan is not something the documentation can settle, since per-plan limit figures are not published there. For an account-specific billing question, the documented route is to sign in at claude.ai, click your initials in the lower left, and select Get help.
Q. Since Gemini CLI 0.63.0 an "Untrusted Command Flags" warning interrupts even in YOLO mode, on basic file operations through MCP servers. Is there a setting to cut the confirmations down?
The "Untrusted Command Flags" warning itself could not be found in the official configuration or command references as of 2026-10-12, and there is no documented key that turns that particular check off. What follows is therefore the set of documented levers for reducing MCP tool confirmations.
1. Trust the server (settings file)
mcpServers.<SERVER_NAME>.trust is documented as a boolean that "trusts the server and bypasses tool call confirmations." It skips the confirmation for that server's tool calls.
Put it in ~/.gemini/settings.json for your user or .gemini/settings.json for the project.
2. Name the tools instead (launch flag)
--allowed-tools is documented as "A comma-separated list of tool names that will bypass the confirmation dialog." That narrows the bypass to specific tools rather than a whole server.
3. Re-check the approval mode
general.defaultApprovalMode takes default, auto_edit or plan. YOLO mode cannot be enabled from a settings file at all — only from the command line with --yolo or --approval-mode=yolo — and --approval-mode cannot be used together with --yolo. Note also security.disableYoloMode: when it is true, YOLO stays off even if a flag enables it (it requires a restart). If your machine is managed, it is worth checking that this is not switched on without your knowing.
注意
trust: true waives the confirmation for every tool call that server makes. On a filesystem server, or any server that can run arbitrary commands, that widens what runs unattended to everything that server can do. Reserve it for servers whose arguments and reachable paths you have pinned down yourself.
Q. In the Codex desktop app, "Always allow" for an MCP tool stops working in a new chat — the prompt returns. I have a per-tool approval_mode in config.toml. Can I authorize across chats?
It helps to separate what the documentation settles from what it does not.
What it settles: per-tool approval is a documented setting. default_tools_approval_mode is the server-wide default and tools.<tool>.approval_mode is the per-tool override. The docs read: "Default approval behavior for tools from this server. Supported values are auto, prompt, writes, and approve" and "Per-tool approval behavior override."
What it does not settle: of those four values, the only one the documentation explains is writes — "The writes mode prompts for tools that aren't marked read-only." What auto, prompt and approve actually do is stated neither in the configuration reference nor on the MCP page.
The official example is still informative: it sets the server default to prompt and then overrides one tool with approval_mode = "approve". That arrangement reads as approve being the more permissive side, the one that does not prompt — but the documentation does not say so outright.
How long "Always allow" lasts: whether the UI's "Always allow" survives into a new chat could not be confirmed in the official documentation. Where the Codex docs do discuss a persisting "Always allow", it is for Browser Use and for Windows Computer Use app entries; there is nothing equivalent for MCP tools.
注意
So the reliable route today is config.toml rather than the UI's "Always allow". If approval_mode = "approve" still prompts every time, the setting may not be reaching the session: check that the [mcp_servers.<server>.tools.<tool>] table name matches the server id and tool name exactly. Whether this key takes effect through the desktop app's path specifically is not stated in the documentation.
A different lever worth knowing: enabled_tools is an allow list of the tool names a server exposes and disabled_tools is a deny list applied after it. Those control whether a tool is offered at all, not how it is approved.
Q. A server I added with claude mcp add never shows up in /mcp, and I can't use it until I fully restart Claude Code. Is there a documented way to load a newly added MCP server mid-session?
One thing to separate out first: the Added ... line from claude mcp add only tells you the configuration was written. The documentation says so — "claude mcp add confirms a successful add by printing an Added ... line, which means the configuration was written" — and points you elsewhere to verify the connection: "To check that Claude Code connected, run claude mcp get <name>." Start there.
If you added it at project scope (.mcp.json), it is unusable until approved. /mcp shows ⏸ Pending approval (run claude to approve), and the docs say "Run claude interactively to review and approve it." A server stuck at that step looks exactly like "a restart fixed it."
The documented mid-session mechanisms are these:
Mechanism
Covers
Notes
Reconnect from a server's menu in /mcp
One server
On a connected or failed server it also discards the cache entry
/mcp reconnect all
Every server that failed or needs authentication
In the interactive terminal this requires v2.1.284 or later; earlier versions print MCP server "all" not found
/reload-plugins
Plugin-provided servers
In a session without an interactive terminal it doesn't connect or disconnect them; those changes take effect in your next session
Moving the session with /cd
Servers of plugins the new directory's settings enable
v2.1.246 or later; no /reload-plugins needed after the move
注意
Whether a newly added non-plugin server is picked up without a restart could not be confirmed in the official documentation. The mid-session mechanisms it names are the reconnect paths above, plus list_changed notifications that refresh the tool list of a server that is already connected — "An MCP server can change the tools, prompts, or resources it offers while connected."
Note also that toggling a server off in /mcp keeps its configuration: "Toggle a server off in the /mcp panel to stop Claude Code from connecting to it without losing its configuration." Removal is claude mcp remove, and removing a remote server also deletes the OAuth tokens and client registration Claude Code stored for it.
Q. I set omitClaudeMd: true on a subagent, but a subdirectory CLAUDE.md and path-scoped rules still get loaded, and it does nothing at all for a session started with --agent. Is that intended?
omitClaudeMd excludes files from the initial context a subagent starts with. It has no effect on anything loaded later in the session. The documentation places it under the heading "What loads at startup," and that is its scope.
The frontmatter reference reads: "Set to true to launch this subagent without the user, project, and local CLAUDE.md files; managed policy files still load, except for managed subagents." Three things come off — the user, project and local CLAUDE.md — and managed policy files stay.
The memory documentation, describing even the strictest project-instruction setting (managed-only), says: "A subdirectory's CLAUDE.md and .claude/rules/ files, and path-scoped rules, still load on demand." Those load the moment a file in that directory is read. No startup-time exclusion documented anywhere stops that.
For --agent the answer is simpler. The omitClaudeMd row says it is "Ignored when the agent runs as the main session agent via --agent or the agent setting," and "Run the whole session as a subagent" repeats it: "CLAUDE.md files and project memory still load through the normal message flow, even when the agent's definition sets omitClaudeMd." Being ignored there is the documented behavior.
---name: doc-writeromitClaudeMd: true---This writing agent works only from what the delegation prompt gives it.
That setting does nothing under claude --agent doc-writer. It applies only when the agent is invoked as a subagent.
For a rule that genuinely has to reach the subagent, the documented route is the delegation prompt: "If a rule must, such as "ignore the vendor/ directory," restate it in the prompt you give Claude when delegating." The docs also note that "The main conversation still has your full CLAUDE.md when it reads these subagents' results, so most rules don't need to reach the subagent itself" — the design assumes rules live on the parent side.
注意
Whether an --agent session receives the git status snapshot could not be confirmed in the official documentation. What the docs state about git status is that it is part of a non-fork subagent's initial context, that only Explore and Plan skip it, and that you can't change which subagents receive it; turning the snapshot off at all is the includeGitInstructions setting.
Q. I am on Max and used Fable 5.1 at high effort, and after about 24 hours it said I had exhausted my weekly limit. Is that correct, and which model and effort should I use to keep working?
The "weekly limit" message is a plan-side usage window that is shared across models. The official documentation describes it as "a seat-based usage window on a subscription plan, shared across all models, so the developer can't restore access by switching models with /model." Only the model-specific messages — "You've hit your Opus limit" or "You've hit your Sonnet limit" — can be worked around by switching to a model outside that family.
Whether the window you got is the right size for your plan is not something the documentation can settle. Per-plan limit figures are not published in the docs; they point to the pricing page and the Help Center instead. For an account-specific billing question, the documented route is to sign in at claude.ai, click your initials in the lower left, and select Get help.
What the docs do explain is why usage climbs faster than your activity suggests. Claude Code sends your full conversation with every request, so a one-line question in a session that has been open all day still draws usage for the whole conversation. The prompt cache lifetime is one hour on a subscription, and your first message after a longer break misses the cache and reprocesses the full context.
The documented ways to stretch the allowance:
Run /usage. On Pro, Max, Team and Enterprise it flags behavior flags — behaviors such as long context or cache misses that account for 10% or more of recent usage. Press d or w to switch between 24 hours and 7 days.
Lower the effort level with /effort or in /model. Thinking tokens are billed as output tokens. Note that you cannot turn thinking off on Opus 5.5, Sonnet 5.5, Haiku 5.5 or the Fable models.
Match the model to the job. Sonnet handles most coding tasks and costs less than Opus; reserve Opus for complex architectural decisions and multi-step reasoning.
Run /clear when switching to unrelated work. /compact reads the conversation it summarizes, so it is itself a large request.
If you use agent teams, use fewer teammates. Teams whose teammates run in plan mode use approximately 7x the tokens of a standard session.
Once you are at the limit, /usage-credits requests usage beyond the allowance (it isn't available with API key authentication). On Claude Code v2.1.234 or later you can also wait for the reset and have the interrupted task continue automatically, selectable from /rate-limit-options.
Q. Codex stops with "approval required by policy, but AskForApproval::Granular.sandbox_approval is false". The UI is set to "Ask for approval" and my config.toml has no approval_policy. What do I set?
That error text means a granular approval policy is in effect, whatever the UI shows. approval_policy takes one of three forms — on-request, never, or { granular = { ... } } — and the granular form decides, per category of prompt, whether it surfaces or is auto-rejected. The configuration reference documents five fields:
Field
What true means
sandbox_approval
Sandbox escalation approval prompts are allowed to surface
rules
Approvals triggered by execpolicy prompt rules are allowed to surface
mcp_elicitations
MCP elicitation prompts surface instead of being auto-rejected
request_permissions
Prompts from the request_permissions tool are allowed to surface
skill_approval
Skill-script approval prompts are allowed to surface
With sandbox_approval set to false, a sandbox escalation approval is rejected without prompting you — which is exactly what the error states. To get the prompt instead, put one of these in ~/.codex/config.toml:
# Surface every approval prompt (the documented choice for interactive runs)approval_policy = "on-request"
The docs also note that untrusted is unsupported and on-failure is deprecated, and to use on-request for interactive runs.
If your own config.toml sets no approval_policy and you still see this, the value is arriving from somewhere else. The reference documents managed requirements, where an administrator sets "Allowed approval policies" in the Agent Security UI — an admin control, not a user setting. One more related key is approvals_reviewer, which decides "who reviews eligible approval prompts under on-request or granular approval policies" and defaults to user; it does not change sandboxing or actions already allowed inside the sandbox.
注意
How the desktop app's "Ask for approval" setting maps onto these approval_policy keys could not be confirmed in the official documentation. When the UI and the policy actually in force disagree, writing the value explicitly in config.toml is the reliable route.
The message describes a deadlock: the action needs approval, but your approval policy is never, so there is no one to ask. With no way to prompt, it is rejected.
As of October 6, 2026, the configuration reference lists three forms for approval_policy:
Value
Behavior
on-request
For interactive runs. Prompts when approval is needed
never
For non-interactive runs. Never prompts
{ granular = { ... } }
Decides per category of prompt whether it surfaces or is auto-rejected
The documentation puts it plainly:
untrusted is unsupported, and on-failure is deprecated; use on-request for interactive runs or never for non-interactive runs.
If you are sitting at the keyboard driving it, on-request is the intended value, not never:
approval_policy = "on-request"
To surface only some prompts, use granular. Categories set to true surface; categories set to false are auto-rejected.
If what's failing is an action against an external service, mcp_elicitations is the relevant one: under never, an MCP server's request for confirmation is auto-rejected, so anything that needs a sign-in or a grant can't proceed.
注意
A category set to false under granular does not mean "runs without asking" — it means auto-rejected. To actually restrict what runs, narrow sandbox_mode and the permissions instead of the approval policy.
One caveat about the report this came from: it describes the same action succeeding on the web and failing in the desktop app, and it carries a bug label. Why the effective approval policy differs between platforms could not be confirmed in the official documentation. If fixing the setting doesn't resolve it, follow that report.
Nothing is missing from your configuration. .git is a protected path, and permissions.allow cannot pre-approve one by design. The documentation says so directly:
permissions.allow rules in settings files do not pre-approve protected-path writes. The safety check runs before Claude Code evaluates allow rules from settings.
Because the check runs first, an allow rule such as Edit(.git/**) changes nothing. --add-dir only widens the working directories; it has no bearing on the protected-path check.
The per-mode behavior:
Mode
Protected-path writes
default, acceptEdits
Prompted
plan
Allowed in interactive terminal sessions with bypass permissions available; otherwise routed to the classifier when auto mode is available, and prompted when it isn't
auto
Routed to the classifier
dontAsk
Denied
bypassPermissions
Allowed
In acceptEdits the write is not auto-approved, which is not the same as forbidden: answer the prompt and it goes through. On a path where no prompt can be shown — dontAsk, or an environment that cannot surface one — that reads as a refusal.
.git is not the only one. The protected directories are:
.git .config/git .vscode .idea .husky .cargo.devcontainer .yarn .mvn .claude (with a few exceptions)
Protected files are listed too, including .gitconfig, .gitmodules, shell configuration (.bashrc, .zshrc, .envrc and friends), package manager configuration (.npmrc, .yarnrc, bunfig.toml), .pre-commit-config.yaml, .mcp.json and .claude.json.
注意
In a session started with --restricted (v2.1.248 or later), the classifier cannot approve protected-path writes either, so auto mode won't let them through.
If you genuinely need these writes unattended, the only documented route is bypassPermissions mode — and since that skips the protected-path check wholesale, the docs limit it to isolated environments like containers or VMs. Rewriting .git is usually better done through git commands than by letting the Edit tool at it.
1. Extended thinking cannot be turned off on Sonnet 5.5. The model configuration documentation says so directly:
You can't turn thinking off on Opus 5.5, Sonnet 5.5, or the Fable models.
The same passage adds that on these models the session toggle and the /config row read Thinking can't be turned off, and that a saved alwaysThinkingEnabled: false or MAX_THINKING_TOKENS=0has no effect there. Sonnet 5.5 always uses adaptive reasoning, where the effort level is the primary control over how much thinking happens.
Model
Effort levels
Opus 5.5, Sonnet 5.5, Opus 5, Sonnet 5, Opus 4.8, Opus 4.7
low, medium, high, xhigh, max
Opus 4.6, Sonnet 4.6
low, medium, high, max
Run /effort with no arguments for a slider, /effort low to set it directly, or /effort auto to clear the level saved for the active model.
2. In a long session the cost driver is context, not thinking. Claude Code sends the whole conversation with every request, and each time it uses tools it sends another request carrying those results. The documentation's "Why usage climbs in a long session" names long context, cache misses, scheduled tasks, subagents and compaction as the causes:
a one-line question in a session that has been open all day still draws usage for the whole conversation
Lowering effort does nothing about that part. What does:
Action
Effect
/clear between tasks
Drops the conversation history from later requests
/compact when a session runs long
Summarizes history, cutting tokens per request
Narrow what gets read
Ask for "20 lines either side of the error", not "the log"
Match the model to the task
Send routine work to a lighter model
On Pro, Max, Team and Enterprise plans, /usage flags any behavior accounting for 10% or more of your recent usage, such as long context or cache misses. That is the fastest way to see which one is actually costing you. The full picture is in Claude Code cost and usage.
Q. I configured Claude Code to answer in my language, but it keeps reverting to English. How do I make it stick?
The feature for keeping every response in a given voice is an output style. From the documentation:
An output style is a set of instructions that sets Claude's role, tone, and response format for every response in a session.
You can also put "answer in Korean" in CLAUDE.md, but that file is for what Claude should know about your project, and following it is not guaranteed. The docs' own comparison table routes "every response in a certain voice, length, or format" to an output style.
The usual reason it seems to revert is where the choice is saved. The /output-style command and both menus save your selection to .claude/settings.local.json at the local project level. Open a session in a different project and the setting isn't there. To make it your default everywhere, set it in ~/.claude/settings.json:
{ "outputStyle": "Concise"}
The value is case-sensitive. The built-in names are Proactive, Concise, Explanatory and Learning; a value that doesn't match exactly, such as explanatory, silently gives you the Default style. (The /output-style command itself ignores case.) A project's settings files take precedence over your user-level value.
For a language instruction specifically, write a custom style as a Markdown file in ~/.claude/output-styles (user), .claude/output-styles (project), or the managed policy directory:
---name: Koreandescription: Always respond in Koreankeep-coding-instructions: true---Always write your responses to the user in Korean. Leave code, commands, file paths and verbatim error messages in their original form.
Without keep-coding-instructions: true, a custom style drops Claude Code's built-in software engineering instructions. If you only want to change the language of responses, always include it.
注意
The documentation is explicit that an output style "applies to every response in a session. It's an instruction Claude follows, so nothing enforces it." For something that must happen without exception, use a hook instead.
In the terminal, style files are read at startup, so restart Claude Code after creating or editing one mid-session. For how the settings files rank against each other, see Configuring permissions in Claude Code's settings.json.
The thing to establish first is that Claude Code has two billing paths, and credit means something different on each. /status tells you which one your session is on.
Path
Billing
What credit applies
A claude.ai subscription (Pro / Max / Team / Enterprise)
Monthly, with a per-seat allowance
"Usage credits", which let you keep working past the allowance
A Claude Console API key
Per token
Your Console account balance
Usage credits are the subscription-side mechanism. Per the documentation, you manage them by signing in to your claude.ai subscription with /login and then running /usage-credits. The important line:
the command isn't available with API key authentication
So a session running on an API key cannot reach the usage-credits screen at all, and a session signed in with a subscription does not draw down a Console balance. When credit appears to exist but is never used, the usual cause is that the credit sits on one path while the session authenticates on the other.
What /usage-credits opens depends on your role:
Your role
What it does
Pro or Max
Opens Settings > Usage on claude.ai, where you turn usage credits on or off and see your balance, this month's spend, and your monthly spend limit
Team or Enterprise with billing access
Opens Organization settings > Usage
Team or Enterprise without billing access
Asks you to confirm, then sends a request to your organization's admins
One caveat: the term "promotional credit" could not be found in the official documentation. Where a promotional balance can be spent depends on the terms it was granted under. For billing questions about a specific account, the docs point to support: on a subscription, sign in at claude.ai, click your initials in the lower left and choose Get help; for Console billing, do the same at platform.claude.com.
Saying "only this folder" in a prompt is not a boundary. What defines Claude Code's reach is the directory you launched it in, plus any directories added to it. From the documentation:
By default, Claude has access to files in the directory where you launched it.
Launch inside a project and everything under it is in scope. Naming a subfolder in your prompt does not narrow that. If files under your home directory were edited, they were in scope by some other route: the session was launched there, a directory was added with --add-dir, or additionalDirectories lists one. /status shows the current set.
To actually stop it, use settings rather than prose:
Path rules are only evaluated for Edit(path) and Read(path). The documentation states that Claude Code checks file permissions against Edit(path) and Read(path) rules only: a path rule written for Write, NotebookEdit or Glob is accepted but never consulted, and you get a startup warning. Write Edit(docs/**), not Write(docs/**).
Rules are evaluated deny → ask → allow, and the first match decides. Specificity does not change that order, so a broad deny beats a narrower allow.
Setting permissions.blockReadsOutsideWorkingDirectories to true makes the file tools refuse the paths it fences in every permission mode. In auto mode, Claude Code offers to turn it on the first time Claude reads outside the working directories.
There is one — four, in fact, all documented on the auto mode configuration page.
First, why "yes" doesn't work. Per the docs, the explicit user intent that overrides a classifier soft_deny is a message that directly and specifically describes the exact action Claude is about to take. General requests don't count: asking Claude to "clean up the repo" doesn't authorize force-pushing, but asking it to "force-push this branch" does. A bare "yes" names no action, so it isn't treated as intent.
The options:
What you want
How
Allow this kind of action from now on
Add a prose rule to autoMode.allow; allow rules act as exceptions to soft_deny
Allow it just this once
Say specifically what the action is in your next message and let Claude retry
Recover the denied call
Open /permissions, select the Recently denied tab, press r on the action; exiting the dialog lets Claude retry it
Add the rule without editing a file
The Auto mode tab in /permissions (v2.1.246 or later)
autoMode.allow goes in ~/.claude/settings.json. The classifier does not read autoMode from .claude/settings.json or .claude/settings.local.json — both live in the repo directory, so a checked-in repo could otherwise inject its own allow rules. Include the literal "$defaults" in the array to keep the built-in rules.
{ "autoMode": { "allow": [ "$defaults", "git commit --amend --reset-author on unpushed commits is allowed: it only corrects authorship and never rewrites published history" ] }}
To read the full wording of the rule that fired, run claude auto-mode defaults --label 'Git Destructive' (v2.1.208 or later). That rule also clears "when the user asked to amend/reword/fixup", so how you phrase the request can be enough on its own.
Q. CLAUDE.md is injected into the system prompt at session start, so why is it not applied before the first answer?
The premise doesn't match the documentation: CLAUDE.md is not in the system prompt. The memory documentation states it directly:
CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. Claude reads it and tries to follow it, but there's no guarantee of strict compliance, especially for vague or conflicting instructions.
So the expectation that it must be applied because it is in the system prompt doesn't hold. You can confirm the file loaded by running /context and checking the list under Memory files — if it is listed, Claude can see it.
For better adherence, the docs name three things:
Make instructions concrete enough to verify. "Use 2-space indentation" rather than "format code properly"
Look for conflicting instructions across your CLAUDE.md files, nested CLAUDE.md files in subdirectories, and .claude/rules/. When two rules contradict each other, Claude may pick one arbitrarily
Keep each file under 200 lines. Longer files consume more context and reduce adherence, per the docs
For an instruction that must run at a specific point — before every commit, after each file edit — write it as a hook instead of prose. Hooks execute as shell commands at fixed lifecycle events and apply regardless of what Claude decides to do.
If you want instructions at the system prompt level, pass --append-system-prompt at launch. It is better suited to scripts and automation than to interactive use.
Q. My CLAUDE.md lists 11 mandatory project rules, but they are ignored across sessions. Can CLAUDE.md rules be enforced?
CLAUDE.md shapes what Claude tries to do. It is not the mechanism that decides what is allowed. The official permissions documentation states this directly:
Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or CLAUDE.md shape what Claude tries to do, but they don't change what Claude Code allows.
So a rule like "nothing executes without an explicit go-ahead in this session" is not guaranteed by writing it in CLAUDE.md. The file is loaded, but following it is left to the model's judgement. The same page names the four things that do enforce: /permissions, permission rules, a permission mode, and a PreToolUse hook.
For anything you genuinely need blocked, write it in permissions in settings.json. Rules are evaluated deny → ask → allow, and the first match in that order determines the outcome. Specificity does not change the order, so a broad deny beats a narrower allow.
For conditions that rules cannot express, use a PreToolUse hook. Per the docs, PreToolUse hooks run before the permission prompt on every tool call, and their output can deny the call, force a prompt, or skip the prompt. A hook that exits with code 2 stops the call before permission rules are even evaluated.
Hook decisions do not bypass permission rules, though: deny and ask rules are evaluated regardless of what the hook returns, so a matching deny still blocks the call and a matching ask still prompts even when the hook returned "allow".
On the cross-session part: CLAUDE.md is loaded every session, but how the model treats a summary of earlier context is its own judgement. If that behavior has to be fixed, pin it with permissions or a hook rather than with prose.
Q. Can I reload plugins, skills and slash commands inside an open session? I enabled the plugin in settings and ran reload, but no slash commands show up.
You can. The command is /reload-plugins, and it reloads plugins, skills, agents, hooks, plugin MCP servers and plugin LSP servers together. Starting a new project is not required.
If slash commands still do not appear, the documentation names three causes.
1. The change is pending because of the prompt cache
Closing the /plugin menu makes Claude Code run /reload-plugins for you — but if the reload would invalidate the prompt cache, it warns and leaves the changes pending instead. Apply them anyway with:
/reload-plugins --force
The same applies when the install summary said Run /reload-plugins to activate.
2. You did not type it into the session directly
/reload-plugins does run in sessions without an interactive terminal — the desktop app, the Agent SDK, and -p — as of v2.1.260. But it runs only when you type it directly into that session. Sent over a remote connection, such as Remote Control or a relayed chat message, the command declines without reloading anything. In the desktop app, type it into the prompt box yourself.
3. A stale cache
The official troubleshooting entry for plugin skills not appearing is to clear the cache:
rm -rf ~/.claude/plugins/cache
Then restart Claude Code and reinstall the plugin.
One limit to know about: in a session without an interactive terminal, the reload does not connect or disconnect plugin MCP servers. Those changes take effect in your next session. Plugins enabled on your claude.ai account sync into terminal sessions on v2.1.273 or later.
Q. Gemini CLI's sandbox fails with EACCES during builds when I run it under rootless podman.
Rootless podman uses a user namespace by default, so the UID inside the container does not map directly to your host UID. Bind-mounted files then become unwritable, and tools that recreate build directories — node-gyp, for one — fail with EACCES.
Gemini CLI provides a hook for passing arbitrary flags to the container runtime. The documentation states that for container-based sandboxing you can inject custom flags into the docker or podman command using the SANDBOX_FLAGS environment variable. Multiple flags are space-separated.
The podman flag that lines the UIDs up is --userns=keep-id:
One caveat: --userns=keep-id is a podman flag, and the example the Gemini CLI documentation shows is --security-opt label=disable. --userns=keep-id itself does not appear in the official docs — what is documented is the SANDBOX_FLAGS mechanism for passing runtime flags through.
GEMINI_SANDBOX accepts true, docker, podman, sandbox-exec, runsc and lxc. Use --security-opt label=disable only where you need it, since it turns off SELinux labeling.
Q. Can a deny rule for .env in Claude Code be overridden by an allow rule in settings.local.json?
No. deny wins over allow regardless of the scope it is written in (user, project or local). With this in the project .claude/settings.json, a broad Read allow in someone's settings.local.json still cannot read .env:
Note that deny rules govern Claude Code's tool calls. Reading through a shell command such as cat .env is a separate rule, and prefix matches like Bash(cat .env:*) are easy to sidestep. For values that truly matter, keep .env outside the workspace or inject secrets at run time from a secrets manager.
Q. My hook is in settings.json but never runs. What should I check?
Run /hooks and check the hook is listed. If not, the JSON is invalid (trailing comma, quotes) or the file is in the wrong place (.claude/settings.json or ~/.claude/settings.json).
matcher is a regular expression on the tool name: Edit|Write|MultiEdit for file edits, Bash for commands. Check the event name spelling too (PreToolUse / PostToolUse).
Make sure the script is executable (chmod +x), has a shebang line, and that jq is installed. Calling it as bash .claude/hooks/format.sh avoids the permission issue.
Start with claude --debug to see each hook's execution, exit code and stderr.
Restart the session after editing settings to be sure the change is loaded.
Q. An MCP server I added with claude mcp add shows as failed in /mcp. How do I find out why?
In most cases the server itself is failing to start. The quickest way to see the real error is to run the same command outside Claude Code.
npx @playwright/mcp@latest
Three causes account for most of these:
The first npx run times out: it is still downloading the package. Start it manually once so it lands in the cache, then reconnect
Environment variables aren't reaching the server: check that the value you passed with --env KEY=value, or a ${VAR} in .mcp.json, exists in the shell you launched Claude Code from, with echo $VAR
Node.js is too old: check node -v against the version the server requires, usually 18 or later
There is also an argument-order trap the documentation calls out. If the server name comes directly after --env, the CLI reads that name as another KEY=value pair and rejects it. Put at least one other option, such as --transport stdio, between --env and the server name.
Everything after -- is passed to the server untouched. Without it, Claude Code tries to parse the server's own flags, such as --port, as its own options.
Once it starts, check the state with claude mcp list, and re-run /mcp inside the session.
Q. npm install fails inside Codex. Is the sandbox blocking it?
Yes. The workspace-write sandbox blocks network access by default, so package downloads fail. With the on-failure approval policy Codex asks whether to rerun the command outside the sandbox; approve it and the install goes through. To stop being asked, allow the network in ~/.codex/config.toml:
Allowing the network also allows data to leave the machine, so enable it only for repositories you trust. Research-only sessions can stay in read-only.
Q. Gemini CLI stopped responding partway through on the free tier. Have I hit a limit?
Free use with a personal Google account has both a per-minute and a per-day request limit. A single instruction is rarely a single request: the model is called again each time the CLI reads a file or runs a command, so one instruction often costs several requests. Work through a long task and you can reach the daily limit by the afternoon.
There are two ways forward:
Wait for the reset. Both the per-minute and per-day limits recover on their own
Set GEMINI_API_KEY to switch to the paid tier, which is metered from that point on
export GEMINI_API_KEY="your-key"gemini
The limit figures are revised from time to time, so check the official documentation for the current numbers rather than relying on one written down somewhere. For work code, an API key or Vertex AI is the better choice anyway, because the data-use terms differ from the free tier's.
Q. I accidentally let an AI tool read a file containing an API key. What should I do now?
There is no way to unsend data, so revoking the key and issuing a new one is the only reliable response. Work through it in this order:
Revoke the key at the issuing service and issue a replacement
Check that service's own usage logs for anything unexpected between exposure and revocation
Identify how the file was read and close that path: a Read(./.env) deny rule in Claude Code, moving the file outside the workspace for Codex, or .geminiignore for Gemini CLI
If the key was also committed, revoking is still step one; removing it from git history is a separate job on top
Do not skip the revocation on the grounds that only you saw it. How the data is handled during its retention period depends on your plan and contract, and that is not something you can verify after the fact.
Questions are summarized from public posts (GitHub issues, community forums) with a link to the source. Answers are written by the editors from the official documentation.