Skip to content

feat: add Gemini CLI support via rtk init --gemini#174

Closed
ousamabenyounes wants to merge 9 commits intortk-ai:developfrom
ousamabenyounes:feat/gemini-support
Closed

feat: add Gemini CLI support via rtk init --gemini#174
ousamabenyounes wants to merge 9 commits intortk-ai:developfrom
ousamabenyounes:feat/gemini-support

Conversation

@ousamabenyounes
Copy link
Contributor

@ousamabenyounes ousamabenyounes commented Feb 17, 2026

Summary

Introduce first-class support for Gemini CLI by adding a dedicated initialization mode that provides token optimization with the same ease-of-use as Claude Code integration.


Key Features

Core Implementation

  • New flag: rtk init --global --gemini for one-command setup
  • BeforeTool hook integration: Automatic command rewriting via ~/.gemini/settings.json
  • Smart configuration: JSON-based hook registration compatible with Gemini CLI's event system
  • Graceful uninstall: rtk init -g --uninstall removes all Gemini artifacts cleanly

Hook Mechanism

  • Auto-rewrite: Intercepts run_shell_command tool calls before execution
  • JSON I/O: Structured input/output format per Gemini CLI specification
  • Command mappings: 20+ common commands (git, npm, docker, kubectl, file ops)
  • Transparent operation: Gemini never sees the original command

User Experience

  • Intelligent upsert: GEMINI.md updates preserve user content (via upsert_rtk_block)
  • Status verification: rtk init --show displays Gemini configuration state
  • Slim reference: ~/.gemini/RTK.md provides concise command documentation
  • Easy validation: gemini /hooks confirms hook registration

Technical Details

Files Changed

src/init.rs                    +426 -21  (hook logic, settings.json patching)
scripts/test-gemini-init.sh    +91       (automated integration tests)
INSTALL.md                     +21 -1    (Gemini setup guide)
README.md                      +8 -3     (quick start updates)
src/main.rs                    +7 -1     (CLI flag addition)

Architecture Decisions

Separate hook implementation (REWRITE_GEMINI_HOOK):

  • JSON-structured output (vs. Claude's text-based format)
  • Event-driven architecture (BeforeTool matcher)
  • Explicit settings.json registration (vs. auto-discovery)

Reused core logic:

  • upsert_rtk_block(): Consistent update mechanism across AI tools
  • ensure_hook_installed(): Parameterized for hook content injection
  • uninstall(): Extended to handle both Claude and Gemini artifacts

Robust error handling:

  • Settings.json creation if missing
  • Hook deduplication (prevents multiple registrations)
  • Graceful degradation on JSON parse failures

Testing Strategy

Comprehensive test coverage via scripts/test-gemini-init.sh:

  1. Fresh installation: Verifies all files created with correct permissions
  2. Upsert behavior: Confirms user content preservation during updates
  3. Hook registration: Validates settings.json structure and hook presence
  4. Clean uninstall: Ensures complete artifact removal

All tests use isolated $HOME to avoid pollution.


Usage Example

# Installation
rtk init -g --gemini

# Verification
gemini /hooks
# Expected output:
# BeforeTool hooks:
#   - rtk-rewrite (run_shell_command)

# Transparent usage
gemini "show me git status"
# → Hook rewrites to: rtk git status
# → Output: ~15 tokens (vs ~150 standard)

Documentation Updates

  • INSTALL.md: Dedicated Gemini CLI Setup section with verification steps
  • README.md: Quick Start updated with parallel Claude/Gemini instructions
  • GEMINI.md: Auto-generated usage guide with command mappings and token savings

Compatibility

  • Gemini CLI: v0.26.0+ (requires BeforeTool hooks support)
  • RTK: All versions (backward compatible)
  • Dependencies: Requires jq for JSON parsing in hook script

Migration Path

Existing Gemini users can adopt RTK with zero config changes:

rtk init -g --gemini  # One command, full setup
gemini /hooks         # Verify
# Start using Gemini normally - commands auto-optimized

Checklist

  • Code follows project style guidelines
  • Tests pass locally (cargo test)
  • New tests added (scripts/test-gemini-init.sh)
  • Documentation updated (INSTALL.md, README.md)
  • No security concerns (reviewed with project security policy)
  • Backward compatible (existing Claude Code users unaffected)

Author: Ousama Ben Younes ([@ousamabenyounes](https://github.com/ousamabenyounes))

Implementation Notes:
This PR was developed using AI-assisted coding with Gemini AI. The architecture, testing strategy, and integration design were manually crafted; code generation was AI-assisted and manually reviewed.

# 2. Initialize for Claude Code (RECOMMENDED: hook-first mode)
rtk init --global
# 2. Initialize (RECOMMENDED: hook-first mode)
rtk init --global # For Claude Code
Copy link

@bleleve bleleve Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep it understandable/simple in six months, I will have taken this approach:

  • rtk init --claude
  • rtk init --gemini
  • rtk init --global -> auto CLIs detection (search for ~/.gemini and ~/.claude)

(By the way, Hey Ousama, I hope you are doing well 😄)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a PR in progress similar to this one.
#158

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! I’m doing great, hope you are too 🙂

I’m aligned with your approach and implementing it in a lightweight way.

There was #131, but it was considered too large and needed splitting.
So I decided to move forward with a lighter, more focused version instead.

I’ve also applied the requested fixes:
feat: auto-detect CLIs with rtk init --global, add --claude flag

I’m against duplicate work… just like I’m against copy-paste code 😄
Happy to align if #158 already covers it.

@ousamabenyounes ousamabenyounes force-pushed the feat/gemini-support branch 2 times, most recently from 6b2e23b to c22f6d0 Compare February 18, 2026 12:10
@ahundt
Copy link

ahundt commented Feb 19, 2026

hey just a heads up I've had one version of gemini support available for a bit here: #158

@FlorianBruniaux
Copy link
Collaborator

Hi @ousamabenyounes, the integration design is thoughtful. The idempotent upsert_rtk_block() approach, the clean uninstall logic, and the isolated test script using a temporary $HOME are all well-done.

Before this can move forward, one issue to fix and one broader question:

  1. The diff modifies hooks/rtk-rewrite.sh, which is currently used by Claude Code users in production. Could you confirm the Claude Code hook output format and detection logic are still fully correct after your changes? The file now needs to serve both Claude Code and Gemini, and a regression here would be silent and hard to diagnose.

  2. PR Gemini CLI Hook Support (PR #131 Part 3) #158 by @ahundt also implements Gemini support, using a compiled Rust binary (rtk hook gemini) rather than a bash script. These are incompatible approaches and we need to align on one before either can merge. The Rust binary approach avoids the jq dependency and works natively on Windows, but your PR has better init ergonomics and more complete uninstall logic. Could you share your reasoning for the bash approach? We'd like to coordinate with @ahundt on a path that combines the best of both without landing two competing implementations.

@ousamabenyounes
Copy link
Contributor Author

Thanks for the detailed review @FlorianBruniaux — both points were spot on.

Why I initially went with shell:
The first iteration modified hooks/rtk-rewrite.sh directly because it was the fastest path to a working Gemini hook. Gemini CLI uses a BeforeTool hook format similar to Claude Code's PreToolUse, so reusing the same bash script with a different JSON output seemed natural. However, this created regression risk for the Claude Code hook which is already in production.

Why I pivoted to Rust:
After your feedback and the direction the project took (delegating all rewrite logic to rtk rewrite), I decided to move the Gemini hook fully to Rust as well. The result:

  • src/hook_cmd.rs — A standalone Rust module that handles Gemini's BeforeTool hook protocol. It reads JSON from stdin, pattern-matches commands, and outputs the Gemini-format JSON response (hookSpecificOutput.tool_input).
    49 unit tests cover all command families (git, cargo, docker, kubectl, Python, Go, npm, etc.). No dependency on jq.
  • hooks/rtk-rewrite.sh — Restored to the upstream thin delegator (rtk rewrite). No modifications and no regression risk.
  • Gemini hook in init.rs — Reduced from a 95-line bash script to a 3-line wrapper: exec rtk hook gemini. All logic now lives in Rust.

Live testing on both CLIs:

  • Gemini CLI: cargo test is correctly rewritten to rtk cargo test — output goes from 342+ lines to a single summary line. git status is rewritten with compact output. Hook protocol verified via debug logging.
  • Claude Code: No regression — hook rewrites work identically to before. Tested with git status, git log, git diff, and cargo check.
  • Uninstall: rtk init -g --uninstall cleanly removes all files for both CLIs (hooks, RTK.md, GEMINI.md, settings.json entries).

Automated tests:

  • 761 tests passing (759 unit + 2 integration)
  • 89 smoke test assertions, 0 failures
  • test-gemini-init.sh: fresh install, upsert, uninstall — all 6 assertions pass

@yogasw
Copy link

yogasw commented Mar 8, 2026

Will this work in antigravity? If so, how can I try it?

Related to this discussion #233

@ousamabenyounes
Copy link
Contributor Author

I haven't used Antigravity yet so I can't test it directly.
However, since Antigravity is built on top of Gemini CLI (same GitHub repo, same ~/.gemini/ config directory), our
hook should work out of the box — it's a standard BeforeTool hook on run_shell_command registered in ~/.gemini/settings.json.

If someone with Antigravity access wants to test it, the setup is simply:
rtk init -g
Then verify the hook is active and try any shell command (e.g. git status, cargo test).

If Antigravity uses a different tool name or hook protocol than Gemini CLI, we'd need to adapt — happy to do so if someone can share the hook input JSON format.

@pszymkowiak
Copy link
Collaborator

Hi @ousamabenyounes, sorry — there have been a lot of changes on master since this PR was opened. Could you please rebase on latest master? Thanks!

ousamabenyounes and others added 8 commits March 11, 2026 09:51
Introduce first-class support for Gemini CLI by adding a dedicated
initialization mode. This allows Gemini users to benefit from RTK's
token optimization with the same ease as Claude Code users.

- Add --gemini flag to 'rtk init' command
- Implement run_gemini_mode() in src/init.rs for global setup
- Automated installation of the rewrite hook in ~/.gemini/hooks/
- Intelligent GEMINI.md patching using upsert_rtk_block (preserves user content)
- Support for ~/.gemini/RTK.md slim instructions
- Update 'rtk init --show' to display Gemini configuration status
- Update 'rtk init -g --uninstall' to clean up Gemini artifacts
- Add comprehensive automated test: scripts/test-gemini-init.sh
- Update INSTALL.md and README.md with Gemini setup instructions

Collaboration:
- Vision & Prompt Architecture: Ousama Ben Younes
- Technical Implementation: Gemini AI (Google)

Co-authored-by: Gemini AI <assistant@google.com>
Introduce first-class support for Gemini CLI by adding a dedicated
initialization mode. This allows Gemini users to benefit from RTK's
token optimization with the same ease as Claude Code users.

- Add --gemini flag to 'rtk init' command
- Implement run_gemini_mode() in src/init.rs for global setup
- Automated installation of the rewrite hook in ~/.gemini/hooks/
- Intelligent GEMINI.md patching using upsert_rtk_block (preserves user content)
- Support for ~/.gemini/RTK.md slim instructions
- Update 'rtk init --show' to display Gemini configuration status
- Update 'rtk init -g --uninstall' to clean up Gemini artifacts
- Add comprehensive automated test: scripts/test-gemini-init.sh
- Update INSTALL.md and README.md with Gemini setup instructions

Collaboration:
- Vision & Prompt Architecture: Ousama Ben Younes
- Technical Implementation: Gemini AI (Google)

Co-authored-by: Gemini AI <assistant@google.com>
…ed functions

- Convert all French comments in REWRITE_GEMINI_HOOK constant to English
- Translate doc comments and inline comments in patch_gemini_settings_json
- Maintain exact same functionality, only language changes
- Fix grep pattern for cargo test output (add 'passed' detection)
- Replace skip with skip_test for pytest, ruff, pip, go, golangci-lint
- Skip learn test when Claude Code not installed
- Result: 0 failures, 87 passed, 6 skipped
Replace 95-line bash Gemini hook with a Rust binary approach:
- New src/hook_cmd.rs: standalone Gemini BeforeTool hook processor
  with 49 unit tests covering all command families (git, cargo,
  docker, kubectl, Python, Go, npm, etc.)
- Uses correct Gemini CLI protocol: hookSpecificOutput.tool_input
  (not updatedInput) for command rewriting
- Zero dependency on jq for Gemini users
- Gemini hook in init.rs reduced to 3-line wrapper: exec rtk hook gemini
- hooks/rtk-rewrite.sh restored to upstream thin delegator (no regression)
- Tested end-to-end on both Claude Code and Gemini CLI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ousamabenyounes
Copy link
Contributor Author

Done! Rebased on latest master (0.28.2). Full test suite is green:

  • ✅ cargo fmt --check — OK
  • ✅ cargo clippy --all-targets — 0 errors
  • ✅ cargo test — 814 passed, 2 ignored
  • ✅ cargo test -- --ignored — 2 passed
  • ✅ test-all.sh — 0 failures
  • ✅ validate-docs.sh — versions 0.28.2, 61 modules consistent

- Add 3 smoke tests for Gemini CLI hook:
  - rewrites git status to rtk git status
  - passes through non-rewritable commands (echo)
  - skips already-rewritten commands (no double-rewrite)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ousamabenyounes ousamabenyounes changed the base branch from master to develop March 12, 2026 20:40
ousamabenyounes added a commit to ousamabenyounes/rtk that referenced this pull request Mar 13, 2026
- Add `rtk hook gemini` command: native Rust hook processor for Gemini CLI
  BeforeTool hooks. Reads JSON from stdin, delegates to `rewrite_command()`
  (single source of truth), outputs Gemini-format JSON response.
- Add `--gemini` flag to `rtk init`: installs hook wrapper script, GEMINI.md,
  and patches ~/.gemini/settings.json with BeforeTool hook entry.
- Add `rtk init -g --gemini --uninstall`: clean removal of all Gemini artifacts.
- 6 unit tests covering hook format, rewrite delegation, and exclusions.

Replaces PR rtk-ai#174 which had too many conflicts after upstream restructuring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ousama Ben Younes <benyounes.ousama@gmail.com>
@ousamabenyounes
Copy link
Contributor Author

Closing in favor of #573 — clean reimplementation on latest develop branch. The old branch had 9 commits with 6+ merge conflicts after upstream restructuring.

Key improvements in the new PR:

  • Reuses rewrite_command() from registry instead of duplicating rewrite rules (single source of truth)
  • Additive only — no modifications to existing Claude Code or OpenCode hooks
  • Minimal diff — 4 files, 412 additions (vs 98 files, 10K+ lines of conflict)

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.

6 participants