Originally published at omerbinsaleem.com by Omer Bin Saleem (Omer Saleem).

I wanted a scheduled claude -p job that only reads files. I tested which flags keep project hooks out while the subscription login keeps working.

What changed

  • Our weekly rules lint now runs four read-only claude -p passes with this flag set: one each for conflicts, stale lines, drift and duplicates.
  • launchd runs it on Mondays, so nobody has to remember it.

How to do it

  1. Test before you trust a flag. Make a throwaway folder whose .claude/settings.json has a SessionStart hook that touches a file. Run claude -p there and check whether the file appears.
  2. Pass --setting-sources "" so no settings files load. On Claude Code 2.1.314 the hook did not run, and my subscription login still worked and returned an answer. With --setting-sources project, the hook ran.
  3. Skip --bare if you log in with a subscription. It reads only ANTHROPIC_API_KEY and never OAuth or the keychain, so it was unusable for me.
  4. Limit the run to reading: --tools Read,Grep,Glob with the same list in --allowedTools, plus --strict-mcp-config, --no-session-persistence and --output-format text.
  5. macOS has no timeout command. Wrap the call in perl -e 'alarm shift; exec @ARGV' . A killed run exits with code 142, so the script can check for that code.
  6. The stock macOS bash 3.2 cannot parse a heredoc inside $( ) when the text has a backtick. Load the prompt with IFS= read -r -d '' var <<'EOF' || true instead.

Prompt to copy

Write a bash script for macOS that runs claude -p headless and read-only. Use exactly these flags: --tools Read,Grep,Glob --allowedTools Read,Grep,Glob --strict-mcp-config --setting-sources "" --no-session-persistence --output-format text. Wrap the call in perl -e 'alarm shift; exec @ARGV' <SECONDS> and report exit code 142 as a timeout. Load the prompt with IFS= read -r -d '' PROMPT <<'EOF' || true, never a heredoc inside $( ), because bash 3.2 breaks on backticks there. Then give me a test: a temp folder whose .claude/settings.json has a SessionStart hook that touches a file, and a check that the file was not created. 

I am Omer Bin Saleem, a frontend chapter lead who builds with AI every day. One practical AI hack a day at omerbinsaleem.com. LinkedIn: omer-bin-saleem · Instagram: @iomerbinsaleem.

Written with AI assistance, from my own work notes.