Skip to content

fix(hooks): prompt on every exec write, including flagged calls - #232

Draft
christiaan-ph wants to merge 3 commits into
mainfrom
fix/gate-exec-write-flags-and-write-list
Draft

christiaan-ph wants to merge 3 commits into
mainfrom
fix/gate-exec-write-flags-and-write-list

Conversation

@christiaan-ph

Copy link
Copy Markdown

Problem

  • Users who allow-list mcp__posthog__exec and rely on the plugin's write gate get no approval prompt on many PostHog writes.
  • With POSTHOG_MCP_EXEC_GATE_DENY="*", documented as "prompt on every write", survey-stop, workflows-publish, cdp-functions-publish, opt-outs-add and 61 other unflagged write tools run silently. 15 of them carry destructiveHint: true.
  • In the default configuration, call --confirm insight-delete {} and call --no-skills insight-delete {} run silently, while call insight-delete {} prompts.
  • The gate classified a write from a hardcoded verb regex, and the deny globs only applied to tools that regex matched. DENY could narrow that set but never widen it.
  • The tool-name parser skipped only --json, so any other leading flag was read as the tool name.
  • Reported through a support ticket by a team relying on the gate. The server-side counterpart is (mcp): always-allow reads and prompt on writes over a single connection posthog#104559.

Changes

  • A write call now prompts whenever the tool is in hooks/write-tools.txt or its name carries a write verb. DENY="*" now covers every write.
  • A call with leading flags (--json, --confirm, --no-skills, in any order) now prompts the same as the bare call.
  • hooks/write-tools.txt lists the 457 registry tools with readOnlyHint: false. scripts/generate-write-tools.sh builds it from services/mcp/schema/tool-definitions-all.json on PostHog/posthog master with curl and jq, and refuses to write a list under 100 entries.
  • The daily skill sync workflow runs the generator and stages the list, so the list refreshes with the plugin. A generator failure keeps the committed list and emits a warning.
  • The gate stays pure bash and fails open: a missing or unreadable list falls back to the verb regex.
  • Mechanical: patch version bumps on the four manifests and marketplace.json.

Note

Default installs change only for flagged calls: no list-only tool matches the default deny globs. Users who set POSTHOG_MCP_EXEC_GATE_DENY to a broad glob will see prompts on writes that ran silently before.

How did you test this code?

  • ./tests/test_gate_exec_write.sh passes under macOS /bin/bash 3.2 as well as bash 5.3. CI covers Ubuntu only.
  • New case: call --confirm insight-delete {} prompts. Catches the parser regression.
  • Changed case: deny="*" now uses survey-stop, a write with no regex verb, so it exercises the list path. The previous case used experiment-update, which the regex already matched, and passed without reaching the deny check.
  • New case: made-up-tool-delete prompts, so the regex fallback survives the list.
  • Piped payloads for cdp-functions-publish, organization-enforce-2fa-execute, --no-skills insight-delete and --json --confirm insight-delete through the hook with DENY="*": all prompt. insight-get and --json insight-get stay silent.
  • Not run: the sync workflow end to end. The generator ran locally and produced the committed list.
  • Not run: a live Claude Code session.

🤖 Agent context

  • Autonomy: agent-written, human-directed. Claude Code, model Claude Fable 5.1.
  • Skills: writing-pr-descriptions, writing-code-comments.
  • The list-based classification was chosen over extending the verb regex. Both a write-verb list and a read-verb list misclassify real tool names: feature-flags-test-evaluation-create is read-only but has a write verb, and batch-export-delete is destructive but a read-verb list would pass it on export.

🤖 Generated with Claude Code

christiaan-ph and others added 3 commits September 22, 2026 17:05
`call` accepts `--json`, `--confirm` and `--no-skills` before the tool
name. The gate only skipped `--json`, so any other leading flag was read
as the tool name and the call never prompted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The gate decided whether a call was a write from a hardcoded verb regex,
and the deny globs only applied to tools that regex matched. Tools such
as `survey-stop`, `workflows-publish` and `opt-outs-add` never prompted,
even with POSTHOG_MCP_EXEC_GATE_DENY="*".

`hooks/write-tools.txt` lists every registry tool with
readOnlyHint=false. A tool on that list is a write; the verb regex stays
as the fallback when the list is missing or a tool is newer than the
list. The skill sync workflow regenerates the list with
scripts/generate-write-tools.sh.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant