Permission audit logging: capture approval method (settings.json rule vs manual user approval)

Resolved 💬 3 comments Opened Mar 29, 2026 by roughlyhumanoid Closed May 2, 2026

Feature Request

Summary

When a permission request is evaluated, the final approval method — whether it was auto-approved by a matching rule in settings.json / settings.local.json, or manually approved by the user — is not captured anywhere in the audit log.

Current behaviour

The PermissionRequest hook fires and records its own decision (e.g. defer, allow, deny). When the hook defers to settings.json, Claude Code evaluates the allow/deny rules internally and either auto-approves or prompts the user. This final outcome is not written back to any log.

Available log files (/var/log/agents/ in our setup):

  • claude_permission_hook.log — records hook verdict only; shows DEFER for everything that didn't match a hook rule
  • claude_permission_metrics.jsonl — same; decision: unknown for all deferred requests
  • claude_hook.log — records tool_complete with success/fail outcome, but no approval method
  • No log records whether the tool ran because a settings rule matched, or because the user clicked Approve

Impact

  • Cannot audit how many operations in a session required manual user intervention vs were silently auto-approved
  • Cannot tune settings.json rules effectively without counting manual approvals per tool/command pattern
  • Cannot produce meaningful permission usage reports or detect over-permissioning
  • A session with 266 permission requests has no way to distinguish "20 needed human review" from "266 needed human review"

Proposed behaviour

After settings.json evaluation, write a post-decision log entry that includes:

{
  "timestamp": "...",
  "session_id": "...",
  "tool_name": "Bash",
  "approval_method": "settings_rule",   // or "manual_user", "hook_allow", "hook_deny"
  "matched_rule": "Bash(git:*)",         // the specific rule that matched, if any
  "outcome": "allowed"
}

This could go to an existing log file (e.g. claude_permission_metrics.jsonl) as an additional event, or a new claude_permission_decisions.jsonl.

Why this matters

For users running Claude Code in high-autonomy / unattended modes with rich settings.json allow lists, understanding the actual approval breakdown is essential for:

  • Security auditing (which operations truly ran without human review)
  • Permission hygiene (identifying rules that are never matched, or commands that keep prompting)
  • Compliance (demonstrating human oversight of specific operation classes)

Environment

  • Claude Code CLI, macOS
  • Custom permission hook writing to /private/var/log/agents/
  • settings.local.json with ~80+ allow rules across Bash, Read, Write, Edit, MCP tools

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗