[BUG] Desktop app: skill allowed-tools grants never arm — pre-approved commands always prompt
Summary
allowed-tools in a plugin skill's SKILL.md frontmatter pre-approves the listed tool patterns for the invoking turn in the CLI, but in the desktop app the same byte-perfect commands always raise permission dialogs. It appears the desktop shell's skill-invocation path never arms the per-turn grant.
Reproduction
Plugin: https://github.com/nikicat/claude-ppq (skill ppq:claude-code), frontmatter includes e.g.:
allowed-tools:
- Bash(${CLAUDE_SKILL_DIR}/scripts/claude-ppq *)
- Bash(bash ${CLAUDE_SKILL_DIR}/scripts/claude-ppq *)
In the Windows desktop app (current, 1.24012.x train), invoke /ppq:claude-code glm. The model runs:
C:/Users/<user>/.claude/plugins/cache/ppq/ppq/0.4.5/skills/claude-code/scripts/claude-ppq --models glm
— an exact match for the first pattern after ${CLAUDE_SKILL_DIR} substitution — and a permission dialog appears. Every pre-approved shape across four plugin versions (0.3.2 → 0.4.5) has behaved the same on desktop. Denied the canonical path often enough, the model falls back to improvised curl + parsing chains — strictly worse for the user and for security posture.
Evidence it's the desktop shell, not the engine or the plugin
- CLI is clean, verified continuously: our CI drives real headless sessions (
claude -pwith a--permission-prompt-toolrecorder that logs any would-be prompt) on ubuntu/macos/windows. Identical skill flows produce zero permission requests: https://github.com/nikicat/claude-ppq/blob/main/.github/workflows/e2e.yml - The engine the desktop fetches supports the feature:
downloads.claude.ai/claude-code-releasesserves 2.1.206 (stable) / 2.1.218 (latest), well past 2.1.129 where${CLAUDE_SKILL_DIR}substitution landed — and substitution demonstrably works in the desktop transcript (paths render resolved). - The CLI's permission pipeline consults the host (permission-prompt tool /
canUseTool) only after grant filtering — verified empirically. On desktop, grant-covered commands reach the dialog, implying the grant was never registered for the turn.
Expected
Skill invocation in the desktop app arms the skill's allowed-tools for that turn, as the CLI does (docs: "Tools Claude can use without asking permission during the turn that invokes this skill").
Environment
- Claude desktop app, Windows x64, 1.24012.x train (also inspected the Linux 1.24012.0 deb: Electron shell driving the engine via the Agent SDK with a custom
canUseToolhost) - Plugin installed from a GitHub marketplace; CLI 2.1.210 with the identical plugin behaves correctly on the same machine class