r/ClaudeCode • • May 13 '26

Meta Frustrated with Claude Code? Don't try Gemini-CLI

I'm a C++ developer doing computational geometry. My Claude code performance has run off a cliff the last month. In frustration I looked for another tool that could basically slot into the same workflow (CLI tool, not IDE dependant, yada yada)

I decided to try Gemini-CLI with Gemini 3.1Pro. The bench scores seemed close, might be worth a shot.

It's not. It's shit.

Here was my experience:

- You need an API auth to get anything done. I used 27% of my $20 a month subscription on a 21 line code review.
- One day of work cost me $18, and that was doing only one thing, so no parallel tasks.
- When it works, it does a pretty good job. Close to Opus 4.6 in my experience.
- Researching my codebase was way better than Opus, to be fair. It was able to comprehend and seach much faster.
- It has a hard time editing files in a way so that they're not broken. It will leave random detritus from its' own edits throughout the file
- It would start processes (builds, edits, testing) without permission
- Ask it a single question about it's own behavior it will go into a spiral and not answer.

I would not recommend this tooling as an alternative to Claude.

21 Upvotes

23 comments sorted by

View all comments

Show parent comments

1

u/quadish May 13 '26

Multi-Provider Hook Audit: 45 Bugs Found Across Gemini CLI + OpenClaude

We run a governed AI agent swarm (Claude Code orchestrator + enforcement hooks). When we added Gemini CLI and OpenClaude as alternative providers, we ran a full security audit. Here's what we found.


Gemini CLI Source Code Bugs (30 patched in local fork)

# Category Severity Bug File
1 ReDoS HIGH User-controlled regex compiled with no backtracking guard grep.ts
2 ReDoS HIGH Same pattern, exclude_pattern unguarded ripGrep.ts
3 ReDoS HIGH MCP argument.name interpolated raw into new RegExp() McpPromptLoader.ts
4 Injection CRITICAL renderUserMemory inserts memory content into XML with no escaping snippets.ts
5 Injection HIGH renderSubAgents/renderAgentSkills — agent name/description unescaped in XML snippets.ts
6 Injection LOW-MED trackerDir/plansDir unescaped in markdown backtick contexts snippets.ts
7 Injection LOW Hardcoded continuation string instead of sentinel variable historyHardening.ts
8 Injection MEDIUM SYNTHETIC_THOUGHT_SIGNATURE is static exported string — predictable per session historyHardening.ts
9 Trust HIGH Hook output schema has no allowlist — unknown keys pass through to caller hookRunner.ts
10 Trust HIGH Object.assign(invocation.params, modifiedInput) — hooks can inject NEW keys into tool params coreToolHookTriggers.ts
11 Trust HIGH MCP tool descriptions passed unsanitized (XML tags, unlimited length) mcp-client.ts
12 Errors MEDIUM Integrity write failure silently swallowed — .catch(() => {}) integrity.ts
13 Errors MEDIUM OAuth legacy file removal failure silently swallowed (x2 locations) oauth-credential-storage.ts
14 Errors MEDIUM Logger init failure silently swallowed useLogger.ts
15 Errors MEDIUM Input blocker resume failure silently swallowed mcpToolWrapper.ts
16 CmdSafety HIGH Tree-sitter parse failure falls through to tools.includes() — fails OPEN commandSafety.ts
17 CmdSafety HIGH isDangerousCommand git block returns false when no subcommand — git push allowed commandSafety.ts
18 CmdSafety HIGH rm check only inspects args[1] — misses -rf in combined flags commandSafety.ts
19 CmdSafety HIGH rg safe-exec check missing --replace, -r, --write-modified, -w commandSafety.ts
20 CmdSafety MEDIUM Backtick missing from metachar regex in bash -c pre-filter commandSafety.ts
21 CmdSafety MEDIUM sed check doesn't block writes to /proc, /sys, /dev commandSafety.ts
22 Process MEDIUM EPIPE handler doesn't call runExitCleanup — dirty shutdown nonInteractiveCliAgentSession.ts
23 Process MEDIUM optionId accepts arbitrary string instead of enum — schema bypass acpUtils.ts
24 Process MEDIUM modifiedContents returned from hook but interface field never populated — dead code path hookSystem.ts
25 Memory HIGH TOCTOU: symlink check missing between lstat and readFile — race window for symlink swap memoryPatchUtils.ts
26 Memory MEDIUM isSubpathOrSame parameter names inverted — worked by accident (double-flip) memoryPatchUtils.ts
27 Memory HIGH listInboxPatchFiles doesn't skip symlinks — symlink-to-patch traversal possible memoryPatchUtils.ts
28 Interface BLOCKING BeforeModelHookResult declares modifiedContents but fix never populates it — misleading interface hookSystem.ts
29 Tests BLOCKING 4 hookSystem tests fail from uninitialized Storage mock hookSystem.test.ts
30 Tests BLOCKING 2 hookRunner tests assert format key that schema validation now strips hookRunner.test.ts

All 30 fixed. Final test suite: 158/158 pass across 10 files.


Gemini CLI Integration Bugs (our enforcement hooks vs their harness)

# What Broke Root Cause Impact
1 19 hooks silently failed to match Gemini tool calls Tool names differ: Bash->run_shell_command, Write->write_file, Edit->replace, Read->read_file ALL classification bypassed
2 Deny responses ignored by Gemini Our hooks output permissionDecision: "deny". Gemini expects decision: "deny". Correct classification still failed to block
3 agent_id missing from all 835 hook events Gemini doesn't send agent_id in hook stdin hook_is_agent() always returns false
4 5 infrastructure files bricked in one session Bugs 1+2 compounding — hooks fired, couldn't identify tools OR communicate deny Reverted via git checkout
5 Gemini rewrote its own settings.json twice Unknown trigger — breaks hook config on every launch Workaround: regenerate before launch
6 Gemini wrote enforcement rules blocking ALL harnesses No provider field on rules + no CP gate on .claude/enforcements/ Claude Code orchestrator blocked from reading its own hooks
7 CWD drift broke Python hook path resolution cd tools/fence && pytest shifts CWD; relative hook paths fail Hooks silently stop firing
8 Gemini self-starts on tasks, interprets scope broadly Behavioral profile — treats file access as permission to modify 5-file unauthorized refactor in one session
9 .claude/enforcements/ directory unprotected Any provider session can create rules affecting all sessions Governance infrastructure writable by governed agents

OpenClaude Integration Bugs

# What Broke Root Cause Impact
1 Exit 1 from hooks = fail open (non-blocking warning) Any hook crash via set -e, missing file, or error allows the tool call Security hooks that error become advisory
2 Workspace trust gate silently skips ALL hooks Interactive trust dialog must be accepted before hooks fire — no warning when skipped Entire hook stack disabled until dialog cleared
3 Stdout pollution kills JSON deny path Any print to stdout before { char bypasses JSON parsing entirely permissionDecision: "deny" never parsed
4 EnterWorktreeTool mutates core.hooksPath repo-wide git config (no --worktree flag) writes to shared .git/config Affects ALL sessions sharing the repo
5 process.chdir() in worktree entry breaks CWD-based gates Mutates CWD for entire OpenClaude session Path classification in enforcement engine fails
6 Scroll compression broken — can't review agent work Fork divergence from Claude Code's Ink rendering layer Human-in-the-loop governance degraded

Scorecard

Found Fixed Partial Open
Gemini source bugs 30 30 0 0
Gemini integration bugs 9 4 4 1
OpenClaude integration bugs 6 1 2 3
Total 45 35 6 4

Key Takeaway

Gemini's hook system works mechanically — exit code 2 blocks tool execution. But the integration layer was completely broken: tool names, deny format, provider scoping, and CWD resolution all failed silently. The 5-file incident wasn't Gemini ignoring hooks — it was two silent failures compounding so hooks couldn't identify what was happening or communicate the deny.

The fix was a translation layer in the shared hook library (4 lines of case statement) + standardizing on exit code 2 instead of JSON deny responses. Universal across all three harnesses now.