hooks/human-gate.ts. Options: categories, protectedBranches, extraCommands, extraTools, readOnlyFastLane, trustMcpReadOnly (set in user or managed settings pluginConfigs, or /config). Run claude plugin validate on the installed folder to see every event it hooks and every $ call it makes.
human-gate
Splits tool permissions into two lanes:
- Held for a person. Calls that cannot be undone are answered
askby the mod: deploys, package publishes, pushes to a protected branch, money moves, messages sent outside the session, destructive SQL. Since Claude Code 2.1.304 a mod's ask belongs to a person: the auto-mode classifier and allow rules in settings can't approve it. Where nobody can be asked (claude -p, a headless host), the call is refused and the model gets the reason. - Let through. A call that the tool marks read-only (
e.isReadOnly), and that the engine would only have asked about, runs without a prompt. A deny rule or ask rule you wrote, a classic hook's ask, a setting's own check (such as reads outside the working directories), or an organization ceiling ofaskalways wins.
npx claude-code-templates@latest --mod security/human-gateType /human-gate to see which categories are active and how many calls the mod has held or let through in this session. The status line under the prompt shows the same counts.
What is held
| Category | Examples |
|---|---|
deploy |
wrangler pages deploy, vercel --prod, fly deploy, kubectl apply, helm upgrade, terraform apply, gh workflow run, MCP deploy_* and delete_project |
publish |
npm publish (also pnpm/yarn/bun), npm unpublish, cargo publish, twine upload, docker push, gh release create |
push-main |
git push origin main, git push origin HEAD:main, git push --all/--mirror, or git push / git push origin HEAD while the repository the push runs in (git -C dir, cd dir && …) is on a protected branch. Quoted refs count ("HEAD:main"). If git can't name the branch (detached HEAD) or the directory is one the shell would expand (~, $VAR), the push is held |
money |
Any tool of an MCP server whose name contains stripe, except list/get/retrieve/search/read/fetch/describe/find/count/query_read tools that change nothing (get_or_create_customer is held), and any MCP tool about refunds, payouts, charges, transfers, payment intents or invoices (same read exception). camelCase names count too (createInvoice) |
outbound |
MCP tools whose name has a send, forward, reply, post, publish or share word (send_message, slack_send_message), or adds a comment (add_issue_comment, addIssueComment) |
data |
DROP/TRUNCATE/ALTER of a table, database, schema, role or user, DELETE/UPDATE without a real WHERE (one inside a SQL string, quoted identifier or comment does not count, and a MySQL /*! … */ body is read as code; also inside the quotes of psql, mysql, sqlite3 and other SQL clients, and in any string of an MCP tool's input), prisma migrate deploy, alembic upgrade, rails db:migrate |
Compound Bash commands are split on &&, ||, ; and |, so cd app && npm publish is caught. Global flags before the verb don't hide it (terraform -chdir=infra apply, kubectl -n prod apply, pnpm -r publish). Text inside quotes is ignored, so git commit -m "explain npm publish" is not held. A segment with --dry-run (npm publish --dry-run, kubectl apply --dry-run=client) is not held, but --dry-run=none and =false are.
Options
Set them in ~/.claude/settings.json under pluginConfigs["human-gate@skills-dir"].options.
| Option | Default | What it does |
|---|---|---|
categories |
all | Comma-separated subset of deploy, publish, push-main, money, outbound, data. Unknown names are logged and ignored, and if none of the names is known, every category stays held, so a typo can't switch the gate off |
protectedBranches |
main, master, production, prod, release |
Comma-separated branch names |
extraCommands |
— | Comma-separated regexes on Bash command segments, e.g. \bansible-playbook\b |
extraTools |
— | Comma-separated regexes on tool names, e.g. ^mcp__linear__save_issue$ |
readOnlyFastLane |
true |
Let read-only calls run without a prompt |
trustMcpReadOnly |
false |
Include MCP tools in the fast lane. Off because an MCP tool's read-only flag is only its server's claim |
WebFetch, WebSearch, Agent, Task, SendMessage and Skill never take the fast lane, even though they report themselves as read-only: they reach the network or hand the work to someone else.
Limits
- The patterns are heuristics. A command built at run time (
sh -c "$CMD", a script that publishes) is not seen, and only theBashtool's commands are parsed (not PowerShell or an MCP shell tool). Use the mod as a second line of defense alongside deny rules, not as a sandbox. - If the check itself throws, the mod fails closed and asks a person.
- Overlaps with
security/jev-auto-mode, which is a full allow/ask/deny policy. Use human-gate when all you want is "irreversible things wait for me".
Needs Claude Code 2.1.304 or later.
human-gate
Splits tool permissions into two lanes:
- Held for a person. Calls that cannot be undone are answered
askby the mod: deploys, package publishes, pushes to a protected branch, money moves, messages sent outside the session, destructive SQL. Since Claude Code 2.1.304 a mod's ask belongs to a person: the auto-mode classifier and allow rules in settings can't approve it. Where nobody can be asked (claude -p, a headless host), the call is refused and the model gets the reason. - Let through. A call that the tool marks read-only (
e.isReadOnly), and that the engine would only have asked about, runs without a prompt. A deny rule or ask rule you wrote, a classic hook's ask, a setting's own check (such as reads outside the working directories), or an organization ceiling ofaskalways wins.
npx claude-code-templates@latest --mod security/human-gateType /human-gate to see which categories are active and how many calls the mod has held or let through in this session. The status line under the prompt shows the same counts.
What is held
| Category | Examples |
|---|---|
deploy |
wrangler pages deploy, vercel --prod, fly deploy, kubectl apply, helm upgrade, terraform apply, gh workflow run, MCP deploy_* and delete_project |
publish |
npm publish (also pnpm/yarn/bun), npm unpublish, cargo publish, twine upload, docker push, gh release create |
push-main |
git push origin main, git push origin HEAD:main, git push --all/--mirror, or git push / git push origin HEAD while the repository the push runs in (git -C dir, cd dir && …) is on a protected branch. Quoted refs count ("HEAD:main"). If git can't name the branch (detached HEAD) or the directory is one the shell would expand (~, $VAR), the push is held |
money |
Any tool of an MCP server whose name contains stripe, except list/get/retrieve/search/read/fetch/describe/find/count/query_read tools that change nothing (get_or_create_customer is held), and any MCP tool about refunds, payouts, charges, transfers, payment intents or invoices (same read exception). camelCase names count too (createInvoice) |
outbound |
MCP tools whose name has a send, forward, reply, post, publish or share word (send_message, slack_send_message), or adds a comment (add_issue_comment, addIssueComment) |
data |
DROP/TRUNCATE/ALTER of a table, database, schema, role or user, DELETE/UPDATE without a real WHERE (one inside a SQL string, quoted identifier or comment does not count, and a MySQL /*! … */ body is read as code; also inside the quotes of psql, mysql, sqlite3 and other SQL clients, and in any string of an MCP tool's input), prisma migrate deploy, alembic upgrade, rails db:migrate |
Compound Bash commands are split on &&, ||, ; and |, so cd app && npm publish is caught. Global flags before the verb don't hide it (terraform -chdir=infra apply, kubectl -n prod apply, pnpm -r publish). Text inside quotes is ignored, so git commit -m "explain npm publish" is not held. A segment with --dry-run (npm publish --dry-run, kubectl apply --dry-run=client) is not held, but --dry-run=none and =false are.
Options
Set them in ~/.claude/settings.json under pluginConfigs["human-gate@skills-dir"].options.
| Option | Default | What it does |
|---|---|---|
categories |
all | Comma-separated subset of deploy, publish, push-main, money, outbound, data. Unknown names are logged and ignored, and if none of the names is known, every category stays held, so a typo can't switch the gate off |
protectedBranches |
main, master, production, prod, release |
Comma-separated branch names |
extraCommands |
— | Comma-separated regexes on Bash command segments, e.g. \bansible-playbook\b |
extraTools |
— | Comma-separated regexes on tool names, e.g. ^mcp__linear__save_issue$ |
readOnlyFastLane |
true |
Let read-only calls run without a prompt |
trustMcpReadOnly |
false |
Include MCP tools in the fast lane. Off because an MCP tool's read-only flag is only its server's claim |
WebFetch, WebSearch, Agent, Task, SendMessage and Skill never take the fast lane, even though they report themselves as read-only: they reach the network or hand the work to someone else.
Limits
- The patterns are heuristics. A command built at run time (
sh -c "$CMD", a script that publishes) is not seen, and only theBashtool's commands are parsed (not PowerShell or an MCP shell tool). Use the mod as a second line of defense alongside deny rules, not as a sandbox. - If the check itself throws, the mod fails closed and asks a person.
- Overlaps with
security/jev-auto-mode, which is a full allow/ask/deny policy. Use human-gate when all you want is "irreversible things wait for me".
Needs Claude Code 2.1.304 or later.
Scanned by NVIDIA SkillSpector
Automated static analysis (no LLM) · v2.12.0 · 2026-11-03
Partial analysis: some checks could not run on this component.
SkillSpector looks for patterns such as shell commands, credential access, network calls or unpinned dependencies. An observation is something worth reading in the files before you install, not a confirmed vulnerability. Components that run code locally, like hooks, MCP servers and security tooling, naturally show more of them.
- Agent Config Directory AccessAgent Snooping · README.md:29
- npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.MCP Rug Pull · README.md:9
Learn more about NVIDIA SkillSpector.