You add allowed-tools: Bash(git add *) Bash(git commit *) to a skill. You type /commit, and Claude stages and commits without asking. You send one more message, ask for another commit — and the permission prompt is back.
Nothing broke. allowed-tools did exactly what it is specified to do. It is just narrower than the name suggests.
The one-line version
allowed-tools pre-approves the listed tools for the turn that invokes the skill. That is the entire scope. The docs are explicit about the expiry: the grant "clears when you send your next message."
Invoking the skill again re-applies it for that turn. So /commit, then a follow-up message asking Claude to commit again, are two different worlds: the first is covered, the second is not.
The asymmetry that generates the bug report
Two things happen when a skill is invoked, and they have different lifetimes:
| What | Lifetime |
|---|---|
The rendered SKILL.md content |
Enters the conversation as a single message and stays for the rest of the session |
The allowed-tools grant |
Clears when you send your next message |
Instructions persist. Permissions do not.
That mismatch is why two contradictory-sounding statements are both true: the skill is still loaded and the skill stopped working. Claude still has the instructions. It just lost the pre-approval, so it asks.
If you hit this, you have two honest options:
- Re-invoke the skill. That re-applies the grant for the new turn.
- Move the permission out of the skill entirely (see below).
It is a grant, not a fence
This is the part that trips people who read the field as a whitelist:
It does not restrict which tools are available: every tool remains callable, and your permission settings still govern tools that are not listed.
So a skill with allowed-tools: Read Grep has not been sandboxed to reading and grepping. Claude can still call Bash. The field only says "these specific ones don't need a prompt right now." Everything else falls back to your normal permission rules.
If you actually want a tool taken away, that is a different field.
disallowed-tools is the restricting half
disallowed-tools removes tools from Claude's available pool while the skill is active. It is the right field for an autonomous skill that should never call something — a background loop that must not stop to ask you a question, for example.
Two limits worth knowing:
- It clears on your next message, same as the grant.
- Like deny rules, it cannot remove
EndConversationwhile any other tool remains.
To block a tool across all skills and prompts rather than one skill, use deny rules in your permission settings.
Picking the right place for the rule
| What you want | Where it goes | How long it lasts |
|---|---|---|
| Skip prompts for a few commands when this skill runs |
allowed-tools in SKILL.md
|
the invoking turn |
| Keep a tool away from one autonomous skill |
disallowed-tools in SKILL.md
|
while the skill is active |
| Skip prompts for the whole session | allow rules in permission settings | your settings files |
| Block a tool everywhere | deny rules in permission settings | your settings files |
The rule of thumb: frontmatter is for this invocation, settings are for this project or user. If you find yourself wanting allowed-tools to stick around, you have discovered that the rule belongs in settings.
The pattern that makes a bundled script run silently
Skills can ship their own scripts. The problem is that a hardcoded path breaks the moment the skill is installed somewhere else — and for a plugin skill, ${CLAUDE_SKILL_DIR} points at the skill's subdirectory inside the plugin, not the plugin root, so guessing is worse than it looks.
The fix is that Claude Code substitutes ${CLAUDE_SKILL_DIR} in two places: the skill's markdown content, and Bash rules in allowed-tools. Use the same variable in both and the allow rule matches the exact command the body tells Claude to run:
---
name: render-chart
description: Render a chart from a CSV file
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/render.sh *)
---
Run `${CLAUDE_SKILL_DIR}/scripts/render.sh <csv>` to render the chart.
Installed at ~/.claude/skills/render-chart/, both occurrences expand to that directory, the rule matches, and the script runs without a prompt. Move the skill and it still matches, because neither side was hardcoded.
There is a sibling variable, ${CLAUDE_PROJECT_DIR}, for project-local scripts — that one needs Claude Code v2.1.196 or later.
The line to read before you trust a repository
For skills checked into a project's .claude/skills/ directory, allowed-tools takes effect after you accept the workspace trust dialog for that folder — the same as permission rules in .claude/settings.json.
Read that in reverse: a skill in a repo can grant itself broad tool access, and clicking "trust" is what turns it on. Reviewing the skills is part of reviewing the repository, not a separate chore.
A 10-second pass before trusting an unfamiliar project:
grep -rn "allowed-tools\|disallowed-tools" .claude/skills/ .claude/commands/ 2>/dev/null
If a skill you did not write pre-approves Bash(* ) or anything close to it, that is worth a second look before you accept the dialog.
Checklist: "my skill keeps asking for permission"
- Did you send a message since invoking it? The grant is per-turn. Re-invoke.
-
Does the rule match the command as written?
Bash(git commit *)coversgit commit -m "x", not a command routed through something else. -
Are you expecting it to restrict? It never did. That is
disallowed-tools. - Do you want it for the whole session? Then it belongs in permission settings, not in the skill.
- Is it a project skill in an untrusted folder? Nothing applies until the workspace trust dialog is accepted.
The mental model
allowed-tools is a receipt you hand over at the door, not a badge you wear all day. It gets you past the prompt for the turn you invoked the skill, and then it is spent. Everything durable — what Claude may do session-wide, what it may never do — lives in your permission settings.
Once you stop expecting the frontmatter to be a sandbox, the field becomes genuinely useful: it removes the friction from the two or three commands a skill actually needs, without quietly widening what Claude can do for the rest of the day.
Written while building Rulestack — packs of Cursor rules, Claude Code skills, and AGENTS.md setups for people who would rather not rediscover this by trial and error.
More notes like this as I find them: @ai-shop.bsky.social on Bluesky.
Top comments (0)