You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The disk-hygieneclean skill's disk_hygiene_enabled userConfig kill switch (false = audit-only
mode, which should deny every deletion lane) cannot be delivered to the skill-frontmatter guard
hook by any channel, so the guard defaults to enabled and audit-only mode degrades from deny-outright to human-prompt-gated.
Surfaced while fixing #983 (the guard's fail-open on the ${CLAUDE_PLUGIN_DATA} skill-hook launch
refusal, PR #1014). That PR removes the un-launchable ${user_config.*} token from the hook args to
guarantee the guard launches; this issue tracks the capability that removal gives up.
Why no channel reaches the guard
A skill-frontmatter hook has only two ways to receive a userConfig value, and neither works:
Fails safe: the guard stays active and forces a human ask prompt before every mutation; the
model also self-enforces audit-only because the skill body substitution does surface the
configured value to the model. What is lost is the guard's independent deny-outright enforcement
in audit-only mode.
Candidate resolutions (needs a design pass)
Platform: Claude Code adds ${user_config.*} substitution (or CLAUDE_PLUGIN_OPTION_* env
injection) for skill-frontmatter hooks. Cleanest, but not in the plugin's control.
Plugin-scoped delivery: a plugin-level hooks.json SessionStart hook (plugin hooks do get ${user_config.*}) writes the resolved value to a file under ${CLAUDE_PLUGIN_DATA} that the skill
guard reads. Works today but adds a per-session component and a file-trust surface — evaluate
before building.
Summary
The
disk-hygienecleanskill'sdisk_hygiene_enableduserConfig kill switch (false= audit-onlymode, which should deny every deletion lane) cannot be delivered to the skill-frontmatter guard
hook by any channel, so the guard defaults to enabled and audit-only mode degrades from
deny-outright to human-prompt-gated.
Surfaced while fixing #983 (the guard's fail-open on the
${CLAUDE_PLUGIN_DATA}skill-hook launchrefusal, PR #1014). That PR removes the un-launchable
${user_config.*}token from the hook args toguarantee the guard launches; this issue tracks the capability that removal gives up.
Why no channel reaches the guard
A skill-frontmatter hook has only two ways to receive a userConfig value, and neither works:
${user_config.disk_hygiene_enabled}arg substitution — Claude Code substitutes only${CLAUDE_PLUGIN_ROOT}into skill-hook args (${CLAUDE_PLUGIN_DATA}is plugin-only and refusesthe launch;
${user_config.*}is, on the evidence, not substituted for skill hooks). Passing itwould reintroduce the disk-hygiene: guard hook fails to launch on skill-frontmatter hooks referencing ${CLAUDE_PLUGIN_DATA} — live fail-open on 0.4.6 #983 launch-refusal fail-open.
CLAUDE_PLUGIN_OPTION_DISK_HYGIENE_ENABLEDenvironment variable — not injected into askill-frontmatter hook's process environment (the disk-hygiene: skill-frontmatter guard reads CLAUDE_PLUGIN_DATA from env but never receives it -> engine lane fails closed on all platforms #376 finding for
CLAUDE_PLUGIN_DATA; theCLAUDE_PLUGIN_OPTION_*class is likewise absent).Impact
functioned there either.
askprompt before every mutation; themodel also self-enforces audit-only because the skill body substitution does surface the
configured value to the model. What is lost is the guard's independent deny-outright enforcement
in audit-only mode.
Candidate resolutions (needs a design pass)
${user_config.*}substitution (orCLAUDE_PLUGIN_OPTION_*envinjection) for skill-frontmatter hooks. Cleanest, but not in the plugin's control.
hooks.jsonSessionStart hook (plugin hooks do get${user_config.*}) writes the resolved value to a file under${CLAUDE_PLUGIN_DATA}that the skillguard reads. Works today but adds a per-session component and a file-trust surface — evaluate
before building.
References
CLAUDE_PLUGIN_DATAin env.