Prerequisites

  1. Elixir >= 1.14
  2. Gemini CLI installed and authenticated:
# Install the Gemini CLI (or just have npx available -- the SDK finds it automatically)
npm install -g @google/gemini-cli

# Authenticate
gemini auth login
  1. cli_subprocess_core brings in a native subprocess dependency transitively, so a C compiler is required for the native build. On Debian/Ubuntu:
sudo apt install build-essential

Installation

Add gemini_cli_sdk to your dependencies in mix.exs:

def deps do
  [
    {:gemini_cli_sdk, "~> 0.2.0"}
  ]
end

Then fetch and compile:

mix deps.get
mix compile

Quick Start

The streaming API returns a lazy Stream that yields typed event structs as the Gemini CLI produces output:

GeminiCliSdk.execute("Explain GenServer in 3 sentences")
|> Enum.each(fn event ->
  case event do
    %GeminiCliSdk.Types.MessageEvent{role: "assistant", content: text} ->
      IO.write(text)
    _ ->
      :ok
  end
end)

Synchronous

For simple request/response usage:

{:ok, response} = GeminiCliSdk.run("What is Elixir?")
IO.puts(response)

With Options

opts = %GeminiCliSdk.Options{
  model: GeminiCliSdk.Models.fast_model(),
  timeout_ms: 60_000
}

{:ok, response} = GeminiCliSdk.run("Summarize OTP", opts)

How It Works

GeminiCliSdk starts a core-backed Gemini CLI session through cli_subprocess_core. That shared transport lane brings in a native subprocess runtime transitively for:

  • Process group management (proper cleanup on halt)
  • Separate stdin/stdout/stderr streams
  • Signal delivery (SIGTERM, SIGKILL)
  • Non-blocking async I/O

The CLI is invoked with --output-format stream-json, which emits newline-delimited JSON (JSONL). Each line is parsed into a typed Elixir struct. The stream is lazy and composable with all standard Stream and Enum functions.

Next Steps