Skip to Content
Cardinal UIAgent OutcomesInstall: Gemini CLI plugin

Install the Gemini CLI plugin

The cardinal-gemini-plugin puts your Google Gemini CLI sessions on the Agent Outcomes dashboard, matching the Claude Code, Codex CLI, and Cursor plugins:

  • Telemetry — Gemini CLI ships a native OpenTelemetry exporter; the plugin points it directly at Cardinal ingest so gemini_cli.token.usage, gemini_cli.tool.call.*, gemini_cli.api.request.*, and session/config/agent/compression events arrive without any hook code. Plugin-owned hooks emit the same Cardinal event contract as the sibling plugins on top, so sessions are attributed to engineer, branch, PR, and initiative with per-turn token and tool usage.
  • MCP tools — a managed cardinal MCP server entry, installed as a Gemini CLI extension bundle under ~/.gemini/extensions/cardinal/, exposing whichever tools your org has integrations for. Pass --telemetry-only to skip this side.

Sessions in a git repo receive the initiative branch-naming convention at start, and org spend-limit policies are enforced in-session — quiet context at notify, a visible message at warn, a stopped turn at block. Verdicts are cached locally, so the spend gate never adds a network hop to your prompt path.

Reach out to support@cardinalhq.io for support or to ask questions not answered in our documentation.

Requirements

  • Gemini CLI 0.26.0 or later, where hooks are on by default. Earlier versions need hooks explicitly enabled in Gemini CLI’s settings.
  • Python 3.11+ on your PATH.
  • A Cardinal account on app.cardinalhq.io, or a self-hosted Cardinal UI your operator has prepared (see Connect AI clients).

1. Install

Gemini CLI doesn’t have a plugin marketplace, so the install is a git clone + run:

git clone https://github.com/cardinalhq/cardinal-gemini-plugin.git ~/workspace/cardinal-gemini-plugin

2. Connect

python3 ~/workspace/cardinal-gemini-plugin/plugins/cardinal-gemini-plugin/scripts/cardinal-connect

The connect script prints a URL like https://app.cardinalhq.io/connect?code=ABCD-EFGH. Open it in your browser, sign in if you aren’t already, pick the org to connect, and click Approve. The plugin picks up your consent within a few seconds and writes:

FileWhat gets written
~/.gemini/extensions/cardinal/gemini-extension.jsonExtension manifest with the mcpServers.cardinal entry, tagged cardinalManaged: true.
~/.gemini/extensions/cardinal/hooks/hooks.jsonManaged Cardinal hook entries for SessionStart, BeforeAgent, AfterModel, AfterTool, PreCompress, and SessionEnd.
~/.gemini/extensions/cardinal/GEMINI.mdContext file loaded into the model context by Gemini CLI.
~/.gemini/settings.jsonManaged telemetry block pointing Gemini CLI’s native OTLP exporter at Cardinal ingest.
~/.gemini/cardinal.jsonNon-secret connection state for status/disconnect.
~/.gemini/cardinal-secrets.jsonYour minted keys, written mode 0600.

For self-hosted Cardinal UI, add --host:

python3 scripts/cardinal-connect --host https://ui.example.internal

With --host set, nothing touches Cardinal Cloud: your Cardinal UI runs the consent flow, mints the keys, and hands the plugin your endpoints. The telemetry side requires your operator to have set MAESTRO_INGEST_ENDPOINT on the Cardinal UI deployment (see Environment variables); without it the connect bundle omits telemetry and sessions never reach the dashboard.

Then restart Gemini CLI so it reloads MCP, hooks, and extensions.

3. Verify

python3 scripts/cardinal-status

You’ll see the connected org, both endpoints, key prefixes, and a reachability probe against each side. Run a session in any git repo and it appears on the Outcomes dashboard within a few minutes.

Variants

python3 scripts/cardinal-connect --telemetry-only # Outcomes dashboard only; skip the MCP tools python3 scripts/cardinal-connect --rotate # Mint fresh keys, overwrite an existing connection python3 scripts/cardinal-connect --no-extension # Skip the extension bundle (MCP + GEMINI.md), keep telemetry python3 scripts/cardinal-connect --host https://… # Point at a self-hosted Cardinal UI python3 scripts/cardinal-connect --dry-run # Walk the consent flow, write nothing

Getting attributed correctly

Sessions are attributed to an initiative by branch name: <type>/<kebab-name>, where the type prefix is one of feat, fix, refactor, infra, chore, research, or spike (for example feat/outcomes-observability → initiative outcomes-observability, type feature). Sessions on main/master/develop/trunk are treated as research/scoping work. The plugin surfaces this convention to Gemini at the start of every session so branches it cuts for you classify cleanly.

Upgrading from before 0.17.0

Plugin versions before 0.17.0 wrote a hook registration that Gemini CLI ignored, so their hooks never ran. Re-run cardinal-connect to rewrite it (no new consent needed), then restart Gemini CLI. cardinal-status reports an old registration or a Gemini CLI version too old to load hooks.

Pull requests and decisions

Each prompt’s branch state includes the branch’s pull request when gh is installed and signed in and a PR exists. Network work runs in the background, so the hooks don’t slow your prompts.

Decision capture is off by default:

python3 scripts/cardinal-decision on

While it’s on, each prompt tells Gemini to record material choices with cardinal-decision record …, and each decision is sent tagged with the session, repo, branch, and PR. python3 scripts/cardinal-decision off turns it off. With Gemini CLI’s sandbox enabled, the record command can’t write ~/.gemini; it exits with a message telling you to allow that path or run without the sandbox.

Storyboard associations

From version 0.20.4, the plugin tells Gemini CLI how Cardinal’s storyboards relate to your work, and records where a storyboard was written. See Associations for the model: a storyboard is about something someone declared, or written from a checkout.

  • At session start, with Cardinal connected, the plugin gives Gemini this session’s id and shows storyboards about or written from the work in this repository, including after a merge. Gemini HTML-escapes < and > in what it receives, so the block arrives as &lt;cardinal-storyboards&gt;; it is still delimited. It adds the cardinal-storyboard command (context, discover).
  • Edited files are recorded after write_file and replace succeed.
  • Context filled in automatically by a BeforeTool hook, for the cardinal server’s storyboard tools only.
  • No lookup before an edit. That is Claude Code only.
  • Upgrading. Re-run cardinal-connect so the BeforeTool and edit-recording hooks are registered, then restart Gemini CLI.
  • Opt out. CARDINAL_STORYBOARD_SESSION_START=0 drops the session id line and the discovery block; CARDINAL_STORYBOARD_DISCOVERY=0 drops the discovery block only; CARDINAL_STORYBOARD_CONTEXT=0 stops Gemini CLI from filling in session_id and context.
  • What it sends. Repository, branch, commit, pull request number and ticket key from the branch name, and (on main) recently merged pull request numbers and your recent local branch names, to your own Cardinal. Files edited are repository-relative paths, visible to members of your org and never on a public link. See Associations.

Privacy

The plugin captures tool names, bash command lines, and file paths so Cardinal can tell which repo and service a session worked on. The contents of your prompts are never captured. Per-turn token counts come straight from Gemini CLI’s AfterModel hook payload — no transcript scraping — and are attributed to the model id the hook reports. Hooks don’t receive cached-token counts, so reported cost is an upper bound.

From version 0.18.0, the result of every tool call (Gemini’s own tools such as run_shell_command and read_file, and any MCP server, failed calls included) is kept locally as storyboard evidence, in ~/.cardinal/evidence/ on your machine, with credentials scrubbed, and deleted after 14 days. Cardinal’s own tools are skipped: their results are already witnessed. A call that touches something sensitive, such as a .env file, a private key or a secret-printing command, is withheld: only a stub saying why is kept. The plugin never uploads the spool; a result leaves your machine only when you cite it in an Investigation Storyboard and the plugin’s scripts/cardinal-evidence promotes it. To opt out, set CARDINAL_EVIDENCE_CAPTURE=0 in the environment Gemini CLI starts with, or create the file ~/.cardinal/evidence/disabled.

Payload-shape capture

The hooks follow Gemini CLI’s published hook payload types, but haven’t been observed widely in the wild. If your sessions look sparse, set CARDINAL_GEMINI_DEBUG_PAYLOADS=1 before starting Gemini CLI — raw hook payloads land under ~/.gemini/cardinal/telemetry/debug/<Event>-<ts>.json. Share those with the plugin maintainers so the parity spec can be locked to real key names.

Disconnect

python3 scripts/cardinal-disconnect # Remove everything the plugin added python3 scripts/cardinal-disconnect --force # Skip the reachability probe on the revoke step

Disconnect revokes the keys with Cardinal and removes only the plugin-owned settings, extension bundle, and local state; everything else in your Gemini CLI config is left as it was.

Last updated on