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.

Requirements

uv is the only prerequisite. uvx fetches and runs saferead on demand (cached after first use) and provides the Python 3.11+ runtime — there is nothing to install.

Enable the hook

Add saferead as a PreToolUse hook in your Claude Code settings — ~/.claude/settings.json (all projects) or a project's .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [ { "type": "command", "command": "uvx saferead" } ] }
    ]
  }
}

That's it. On each Bash command uvx runs saferead, which reads the PreToolUse payload on stdin and returns a decision. To pin a version, use uvx saferead@0.1.1.

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

Unpinned (uvx saferead) runs from uv's cache. Pull the newest release with:

uvx --refresh saferead

Or pin the version in your hook command (uvx saferead@<version>) and bump it when you want to upgrade.

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.2.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.2-py3-none-any.whl (110.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: saferead-0.1.2.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.2.tar.gz
Algorithm Hash digest
SHA256 cba2ee2481af35bf383b9d22904f27d662ae3ca2072880e9725387fcdeb1663f
MD5 10fc96084828c739827857f997b57678
BLAKE2b-256 aeeea25aa92b7152eee3abd9fc2039222e4058ec7032dd04787348d23371299f

See more details on using hashes here.

Provenance

The following attestation bundles were made for saferead-0.1.2.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.2-py3-none-any.whl.

File metadata

  • Download URL: saferead-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 110.9 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d9c40c5beea26bacd0f5fca720df953413f857ecb8eb93c3761cde5c0cf88b44
MD5 bbd6902de77f6bdb7e1862bdf72dc67a
BLAKE2b-256 186cdb3ce81acfcd237900ecb0ffcd39fa31e7881b0f551376695663af0e7c06

See more details on using hashes here.

Provenance

The following attestation bundles were made for saferead-0.1.2-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