Feature Request: Skill-scoped permissions

Status Fixed / completed
Maintainer reply None cached
Activity 5 comments · opened May 15, 2026 · closed Aug 17, 2026

Problem

Claude Code's permission system only allows global or project-level allow/deny rules for tools and Bash commands. There is no way to scope permissions to a specific skill.

When a user trusts a skill (e.g., /update-servers) to perform its job — SSH into known hosts, write temp scripts, read log files — they must manually enumerate every command pattern in settings.json. This is:

  • Fragile: Any variation in command format (compound commands, different flags) breaks the match
  • Tedious: The user must know in advance every Bash pattern the skill will use
  • Counterintuitive: Users think in terms of skills, not individual tool calls

Desired Behavior

Allow permissions to be scoped to a named skill:

{
  "permissions": {
    "skills": {
      "update-servers": {
        "allow": ["Bash(*)", "Read(/tmp/*)"]
      }
    }
  }
}

Or alternatively, allow skills to declare their required permissions in SKILL.md frontmatter:

---
name: update-servers
description: Updates remote servers via SSH
permissions:
  allow:
    - "Bash(ssh *)"
    - "Bash(bash /tmp/update-servers-*.sh)"
    - "Read(/tmp/update-*.log)"
---

The user would be asked once (at skill invocation or installation) to approve the declared permissions, similar to how mobile apps request permissions.

Why This Matters

Skills are the primary mechanism for extending Claude Code with custom workflows. Without skill-scoped permissions, every skill that runs shell commands degrades the user experience — either:

  1. The user is constantly prompted (friction), or
  2. The user grants overly broad global permissions (security risk)

Skill-level trust is a natural mental model: "I trust this skill to do its job."

Current Workaround

Manually adding pattern rules to settings.json for every command the skill might run — a brittle, incomplete solution that breaks when the skill uses compound commands or argument variations that don't match the glob.

Environment

  • Claude Code CLI
  • Skills system (user-defined SKILL.md files)

View original on GitHub ↗

4 Comments

github-actions[bot] · 3 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/51656

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

caioribeiroclw-pixel · 3 months ago

This mental model feels right: people trust a skill as a unit, not a pile of glob patterns.

One thing I would add to the proposal is making the permission decision inspectable in two places:

  1. Install / approval receipt — what the skill declares it may need:
{
  "skill": "update-servers",
  "declared_permissions": ["Bash(ssh *)", "Read(/tmp/update-*.log)"],
  "declared_write_paths": ["/tmp/update-servers-*.sh"],
  "network_targets": ["known_hosts_from_config"],
  "approved_by_user": true
}
  1. Invocation receipt — what was actually active for this run:
{
  "skill": "update-servers",
  "active_skill": true,
  "tool": "Bash",
  "command_class": "ssh",
  "permission_source": "skill:update-servers",
  "allowed": true,
  "reason": "matches approved skill permission"
}

That split would prevent two common failure modes:

  • a skill declares broad permissions once, but the user cannot later see which permission allowed a risky tool call;
  • a tool call happens during a skill-shaped workflow, but the hook/permission layer cannot tell whether it was genuinely skill-scoped or just a normal model action.

So I’d pair skill-scoped permissions with an active_skill / permission_source field in hook and transcript events. Then security/debugging does not depend on guessing from the text around the tool call.

vidarmoe · 2 months ago

We've been dealing with this exact friction and built a meta-skill (/make-skill-autonomous) specifically to work around the gap: it inspects recent transcripts, finds tool calls that triggered permission prompts, and adds the corresponding glob patterns to settings.json automatically.

It works, but it's the wrong abstraction. The result is a flat global allowlist that grows over time with patterns from many different skills — no way to audit which skill "owns" a given entry, and no way to revoke permissions for one skill without potentially breaking another.

The SKILL.md frontmatter approach in the original proposal feels like the right model to us. Skills already declare their identity, purpose, and invocation instructions in that file — permissions_required would fit naturally there. When a user explicitly invokes /skill-name, they've already expressed trust in that skill; requiring them to also manually expand a global pattern list is redundant and undermines the "skills as units of trust" mental model.

One addition worth considering: a way to see which permissions are currently active because of a skill invocation, so users can audit and revoke at the skill level rather than hunting through glob patterns.

mglyer-vulncheck · 1 month ago

Adding a concrete use case and a vote for the invocation-scoped ("just this run") variant of this.

I have a startup skill that, on invocation, runs ~15–20 tool calls in sequence: several Bash calls (find/grep/date), a dozen MCP calls across multiple connectors, and a few file edits. I want to approve the whole skill run once and have that approval auto-expire when the skill finishes — not persist to settings.json, and not flip the entire session into bypassPermissions.

Today the only options are:

  • --dangerously-skip-permissions / bypassPermissions — session-wide and too broad; I have to remember to toggle it back off afterward.
  • acceptEdits — doesn't cover Bash or MCP tool calls, so it barely helps for a skill like this.
  • Persistent permissions.allow patterns — durable (overkill for an occasional run) and brittle for compound Bash commands.

The ephemeral, auto-expiring manifest in #59314 (approve once for a bounded unit of work, expires on completion) is exactly the right mechanism — I'd just want it triggered at skill invocation rather than at plan approval: show the manifest of tools/globs the run will touch, approve once, auto-expire when the run completes or I send a new message.

Skill-declared permissions in SKILL.md frontmatter (as proposed here) would be a great durable complement, but the per-invocation approve-once is the piece that removes the friction without leaving standing grants.

Showing cached comments. Read the full discussion on GitHub ↗