Skip to content

feat(flow-ai): add opt-in hook to auto-approve Flow API reads - #7

Merged
mhusbynflow merged 1 commit into
mainfrom
mhusbynflow/read-auto-approve
Jul 2, 2026
Merged

feat(flow-ai): add opt-in hook to auto-approve Flow API reads#7
mhusbynflow merged 1 commit into
mainfrom
mhusbynflow/read-auto-approve

Conversation

@mhusbynflow

Copy link
Copy Markdown
Contributor

Summary

Ships an opt-in PreToolUse hook, bundled with the flow-ai plugin, that auto-approves the read-only curl calls the skill makes against the Flow API — so users stop getting a permission prompt on every read. Implements docs/specs/read-auto-approve-hook.md.

Authenticated reads inject the token with $(< ~/.config/flow/api-token). Claude Code treats $(...) as a security boundary, so a permissions.allow rule can't silence these calls and "don't ask again" is never offered. A PreToolUse allow decision is the only mechanism that reliably bypasses the prompt for substitution-bearing commands.

Behaviour

  • Off by default. The script makes no decision unless the user sets FLOW_AI_AUTO_APPROVE_READS=1, so the plugin never grants itself a silent permission bypass. Consent is explicit.
  • Read-only. Matches only a command that starts with the flow-ai curl prefix, uses --get, targets flow.bio (or FLOW_API_URL), and is not a POST. Pipeline runs, uploads (flowbio CLI), and non-flow hosts keep prompting.
  • Chaining-safe. A PreToolUse allow suppresses the prompt for the whole Bash line, so a read that chains a second command (;/&&/||/backticks) is rejected — the tail can't ride in unapproved. A single | jq pipe (the skill's own read formatting) stays approved.
  • Version-agnostic. Keys off the flow-ai/ User-Agent prefix, not a pinned version, so it survives release bumps with no edits.

Activation caveat

Claude Code snapshots hooks at session start. After installing the plugin or setting the env var, users must restart Claude Code or run /reload-plugins for the hook to take effect. Documented in the README.

Changes

  • New plugins/flow-ai/hooks/: flow-read-approve.sh (executable), hooks.json (wired via ${CLAUDE_PLUGIN_ROOT}), and flow-read-approve.test.sh (11 tests: the spec's 7 cases + chaining/pipe/alt-POST hardening).
  • plugin.json 0.7.1 → 0.8.0; CHANGELOG entry; README "Reducing permission prompts" section.
  • User-Agent strings bumped to flow-ai/0.8.0 for the repo's version lockstep.
  • CI (validate-skills.yml) now runs the hook test.

Testing

  • `bash plugins/flow-ai/hooks/flow-read-approve.test.sh` → 11 passed, 0 failed.
  • `python3 scripts/validate_skills.py` → 0 errors.
  • Ran through an adversarial review (converged, APPROVED). The --get/;/&&/||/backtick guards were added in response to review findings.

Note for reviewers

The host check uses a *flow.bio* substring (the spec's deliberate design), so a non-Flow host with flow.bio in a query param would match. The skill never emits such a command; flagged in case we want host-anchored matching instead.

🤖 Generated with Claude Code

Authenticated Flow reads inject the token with the command substitution
$(< ~/.config/flow/api-token). Claude Code treats $(...) as a security
boundary, so a permissions.allow rule cannot silence these calls and the
"don't ask again" option is never offered — every read prompts.

Ship a PreToolUse hook, bundled with the plugin and referenced via
${CLAUDE_PLUGIN_ROOT}, that returns permissionDecision "allow" for read-only
Flow curls. It is opt-in: the script makes no decision unless the user sets
FLOW_AI_AUTO_APPROVE_READS=1, so a plugin never grants itself a silent
permission bypass. A read is matched only when the command starts with the
flow-ai curl prefix, uses --get, targets flow.bio (or FLOW_API_URL), and is
not a POST. Pipeline runs, uploads, and non-flow hosts keep prompting.

Because a PreToolUse allow suppresses the prompt for the entire Bash line, a
read that chains a second command (; && || `...`) is rejected so the tail
cannot ride in unapproved; a single `| jq` pipe stays approved. Matching keys
off the flow-ai/ User-Agent prefix, not a pinned version, so it survives
release bumps.

Bumps the version to 0.8.0 and keeps the User-Agent strings in lockstep.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mhusbynflow
mhusbynflow merged commit f2c25cd into main Jul 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant