npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gemini-cli-extension-han

v0.1.0

Published

Han bridge for Gemini CLI - enables Han's validation hooks and plugin ecosystem in Gemini CLI sessions

Readme

Han Bridge for Gemini CLI

Bridge extension that brings Han's full plugin ecosystem to Gemini CLI — validation hooks, core guidelines, 400+ skills, and 25 agent disciplines.

What This Does

Han plugins define validation hooks, specialized skills, and agent disciplines that run during Claude Code sessions. This bridge makes the entire ecosystem work in Gemini CLI:

  1. Hooks — PreToolUse, PostToolUse, and Stop validation (biome, eslint, tsc, etc.) with parallel execution
  2. Guidelines — Core principles (professional honesty, no excuses, skill selection) injected via GEMINI.md
  3. Datetime — Current time injected on every agent turn via BeforeAgent
  4. Events — Unified JSONL logging with provider: "gemini-cli" for Browse UI visibility

Coverage Matrix

| Claude Code Hook | Gemini CLI Equivalent | Status | |---|---|---| | PostToolUse | AfterTool | Implemented (failures return decision:"deny" with the errors as reason, hiding the tool result) | | PreToolUse | BeforeTool | Implemented | | Stop | AfterAgent | Implemented | | SessionStart | SessionStart | Implemented | | SessionEnd | SessionEnd | Implemented (advisory; runs SessionEnd Han hooks if any, then flushes the event log) | | UserPromptSubmit | BeforeAgent | Implemented | | PreCompact | PreCompress | Implemented | | SubagentStart/Stop | — | Not available | | Permission denial | BeforeTool decision:"deny" | Implemented | | MCP tool events | — | Not available | | — | BeforeModel / AfterModel | Intentionally unsupported (Han has no model-level hooks) | | — | BeforeToolSelection | Intentionally unsupported (Han has no tool-selection hooks) |

Plugin discovery reads the current enabledPlugins boolean map (what han plugin install writes) as well as the legacy plugins object map from Claude Code settings, and resolves marketplace source paths relative to the marketplace root.

Validation Flow

AfterTool (Primary Validation Path)

When the agent edits a file:

Agent edits src/app.ts via write_file
  -> Gemini CLI fires AfterTool hook
  -> Bridge maps write_file -> Write (Claude Code name)
  -> Matches PostToolUse hooks (biome, eslint, tsc)
  -> Runs hooks in parallel
  -> On failure: returns decision:"deny" with validation errors as reason
  -> Tool result is hidden; the agent sees the errors instead and fixes them

AfterAgent (Stop Validation)

When the agent finishes a turn:

Agent signals completion
  -> Gemini CLI fires AfterAgent hook
  -> Bridge runs Stop hooks (full project lint, typecheck, tests)
  -> If failures: returns decision:"block" to force continuation
  -> Agent gets another turn to fix project-wide issues

BeforeTool (Pre-Execution Gates)

Before a tool executes:

Agent about to run a tool
  -> Gemini CLI fires BeforeTool hook
  -> Bridge matches PreToolUse hooks
  -> If any hook rejects: returns decision:"deny"
  -> Tool execution is blocked

Setup

Prerequisites

Han plugins must be installed:

curl -fsSL https://han.guru/install.sh | bash
han plugin install --auto

Bun is required for running the bridge scripts.

Install the Extension

Use the install script to set up the Gemini CLI extension:

# From the han repo
bash plugins/bridges/gemini-cli/install.sh

# Or clone and install
git clone --depth 1 https://github.com/TheBushidoCollective/han.git /tmp/han
bash /tmp/han/plugins/bridges/gemini-cli/install.sh /tmp/han/plugins/bridges/gemini-cli
rm -rf /tmp/han

The install script copies the extension to ~/.gemini/extensions/han/ and sets up the correct hooks configuration for Gemini CLI.

Verify installation:

gemini extensions list
# Should show "han" extension

Note: The source repository stores Gemini CLI hooks in gemini-hooks.json (not hooks/hooks.json) to avoid conflicts with Claude Code's plugin validation. The install script places them at the correct hooks/hooks.json path that Gemini CLI expects.

Architecture

Gemini CLI Hook System
  |
  |-- SessionStart ──────────────> Plugin discovery + coordinator start
  |     hooks/hooks.json            -> systemMessage with capability summary
  |
  |-- BeforeAgent ───────────────> Datetime injection
  |     hooks/hooks.json            -> additionalContext with current time
  |
  |-- BeforeTool (matcher: *) ───> PreToolUse hooks
  |     hooks/hooks.json            -> decision:"deny" if validation fails
  |
  |-- AfterTool (matcher: write_file|replace) ──> PostToolUse hooks
  |     hooks/hooks.json            -> decision:"deny" + reason with validation errors
  |
  |-- AfterAgent ────────────────> Stop hooks (full project validation)
  |     hooks/hooks.json            -> decision:"block" if failures
  |
  |-- SessionEnd ────────────────> SessionEnd hooks (if any) + event log flush
  |     hooks/hooks.json            -> advisory, CLI does not wait
  |
  |-- GEMINI.md ─────────────────> Core guidelines context
  |     (loaded automatically)       (professional honesty, no excuses, etc.)
  |
  |-- JSONL event logger ────────> Browse UI visibility
        ~/.han/gemini-cli/projects/   (provider="gemini-cli")

Bridge Internals (src/):
  bridge.ts        Entry point (stdin JSON → handler → stdout JSON)
  discovery.ts     Read settings + marketplace + resolve plugin paths
  matcher.ts       Filter by tool name, file globs, dirsWith
  executor.ts      Spawn hook commands as parallel promises
  formatter.ts     Structure results as Gemini CLI JSON responses
  cache.ts         Content-hash caching (SHA-256)
  context.ts       Session context + datetime injection
  skills.ts        Skill discovery (counting)
  disciplines.ts   Discipline discovery (counting)
  events.ts        JSONL event logger (provider="gemini-cli")
  types.ts         Gemini CLI + Han type definitions

How Plugins Stay Compatible

Han plugins don't need modification to work with Gemini CLI. The bridge reads the same han-plugin.yml files that Claude Code uses:

# This config works in Claude Code, OpenCode, AND Gemini CLI
hooks:
  lint-async:
    event: PostToolUse
    command: "npx -y @biomejs/biome check --write ${HAN_FILES}"
    tool_filter: [Edit, Write, NotebookEdit]
    file_filter: ["**/*.{js,jsx,ts,tsx}"]
    dirs_with: ["biome.json"]

The difference is in who executes the hook:

  • Claude Code: Reads hooks.json, calls han hook run via shell
  • OpenCode: Bridge reads han-plugin.yml, runs command as JS promise
  • Gemini CLI: Bridge reads han-plugin.yml, runs command as child process, returns JSON

Same hook definition. Same validation. Different runtime.

Gemini CLI Hook Protocol

Gemini CLI hooks communicate via stdin/stdout JSON:

  • Input (stdin): { "tool_name": "write_file", "tool_input": { "path": "src/app.ts", ... } }
  • Output (stdout): { "decision": "allow" } or { "decision": "deny", "reason": "Validation errors..." }
  • Logging (stderr): All debug output goes to stderr (stdout is reserved for JSON)

Exit codes:

  • 0: Success — Gemini CLI parses stdout JSON
  • 2: Critical block — Gemini CLI aborts the action
  • Other: Warning — Gemini CLI continues unchanged

Event Logging

The bridge writes Han-format JSONL events to ~/.han/gemini-cli/projects/. Each event includes provider: "gemini-cli" to distinguish Gemini CLI sessions from Claude Code and OpenCode sessions.

On SessionStart, the bridge launches the Han coordinator in the background. The coordinator watches the events directory and indexes events into SQLite, making them visible in the Browse UI.

Remaining Gaps

  • MCP tool events: Gemini CLI doesn't fire AfterTool for MCP server tool calls. Validation only runs for built-in tools.
  • Subagent hooks: No Gemini CLI equivalent for SubagentStart/SubagentStop.
  • Persistent state: Each hook invocation is a separate process. Plugin discovery runs on every invocation (fast but not cached across invocations).

Development

# From the han repo root
cd plugins/bridges/gemini-cli

# The bridge uses TypeScript directly (Bun handles it)
# No build step required

License

Apache-2.0