Summary
The confirm-deploy PreToolUse Bash hook intermittently hard-blocks legitimate Bash commands that do not invoke lua deploy — including the plugin's own /lua-doctor Step 4 probe (lua agents --json --ci). Because confirm-deploy.decide() blocks anything that isn't a prefixed lua deploy, any command whose if scoping is mis-matched is rejected with DEPLOY_DENIED_BARE.
Environment
- Claude Code on Windows 11 (Git Bash shell)
- Plugin
lua-agent-builder 1.0.0 (claude-code-lua-plugin marketplace)
lua-cli 3.18.0, Node v24.16.0, npm 11.13.0
Relevant hooks/hooks.json
{ "matcher": "Bash",
"hooks": [{ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/confirm-deploy.mjs",
"if": "Bash(*lua deploy*)" }] }
Observed
| Command |
Result |
node --version |
✓ passes |
lua --version |
✓ passes |
lua agents --json --ci |
✗ blocked (DEPLOY_DENIED_BARE) |
multi-line ls … && ls … && … (no lua token at all) |
✗ blocked |
The blocked commands contain no lua deploy substring. Simple single-token commands pass; commands with an env prefix (PATH=… lua agents), pipes, && chains, or spaces in paths appear to trip the if scoping into firing.
Why allow rules don't save it
The user's settings.json explicitly allows Bash(lua agents *), but PreToolUse hooks run regardless of permissions.allow, so the misfiring hook overrides the allow rule. The result is a hard block with no way to proceed except routing the command through a different shell (PowerShell).
Impact
- Legitimate
lua subcommands and general Bash are intermittently hard-blocked.
/lua-doctor cannot complete Step 4 — its own lua agents auth probe is blocked by the plugin's own hook.
Suggested fix
- Tighten the
if matcher to anchor on an actual lua deploy invocation (token / word-boundary match) rather than the substring glob Bash(*lua deploy*), or
- Make
confirm-deploy.decide() return null (allow) unless the command actually invokes the deploy subcommand, instead of blocking every non-prefixed-deploy command it sees.
Summary
The
confirm-deployPreToolUse Bash hook intermittently hard-blocks legitimate Bash commands that do not invokelua deploy— including the plugin's own/lua-doctorStep 4 probe (lua agents --json --ci). Becauseconfirm-deploy.decide()blocks anything that isn't a prefixedlua deploy, any command whoseifscoping is mis-matched is rejected withDEPLOY_DENIED_BARE.Environment
lua-agent-builder1.0.0 (claude-code-lua-pluginmarketplace)lua-cli3.18.0, Node v24.16.0, npm 11.13.0Relevant
hooks/hooks.json{ "matcher": "Bash", "hooks": [{ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/confirm-deploy.mjs", "if": "Bash(*lua deploy*)" }] }Observed
node --versionlua --versionlua agents --json --ciDEPLOY_DENIED_BARE)ls … && ls … && …(noluatoken at all)The blocked commands contain no
lua deploysubstring. Simple single-token commands pass; commands with an env prefix (PATH=… lua agents), pipes,&&chains, or spaces in paths appear to trip theifscoping into firing.Why
allowrules don't save itThe user's
settings.jsonexplicitly allowsBash(lua agents *), but PreToolUse hooks run regardless ofpermissions.allow, so the misfiring hook overrides the allow rule. The result is a hard block with no way to proceed except routing the command through a different shell (PowerShell).Impact
luasubcommands and general Bash are intermittently hard-blocked./lua-doctorcannot complete Step 4 — its ownlua agentsauth probe is blocked by the plugin's own hook.Suggested fix
ifmatcher to anchor on an actuallua deployinvocation (token / word-boundary match) rather than the substring globBash(*lua deploy*), orconfirm-deploy.decide()returnnull(allow) unless the command actually invokes thedeploysubcommand, instead of blocking every non-prefixed-deploy command it sees.