finding (ops-gh): 2026-05-05 - 113 raw gh invocations denied by Claude in 35d while coily ops gh exists and works #36
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally filed by @coilysiren on 2026-05-18T03:42:49Z - https://github.com/coilysiren/coily/issues/221
Migrated from
coily-ops-gh-meta/findings/2026-05-05-claude-bypasses-coily-gh-wrapper.mdon 2026-05-17 as part of coilysiren/coily#215. Original file preserved in git history; see deletion commit on coilysiren/coily#215.2026-05-05 - 113 raw
ghinvocations denied by Claude in 35d whilecoily ops ghexists and worksWhat was observed
Sweep of
~/.claude/projects/**/*.jsonlover the 35-day window: 113Permission to use Bash with command X has been deniedentries where the denied command begins withgh. The denied invocations are mostly read-only:gh repo list coilysiren --limit 50gh issue list --repo coilysiren/eco-mcp-app --state opengh run list --repo coilysiren/repo-recall --branch main --limit 5gh issue view 21 --repo coilysiren/agentic-os-kaigh api repos/coilysiren/agentic-os-kai/issues/21In the same window,
coily gh.*verbs landed 1000+ audit rows (gh.run.list, gh, gh.issue.create, gh.api, gh.search.issues, gh.issue.view, etc.). The wrapper exists and is exercised. Claude reaches for rawgh113 times anyway and gets blocked at the Claude-Code permission boundary.By comparison: only 2 raw
dockerand 2 rawkubectldenials in the same window.ghis the standout.Why it slipped
Two compounding gaps:
coily ops ghas the auto-approved alternative. The Bash permission denial fires before Claude has a chance to route to the wrapper. The agent learns "gh is blocked" but not "coily ops gh is the path."gh.run.list(seemetachar-gate-context-blindfinding) makes the wrapper appear unreliable. When the agent does try the wrapper, it gets rejected. When it tries raw, it gets denied. The asymmetry teaches the agent that gh is fundamentally hard, not that it should be routed differently.The wrapper's existence does not enforce its use. Lockdown is the mechanism that does, but the audit shows lockdown was applied only 12 times in the window with 0 failures - it works, but its rollout is incomplete across operator sessions.
Rule it produced
Anti-signal: "the wrapper exists, therefore the agent uses it." False. The agent uses the path of least denial. Raw
ghdenied by Claude Code without naming the wrapper is the path the agent learns. Without lockdown actively in place for the session, raw is the default reach.The forward shape: ensure Claude Code's permission denial messages name the wrapper. Either (a) inject a hint into the deny text from coily's lockdown layer ("blocked - try
coily ops gh ..."), or (b) make lockdown the default-on state for any session that has coily installed.Linked: the metachar finding above explains why the wrapper sometimes feels broken when reached for. Both findings need to land together for the gh story to actually improve.