Skip to main content

Claude Code PreToolUse hook that auto-approves known-safe read-only shell commands.

Project description

saferead

A Claude Code PreToolUse hook that auto-approves known-safe, read-only shell commands — so routine reads (ls, cat, git status, grep, …) don't interrupt you with permission prompts.

PyPI Python License

What it does

saferead inspects each Bash command Claude Code is about to run and returns one of three verdicts:

  • allow — every part of the command is a recognized read-only operation.
  • ask — a gated git write (add / commit / stash) on a protected branch (master / main); you get a confirmation prompt.
  • abstain — anything it doesn't recognize: it stays silent and lets Claude Code's normal permission flow proceed.

It never denies a command. It only ever removes friction (allow) or adds a confirmation (ask), so it composes safely alongside any separate command-blocking layer you run.

Compound commands are decomposed at top-level &&, ||, ;, |, and newlines (quote / backtick / $(…)-aware). A command is allowed only when every segment is a recognized safe read.

Design guarantee

The cardinal rule is zero false-allows: a command that mutates state must never be silently approved. Coverage is secondary — when in doubt, it abstains. The hook is also built to never crash or block Claude Code: any internal error is caught and the hook abstains.

Examples

Command Verdict Why
ls -la, cat README.md, grep -rn foo src allow read-only
git status, git log --oneline, git diff allow read-only git
cat a.txt && wc -l a.txt allow every segment is a safe read
git commit -m "wip" on main ask gated write on a protected branch
git add . on a feature branch allow gated write off a protected branch
rm -rf build abstain not recognized → normal prompt
npm install abstain not a read
cat a.txt && rm b.txt abstain one segment mutates state

Only the Bash tool is inspected; every other tool is left untouched.

Install

Install the saferead command with uv:

uv tool install saferead

Enable the hook

Register the hook in your Claude Code settings:

saferead install            # prompts for global or project settings.json
saferead install --project  # writes to ./.claude/settings.json

This writes a PreToolUse entry (matcher Bash) whose command is the full path to the installed saferead binary — a direct exec on the hot path, with no launcher overhead. The target settings.json is backed up first and any existing hook entries are left untouched; re-running is idempotent. The entry looks like:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [ { "type": "command", "command": "/home/you/.local/bin/saferead" } ] }
    ]
  }
}

Configuration

Configuration is optional — saferead ships with safe built-in defaults. Two TOML files are read, both optional:

File Trust Purpose
~/.config/saferead/config.toml trusted your global settings
$CLAUDE_PROJECT_DIR/.claude/saferead.toml untrusted per-project overrides

The project file can only narrow trust (add protected branches, disable recognizers) — it can never broaden the allow-set for git writes, by design.

Every key is optional; the values below are the built-in defaults:

[git]
protected_branches = ["master", "main"]           # ask on a gated git write on these branches
gated_subcommands  = ["add", "commit", "stash"]    # which git writes are gated

[recognizers]
disabled = []   # recognizer tags to turn off (those commands then abstain)

[python]
allowed_modules = ["math", "datetime", "json"]  # modules the `python -c` analyzer admits
allowed_methods = []                            # extra read-only methods to admit

[read]
local_allowed_roots = []   # empty = allow any path; non-empty restricts file reads to these roots
ssh_allowed_roots   = []

[logging]
enabled = true                       # audit log of every allow/ask decision (ON by default)
path = "/tmp/claude-hook-audit.log"  # where that audit log is written

Logs

saferead writes two files under /tmp:

  • Audit log (/tmp/claude-hook-audit.log) — one JSON line per allow/ask decision. On by default; configure or disable it via the [logging] table above.
  • Error log (/tmp/claude-hook.log) — internal diagnostics if the hook ever hits an error (it always abstains rather than crashing). Fixed path, not configurable.

Updating

uv tool upgrade saferead

License

GPL-3.0-or-later

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

saferead-0.1.3.tar.gz (160.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

saferead-0.1.3-py3-none-any.whl (110.8 kB view details)

Uploaded Python 3

File details

Details for the file saferead-0.1.3.tar.gz.

File metadata

  • Download URL: saferead-0.1.3.tar.gz
  • Upload date:
  • Size: 160.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saferead-0.1.3.tar.gz
Algorithm Hash digest
SHA256 9d722b9b4a4c7051d800470adf2b887bcb557375759283da33a43d65ef772e3c
MD5 62f810f62024c93cf83cd38b928fb646
BLAKE2b-256 9e2b5ad07e443a09c6f6b09a12f94fcc8f49feebb37fb042ad2d43f580ef7bb1

See more details on using hashes here.

Provenance

The following attestation bundles were made for saferead-0.1.3.tar.gz:

Publisher: release.yml on tovmeod/saferead

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file saferead-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: saferead-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 110.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saferead-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 c7fa26aee901b0e072e3d5d173e1729ac8e59426ba4d34164836719c800485c3
MD5 1e3ca128dbf6c7015507d5936cda8257
BLAKE2b-256 a44a4c4248884a80b3e1cb1e627b084a77c873e6e7d72dd977a653026d238e2a

See more details on using hashes here.

Provenance

The following attestation bundles were made for saferead-0.1.3-py3-none-any.whl:

Publisher: release.yml on tovmeod/saferead

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page