HITL: "Always allow this tool" via Glean ToolPreferences (set_tool_approval gateway meta-tool)#42
Draft
pragati-agrawal-glean wants to merge 5 commits into
Draft
HITL: "Always allow this tool" via Glean ToolPreferences (set_tool_approval gateway meta-tool)#42pragati-agrawal-glean wants to merge 5 commits into
pragati-agrawal-glean wants to merge 5 commits into
Conversation
Replace the run_tool HITL prompt's empty elicitation schema with a single
enum picker offering four scopes:
- Allow for this task -> approve this one call (default)
- Allow in this session -> remember for the session (session-allow-store)
- Allow across sessions -> remember always (tool-permissions-store)
- Decline -> not executed
Before prompting, run_tool now skips the gate when the tool is already
granted for the session or across sessions (per-tool key), alongside the
existing bypassPermissions skip. "always" persists to a local ~/.glean file
using the same flat key shape as Glean's user-settings store
(pluginToolApprovals.<tool> = "true") behind a swappable seam, so it can move
to the backend settings API once the plugin can reach it.
setup({reset}) clears the persistent store. Fail-closed behavior is
unchanged: any non-accept action, an explicit "decline" choice, or a
timeout/error never executes the action.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Simplify the scoped-approval prompt to match the Glean Assistant model: Accept = allow once, or tick "Always allow this tool" to persist. Drop the per-session tier — it can't be represented on a remote MCP server (no client-local session state) and shouldn't diverge from Assistant. - Elicitation schema is now a single boolean field, which Claude Code renders as an inline checkbox shown upfront, instead of a string enum (which CC renders as a collapsed ▶ accordion that hides the choices). - Remove src/session-allow-store.ts and all session wiring. - Message spells out: "Accept = allow once. Tick the box to always allow". - "always" still persists via tool-permissions-store using the Glean user-settings key shape (pluginToolApprovals.<tool>) behind a swappable seam. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The single "Always allow this tool" checkbox + Accept/Decline is self-explanatory; the extra hint line was clutter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add GLEAN_REMOTE_TOOL_APPROVALS (default off). When on, "always allow this tool" upserts to Glean's per-user settings (saveusersettings/listusersettings, key pluginToolApprovals.<tool>) AND the local file; reads prefer the remote value and fall back to the local file when the remote call fails (unscoped/offline). Off = today's local-only behavior. - New src/remote-approvals.ts: best-effort REST transport (bearer from loadCredentials, origin from resolveServerUrl); never throws. - New src/approval-keys.ts: shared key namespace (avoids a store<->remote cycle). - tool-permissions-store.ts: async + flag dispatch + in-process read cache. - run-tool.ts / index.ts: await the now-async store calls. - Tests: remote-approvals (injected fetch) + store dispatch (mocked remote): remote-preferred reads, local fallback on failure, dual write, no-throw. - README: document the flag + the internal:web_api scope caveat. Scope caveat: the plugin's MCP-scoped token can't hit saveusersettings (needs internal:web_api) — flag ships off; local fallback keeps grants working. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oval gateway meta-tool
Replace the REST/local-file persistence (which 401s: the plugin's MCP-scope token
can't call /api/v1/saveusersettings) with a call to a new set_tool_approval
MCP-gateway meta-tool, so "always allow" lands in the same ToolPreferences store
Glean Assistant uses (surface ASSISTANT). Reads already come back via find_skills'
requires_approval (honored by the gate); a process-local session set gives
immediate effect before the next find_skills refresh.
- run-tool.ts: on "always", best-effort callRemoteTool("set_tool_approval",
{server_id, tool_name, value:"ALWAYS_ALLOWED"}) + sessionApproved set; gate
short-circuits on the session set. No persisted local store.
- Delete remote-approvals.ts, approval-keys.ts, tool-permissions-store.ts (+ tests).
- index.ts: drop the tool-permissions reset.
- Depends on the scio set_tool_approval meta-tool (separate PR) to actually
persist; until deployed the call errors and is swallowed (execution unaffected).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pragati-agrawal-glean
force-pushed
the
pragati/hitl-scoped-approvals
branch
from
July 24, 2026 07:56
208f83f to
dad0d59
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
HITL "Always allow this tool" for
run_tool, persisted to Glean the way Glean Assistant does.The approval prompt shows a single inline checkbox above the built-in Accept/Decline:
booleanfield because Claude Code renders that as an inline checkbox (a stringenumrenders as a collapsed accordion — verified from the CC binary).Persistence — via Glean's shared ToolPreferences (not local, not REST)
Ticking "always allow" calls the new
set_tool_approvalMCP-gateway meta-tool (companion: askscio/scio#265738), which writes the user's preference to the sameToolPreferencesstore Assistant uses (surfaceASSISTANT). It's read back throughfind_skills' existingrequires_approval(already honored by the gate), so approvals unify with Assistant and need no plugin-side storage. A process-local session set gives immediate effect before the nextfind_skillsrefresh.Why not local/REST: the plugin's dynamic-registration token holds only the
MCPscope;POST /api/v1/{save,list}usersettingsand/toolpreferencesneedinternal:web_api(empirically 401). The gateway meta-tool is the only reachable write path — hence the scio companion PR.Changes
src/tools/run-tool.ts— single-checkbox schema; on "always", best-effortcallRemoteTool("set_tool_approval", {server_id, tool_name, value:"ALWAYS_ALLOWED"})+ session set; gate short-circuits on the session set. A failed persist never breaks execution.src/remote-approvals.ts,src/approval-keys.ts,src/tool-permissions-store.ts(+ tests) — the earlier REST/local-file design (superseded).src/index.ts— dropped the tool-permissions reset.Testing
npm run typecheckclean ·npm test→ 195 passed ·npm run buildclean.Rollout
Until scio#265738 deploys, the
set_tool_approvalcall errors and is swallowed (execution unaffected); reads still honor any Assistant-set approvals viafind_skills.🤖 Generated with Claude Code