HookStackGitHub
Back to catalogue
SecurityPermissionRequestPermissionRequestOn permission request · can block⚡ blocking

Auto-approve read-only permissions

Automatically approves permission requests for read-only operations (Read, Glob, Grep, safe Bash commands) without manual intervention.

Use cases

  • Reduce interruptions for non-destructive operations
  • Automated security policy based on command safety

Providers & tags

Claude Code
#permission#security#auto-allow#readonly#policy

settings.json fragment

{
  "hooks": {
    "PermissionRequest": [
      {
        "hooks": [
          {
            "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/permission-auto-allow.mjs",
            "type": "command"
          }
        ],
        "matcher": ""
      }
    ]
  }
}

Script · .claude/hooks/permission-auto-allow.mjs

#!/usr/bin/env node
// Auto-autorise les outils lecture seule et les commandes Bash sûres (PermissionRequest)
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';

const SAFE_BASH = [
  /^ls/, /^pwd/, /^echo/, /^cat(?!.*>)/, /^head/, /^tail/, /^wc/,
  /^which/, /^whereis/, /^file/, /^stat/,
  /^git\s+(status|log|diff|show|branch|tag)/,
  /^npm\s+(list|ls|outdated|view)/,
];

const READ_ONLY_TOOLS = ['Read', 'Glob', 'Grep'];

export function run(input) {
  const toolName = input.tool_name || '';
  const toolInput = input.tool_input || {};

  let allow = READ_ONLY_TOOLS.includes(toolName);
  if (!allow && toolName === 'Bash') {
    const cmd = (toolInput.command || '').trim();
    allow = SAFE_BASH.some((p) => p.test(cmd));
  }

  return allow
    ? {
        hookSpecificOutput: {
          hookEventName: 'PermissionRequest',
          decision: { behavior: 'allow' },
        },
      }
    : null;
}

/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const input = JSON.parse(readFileSync(0, 'utf8'));
  const result = run(input);
  if (result) process.stdout.write(JSON.stringify(result));
}