> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fiddler.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gemini CLI Integration

> Integrate Google's Gemini CLI with Fiddler for coding agent observability — track LLM calls, tool usage, user prompts, and session behavior via OpenTelemetry traces.

## Overview

[Gemini CLI](https://github.com/google-gemini/gemini-cli) is Google's open-source command-line AI agent.
It emits OpenTelemetry traces that follow the [GenAI semantic conventions](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/README.md),
which Fiddler ingests and maps to the Fiddler schema.
This gives you observability over coding agent sessions — including user prompts, LLM calls, tool invocations, token usage, and model output.

No Fiddler SDK is required.
Because Gemini CLI speaks GenAI semantic conventions natively, most attributes arrive with the names Fiddler expects and pass through with little translation.

> [!NOTE]
>
> **Gemini CLI 0.65.0 and later export to Fiddler directly.**
> Version 0.65.0 added the `telemetry.otlpHeaders` setting, which lets Gemini CLI send the `Authorization` and `fiddler-application-id` headers that Fiddler ingestion requires.
> Earlier versions have no settings-file support for OTLP headers, so they use a local OpenTelemetry Collector to inject them.
> See [OpenTelemetry Collector Proxy](#opentelemetry-collector-proxy) if you are pinned to a version before 0.65.0.

| Capability | Support |
| - | - |
| User prompt capture | ⚠️ Requires `traces: true` and `logPrompts: true`; lost when the conversation exceeds Gemini CLI's 10,000-character telemetry cap |
| LLM response capture | ⚠️ Requires `traces: true` and `logPrompts: true`; streamed chunks are rejoined, but the response is lost when it serializes past Gemini CLI's 10,000-character telemetry cap |
| System prompt capture | ✅ From `gen_ai.system_instructions` |
| Tool name tracking | ✅ Via `gen_ai.tool.name` |
| Tool input capture | ✅ Tool-call `args` mapped to `gen_ai.tool.input`; requires `traces: true` and `logPrompts: true` |
| Token counts | ✅ Input and output tokens |
| Session correlation | ✅ Via `gen_ai.conversation.id` |
| Agent name | ✅ Emitted as `gemini-cli` |
| Direct OTLP header auth | ✅ Gemini CLI 0.65.0+ via `telemetry.otlpHeaders` |
| Enrichment (Prompt Safety) | ✅ Via Fiddler evaluator rules |

***

## Prerequisites

* **Gemini CLI** 0.65.0 or later for direct export (`npm install -g @google/gemini-cli`), authenticated with an AI Studio API key, Vertex AI, or a Gemini Code Assist Standard or Enterprise license.
  Personal Google accounts (free, Google AI Pro, and Google AI Ultra) stopped working with Gemini CLI on June 18, 2026.
  Earlier Gemini CLI versions are supported through the [OpenTelemetry Collector Proxy](#opentelemetry-collector-proxy).
* A **Fiddler application** with a valid `application.id` and an API key.

> [!NOTE]
>
> Google reports that Gemini CLI has not been optimized for Gemini 4 Argon and recommends Antigravity for that model.
> Gemini CLI remains supported for the models it does target, and Fiddler ingests its traces the same way regardless of the model in use.

***

## How It Works

Gemini CLI's OTLP exporter sends traces straight to Fiddler's OTLP ingestion endpoint, with the Fiddler authentication headers attached.

```mermaid theme={null}
flowchart LR
    A[Gemini CLI] -- "OTLP/HTTP<br/>+ auth headers" --> B[Fiddler]
```

Fiddler identifies the traces as Gemini CLI's by the OpenTelemetry instrumentation scope name `gemini-cli`, which Gemini CLI sets itself.

***

## Quick Start

### Step 1 — Enable Gemini CLI telemetry

Add a `telemetry` block to `~/.gemini/settings.json` (user scope) or `.gemini/settings.json` (project scope):

```json theme={null}
{
  "telemetry": {
    "enabled": true,
    "traces": true,
    "target": "local",
    "logPrompts": true,
    "otlpEndpoint": "<your-fiddler-url>",
    "otlpProtocol": "http",
    "otlpHeaders": {
      "fiddler-application-id": "<your-application-id>",
      "Authorization": "Bearer <your-api-key>"
    }
  }
}
```

Replace the entire `<your-fiddler-url>` value with your Fiddler instance base URL, including the scheme (for example, `https://app.fiddler.ai`).
Gemini CLI appends `/v1/traces` automatically.

| Setting | Purpose |
| - | - |
| `enabled` | Turns on telemetry. |
| `traces` | Enables detailed span attributes (prompts, tool I/O, token counts). |
| `target` | Set to `local` to use the OTLP exporter rather than direct Google Cloud export. |
| `logPrompts` | Includes prompt and response text in traces. Set to `false` to omit those two attributes only — the system prompt and tool definitions are still exported. See [Only `enabled: false` stops content being exported](#only-enabled-false-stops-content-being-exported). |
| `otlpEndpoint` | Your Fiddler instance base URL. |
| `otlpProtocol` | `http` sends OTLP over HTTP, matching Fiddler's other OTel integrations. |
| `otlpHeaders` | The Fiddler authentication headers. Added in Gemini CLI 0.65.0. |

> [!WARNING]
>
> **Do not commit API keys to version control.**
> The `otlpHeaders` value contains your Fiddler API key.
> If you use a project-level `.gemini/settings.json`, add it to `.gitignore`.
> For CI/CD or shared environments, set the headers through the `GEMINI_TELEMETRY_OTLP_HEADERS` environment variable instead of the settings file.

### Step 2 — Tag traces with your Fiddler application

```bash theme={null}
export OTEL_RESOURCE_ATTRIBUTES="application.id=<your-application-id>,service.name=gemini-cli"
```

Fiddler drops spans that arrive without an `application.id`, and the OTLP headers do not supply one — so this step is required even though `fiddler-application-id` is already in `otlpHeaders`.

### Step 3 — Run Gemini CLI

```bash theme={null}
gemini
```

Use Gemini CLI normally.
Every interaction generates OTel traces that flow to Fiddler.
For a quick smoke test, run it headless:

```bash theme={null}
gemini -p "What is 2 + 2?"
```

### Step 4 — Verify traces in Fiddler

Navigate to your application in the Fiddler UI.
Traces should appear within seconds.

The smoke test above produces **LLM spans only** — one per model call, with token counts and latency.
A prompt that answers directly invokes no tools and starts no sub-agent, so seeing only LLM spans means the integration is working.
Expect more span types as you use the CLI on real work:

* **Tool spans** when a turn invokes a tool, such as reading or writing a file
* **Agent spans** when a turn starts a sub-agent

> [!NOTE]
>
> A single prompt produces more than one LLM span.
> Gemini CLI routes each turn through a lightweight classifier model before calling the main model, and both calls are traced — so expect at least two LLM spans per prompt, on different model names.

> [!NOTE]
>
> **Gemini CLI also exports logs and metrics.**
> Alongside traces it sends log records to `<your-fiddler-url>/v1/logs` and metrics to `<your-fiddler-url>/v1/metrics`, and neither can be turned off independently of telemetry as a whole.
> Fiddler's GenAI ingestion consumes traces: it does not ingest OTel metrics, and its `/v1/logs` path serves a separate opt-in feature that stays disabled unless Fiddler enables it for your organization.
> Expect both exports to be rejected, with Gemini CLI recording the failures in its debug output.
> Trace ingestion is unaffected.
> To avoid the rejected requests, use the [OpenTelemetry Collector Proxy](#opentelemetry-collector-proxy), which forwards traces alone.

***

## What Gets Captured

### Span Hierarchy

Each user interaction produces a trace with the following structure:

```text theme={null}
gemini_cli.agent_call (agent — root span, one per user prompt)
├── gemini_cli.llm_call (llm — LLM API call)
├── gemini_cli.tool_call (tool — tool invocation)
└── gemini_cli.llm_call (llm — follow-up LLM call with tool results)
```

Fiddler prefixes each span name with `gemini_cli.` for a descriptive span group in the UI, matching the pattern used by the [Claude Code integration](https://docs.fiddler.ai/integrations/agentic-ai/claude-code-integration.md).

### Span Type Mapping

Gemini CLI encodes the operation type in the `gen_ai.operation.name` attribute (not the span name).
Fiddler maps it to a Fiddler span type:

| `gen_ai.operation.name` | Fiddler Span Type | Description |
| - | - | - |
| `agent_call`, `invoke_agent` | `agent` | Root span for a user interaction. |
| `llm_call`, `chat` | `llm` | Individual LLM API call with token counts and latency. |
| `tool_call`, `execute_tool` | `tool` | Tool invocation. |
| Anything else (`user_prompt`, `system_prompt`, `schedule_tool_calls`, …) | `unknown` | Sub-operation spans that don't map to a primary type. |

### Captured Attributes by Span Type

#### Agent Spans

| Attribute | Fiddler Field | Description |
| - | - | - |
| `gen_ai.system_instructions` | `gen_ai.llm.input.system` | System prompt for the interaction. |
| `gen_ai.conversation.id` | Passthrough | CLI session ID, used for session correlation. |
| `gen_ai.agent.name` | Passthrough | Agent name (`gemini-cli`, or a sub-agent name when set). |

#### LLM Spans

| Attribute | Fiddler Field | Description |
| - | - | - |
| `gen_ai.input.messages` | `gen_ai.llm.input.user` | User message text, extracted from the messages JSON array. |
| `gen_ai.output.messages` | `gen_ai.llm.output` | Model response text, extracted from the messages JSON array. |
| `gen_ai.system_instructions` | `gen_ai.llm.input.system` | System prompt. |
| `gen_ai.usage.input_tokens` | Passthrough | Number of input tokens. |
| `gen_ai.usage.output_tokens` | Passthrough | Number of output tokens. |
| `gen_ai.request.model` | Passthrough | Requested model identifier. |
| `gen_ai.response.model` | Passthrough | Model that produced the response. |

> [!NOTE]
>
> Gemini CLI sends the request `contents` as a JSON array in the form `[{"role": "user", "parts": [{"text": "…"}]}]`, and the response as a single `{"role": "model", "parts": […]}` object — or, when the response is streamed, as an array with one such object per chunk.
> Fiddler extracts the last user message into `gen_ai.llm.input.user` and the model text into `gen_ai.llm.output` as clean text.
> For a streamed response, the per-chunk objects are rejoined, so `gen_ai.llm.output` holds the complete reply rather than its final fragment.
> See [Content capture is incomplete](#content-capture-is-incomplete) for the cases where this yields nothing.

#### Tool Spans

| Attribute | Fiddler Field | Description |
| - | - | - |
| `gen_ai.tool.name` | Passthrough | Tool identifier. |
| `gen_ai.tool.call_id` | Passthrough | Tool call correlation ID. |
| `gen_ai.tool.description` | Passthrough | Tool description. |
| `gen_ai.input.messages` | `gen_ai.tool.input` | The serialized tool request — tool name, call ID, and the `args` object. Fiddler extracts `args` into `gen_ai.tool.input` and removes the original key. Present when `traces` and `logPrompts` are both `true`. |
| `gen_ai.output.messages` | Removed | Tool result. Stripped, because model output belongs on LLM spans. |

Gemini CLI serializes the tool-call request into `gen_ai.input.messages`, which maps to the `input` semantic concept — the LLM prompt slot.
Left in place, tool arguments would populate **Input** while **Tool Input** stayed empty.
Fiddler relocates the `args` payload to `gen_ai.tool.input`, so tool arguments resolve to `tool_input` and no longer contribute to `input`.

A request that serializes past Gemini CLI's 10,000-character telemetry cap arrives cut short and can no longer be parsed.
Because truncation is what large tool calls look like — a `write_file` carrying file content, a long `run_shell_command` — Fiddler moves the surviving prefix into `gen_ai.tool.input` as-is rather than leaving it in the prompt slot.
The stored value keeps Gemini CLI's `...[TRUNCATED: original length N]` marker, so a partial argument blob is recognizable as partial.

A request Fiddler cannot parse for any other reason — or one that is not shaped like a tool-call request — is left on the span untouched rather than discarded.

> [!WARNING]
>
> **Tool spans capture tool arguments.**
> The `args` object reaches Fiddler as `gen_ai.tool.input` and appears in the **Tool Input** column.
>
> For file-writing tools those arguments include the file content, and for shell tools they include the command being run.
> If that is sensitive, set `logPrompts: false`, which stops Gemini CLI emitting `gen_ai.input.messages` on tool spans as well as LLM spans — leaving Fiddler nothing to extract.
> See [Only `enabled: false` stops content being exported](#only-enabled-false-stops-content-being-exported) for what that does and does not cover.

> [!NOTE]
>
> **Evaluator rules scoped to tool spans should use `tool_input`.**
> A rule that resolves the `input` semantic concept previously scored the tool-request blob on these spans as if it were a user prompt.
> Whenever extraction succeeds, tool arguments no longer resolve to `input`, so such a rule returns nothing on those spans.
> Re-scope it to `tool_input` to keep scoring tool arguments.
>
> Extraction failure is the exception, and it fails open rather than silently dropping the request: an unparseable or unexpectedly shaped payload keeps `gen_ai.input.messages`, which still resolves to `input`.
> Such a span populates neither `tool_input` nor a clean prompt, so an `input`-mapped rule still sees the raw request there.
> Truncated requests are not in this category — they are relocated to `tool_input` like any other, so the largest tool calls do not quietly stay behind in `input`.
> Re-scoping to `tool_input` is what makes the behaviour consistent across both cases.
>
> Rules that read the `gen_ai.llm.input.user` attribute directly are unaffected — that extraction has always run on LLM spans only.

***

## Session Grouping

Gemini CLI assigns a session ID to each coding session and emits it as `gen_ai.conversation.id`.
Fiddler uses this for session-level grouping in the UI, so all spans in a session share the same conversation ID.
This lets you view the full timeline of a session and correlate LLM calls with tool invocations.

When the conversation ID is absent, Fiddler falls back to the OTel `trace_id` as the conversation ID.

***

## Enrichment Setup

Fiddler can automatically score Gemini CLI user prompts using Prompt Safety (powered by the Centor Model for Safety) or other evaluators.
To configure:

1. Navigate to your application in the Fiddler UI.
2. Create an evaluator rule with:
   * **Span type:** `llm`
   * **Text field:** `gen_ai.llm.input.user`
   * **Evaluator:** Prompt Safety (or any custom evaluator)
3. New spans are scored automatically as they arrive.

The user-prompt field, `gen_ai.llm.input.user`, is populated only on `llm` spans — Fiddler extracts it from `gen_ai.input.messages` during LLM-span mapping.
Agent spans carry the system prompt but not the user prompt, so scope the rule to `llm` spans.

> [!WARNING]
>
> **`gen_ai.llm.input.user` is often empty, and enrichment then scores nothing.**
> Gemini CLI truncates telemetry content at 10,000 characters, which leaves the attribute unparseable — and because it sends the whole conversation, including file contents, longer sessions cross that limit routinely.
> Affected spans are scored silently as if no prompt were present.
> See [Content capture is incomplete](#content-capture-is-incomplete).

> [!NOTE]
>
> Enrichment also requires prompt content to be captured at all, which takes two settings rather than one.
> Set both `traces: true` and `logPrompts: true` in the Gemini CLI telemetry settings.
>
> With `enabled: true` alone, Gemini CLI still sends spans, but they carry no conversation: `gen_ai.input.messages` and `gen_ai.output.messages` are both absent.
> Setting `logPrompts: false` omits the same two attributes.
> In both cases they are absent rather than replaced with a placeholder, so `gen_ai.llm.input.user` is never populated and enrichment scores nothing.
>
> Note that neither setting is a content opt-out — the system prompt and tool definitions are exported either way. See [Only `enabled: false` stops content being exported](#only-enabled-false-stops-content-being-exported).
> Traces still arrive and still look healthy in the UI, which makes this easy to miss.

***

## Configuration Reference

### Gemini CLI Telemetry Settings

Set these in `~/.gemini/settings.json` under `telemetry`, or via the corresponding environment variables.

| Setting | Environment Variable | Description |
| - | - | - |
| `enabled` | `GEMINI_TELEMETRY_ENABLED` | Set to `true` to enable telemetry. |
| `traces` | `GEMINI_TELEMETRY_TRACES_ENABLED` | Set to `true` for detailed span attributes. |
| `target` | `GEMINI_TELEMETRY_TARGET` | Set to `local` to use the OTLP exporter. |
| `logPrompts` | `GEMINI_TELEMETRY_LOG_PROMPTS` | Set to `true` to include prompt text. Setting it to `false` omits the prompt and response only, not the system prompt or tool definitions. Only `enabled: false` prevents content export. |
| `otlpEndpoint` | `GEMINI_TELEMETRY_OTLP_ENDPOINT` | OTLP endpoint — your Fiddler base URL, or a collector address. |
| `otlpProtocol` | `GEMINI_TELEMETRY_OTLP_PROTOCOL` | `http` for direct export to Fiddler; `grpc` for the collector path. |
| `otlpHeaders` | `GEMINI_TELEMETRY_OTLP_HEADERS` | Custom OTLP headers. Added in Gemini CLI 0.65.0. The environment variable accepts JSON or comma-separated `key=value` pairs. |

### Resource Attributes

| Variable | Description |
| - | - |
| `OTEL_RESOURCE_ATTRIBUTES` | On the direct-export path, must include `application.id=<uuid>` and `service.name=gemini-cli`. The collector path sets both itself. |

> [!NOTE]
>
> Fiddler routes Gemini CLI traces primarily by the OpenTelemetry instrumentation scope name `gemini-cli`, with `service.name=gemini-cli` as a fallback.
> Gemini CLI sets both itself, so routing works without extra configuration; setting `service.name` in `OTEL_RESOURCE_ATTRIBUTES` keeps it correct if another tool in your environment overrides it.

***

## Troubleshooting

These steps cover the direct-export path.
For the collector path, see [Troubleshooting the collector path](#troubleshooting-the-collector-path).

### No traces in Fiddler

* Verify telemetry is enabled: `cat ~/.gemini/settings.json` and confirm `enabled`, `traces`, and `target: "local"` are all set.
* Confirm your Gemini CLI version is 0.65.0 or later: `gemini --version`.
  Earlier versions ignore the `otlpHeaders` setting, so the requests reach Fiddler without authentication.
* Confirm `otlpEndpoint` is the base Fiddler URL with a scheme and no path (Gemini CLI appends `/v1/traces`).
* Confirm `OTEL_RESOURCE_ATTRIBUTES` includes `application.id`.
  Fiddler drops spans that arrive without it.
* Start a fresh Gemini CLI session — settings apply only to new sessions.

### Authentication errors in the Gemini CLI debug output

* Verify the API key is valid for the application named in `fiddler-application-id`.
* Confirm the `Authorization` header value includes the `Bearer ` prefix.

### Export errors for logs or metrics

Expected.
Gemini CLI exports log records and metrics alongside traces, and Fiddler's GenAI ingestion consumes traces and rejects the other two signals.
Trace ingestion is unaffected.
To stop the rejected requests, use the [OpenTelemetry Collector Proxy](#opentelemetry-collector-proxy).

### Spans classified as `unknown`

Only operations in the mapping table above classify as `agent`, `llm`, or `tool`.
Sub-operation spans such as `user_prompt`, `system_prompt`, and `schedule_tool_calls` classify as `unknown`.
This is expected behavior.

***

## OpenTelemetry Collector Proxy

Use a local OpenTelemetry Collector when you are pinned to Gemini CLI **before 0.65.0**, which has no `telemetry.otlpHeaders` setting, or when you want one shared proxy to hold the Fiddler credentials for several developers.

The collector receives Gemini CLI's traces, adds the Fiddler authentication headers, and forwards traces alone.

```mermaid theme={null}
flowchart LR
    A[Gemini CLI] -- "OTLP/gRPC<br/>localhost:4327" --> B[OpenTelemetry Collector]
    B -- "OTLP/HTTP<br/>+ auth headers" --> C[Fiddler]
```

> [!WARNING]
>
> **One collector serves one Fiddler application.**
> The configuration below stamps every span it receives with a single `application.id` and forwards them with that application's API key.
> Run a separate collector for each Fiddler application you send traces to.

### Prerequisites for this path

* **Docker** to run the OpenTelemetry Collector.

### Step 1 — Configure the OpenTelemetry Collector

Create a collector configuration file, `otel-collector-config.yaml`:

```yaml theme={null}
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4327
      http:
        endpoint: 0.0.0.0:4328

processors:
  # Tag every span so Fiddler routes it to the Gemini CLI mapper and
  # attributes it to this collector's Fiddler application.
  resource:
    attributes:
      - key: service.name
        value: gemini-cli
        action: upsert
      - key: application.id
        value: "${env:FIDDLER_APP_ID}"
        action: upsert
  batch:
    timeout: 5s
    send_batch_size: 128

exporters:
  otlphttp/fiddler:
    endpoint: <your-fiddler-url>
    headers:
      fiddler-application-id: "${env:FIDDLER_APP_ID}"
      Authorization: "Bearer ${env:FIDDLER_API_KEY}"
  # Accept and drop the logs and metrics Gemini CLI also emits, so the
  # receiver answers them instead of refusing an unconfigured signal.
  nop:

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [resource, batch]
      exporters: [otlphttp/fiddler]
    logs:
      receivers: [otlp]
      exporters: [nop]
    metrics:
      receivers: [otlp]
      exporters: [nop]
```

Replace the entire `<your-fiddler-url>` value with your Fiddler instance base URL, including the scheme (for example, `https://app.fiddler.ai`).
The collector appends `/v1/traces` automatically.

Setting `application.id` here rather than relying on each developer's `OTEL_RESOURCE_ATTRIBUTES` keeps routing independent of the client environment.
Only the `traces` pipeline exports to Fiddler.
The `logs` and `metrics` pipelines exist so the OTLP receiver accepts those two signals and drops them.
Without those pipelines the receiver registers no handler for either signal, and Gemini CLI's log and metric exports fail against the collector just as they would against Fiddler.

### Step 2 — Start the collector

Create a `docker-compose.yaml`:

```yaml theme={null}
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.163.2
    container_name: gemini-cli-otel-collector
    volumes:
      - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
    ports:
      # Bind to loopback so the proxy is reachable only from this host.
      - "127.0.0.1:4327:4327"   # gRPC receiver
      - "127.0.0.1:4328:4328"   # HTTP receiver
    environment:
      - FIDDLER_APP_ID=${FIDDLER_APP_ID}
      - FIDDLER_API_KEY=${FIDDLER_API_KEY}
    restart: unless-stopped
```

Provide your Fiddler credentials and start the collector:

```bash theme={null}
export FIDDLER_APP_ID=<your-application-id>
export FIDDLER_API_KEY=<your-api-key>

docker compose up -d
docker compose logs -f   # confirm the collector is listening on 4327/4328
```

> [!NOTE]
>
> This configuration uses collector ports `4327` (gRPC) and `4328` (HTTP) instead of the OpenTelemetry defaults `4317`/`4318` to avoid conflicts with other collectors you may be running.
> Use any free ports you prefer, as long as Gemini CLI points at the same gRPC port.

> [!WARNING]
>
> **Protect your API key.**
> The collector configuration references your Fiddler API key through environment variables.
> Keep any `.env` file that contains it out of version control, and restrict who can read it.

### Step 3 — Point Gemini CLI at the collector

```json theme={null}
{
  "telemetry": {
    "enabled": true,
    "traces": true,
    "target": "local",
    "logPrompts": true,
    "otlpEndpoint": "http://localhost:4327",
    "otlpProtocol": "grpc"
  }
}
```

No `otlpHeaders` entry is needed — the collector supplies the authentication headers.

Then run Gemini CLI and verify traces in Fiddler as the Quick Start describes.
Step 2 of the Quick Start is unnecessary on this path, because the collector sets `application.id` itself.

### Troubleshooting the collector path

* Confirm the collector is running: `docker compose ps`.
* Confirm the gRPC port is reachable: `nc -zv localhost 4327`.
* Check the collector logs for export errors: `docker compose logs -f`.
* Verify `FIDDLER_APP_ID` and `FIDDLER_API_KEY` are set and the API key is valid for the application.

***

## Known Limitations

### OTLP header support requires Gemini CLI 0.65.0 or later

The `telemetry.otlpHeaders` setting was added in Gemini CLI 0.65.0.
Earlier versions offer no way to configure the `Authorization` and `fiddler-application-id` headers that Fiddler ingestion requires, so they need the [OpenTelemetry Collector Proxy](#opentelemetry-collector-proxy) to inject them.

### Content capture is incomplete

Prompt and response text do not always survive the trip from Gemini CLI into Fiddler.

| Case | Effect |
| - | - |
| `traces` or `logPrompts` is not set to `true` | Gemini CLI omits the content attributes entirely, so there is nothing to extract. |
| Conversation or response serializes to more than 10,000 characters | Gemini CLI truncates the serialized value past its telemetry cap. Fiddler detects the truncation and leaves `gen_ai.llm.input.user` or `gen_ai.llm.output` unset. |
| A plain-string prompt exceeds 10,000 characters | The same cap applies to unserialized strings, and the attribute is left unset. |

Truncated content is dropped rather than salvaged, deliberately.
Because Gemini CLI keeps the head of the value and discards the tail, a salvaged prompt would be missing its newest turn while still reading as complete — an evaluator would then score clean against text known to be partial.
Leaving the attribute unset makes the gap visible instead.

Span type, token counts, model names, tool names, and session correlation are unaffected — only the prompt and response text.
Evaluator rules that read `gen_ai.llm.input.user` score only the spans where capture succeeded.

### Only `enabled: false` stops content being exported

Neither `logPrompts` nor `traces` suppresses the system prompt or the tool definitions.
Both are exported whenever telemetry is on at all.

Gemini CLI sets `gen_ai.system_instructions` and `gen_ai.tool_definitions` when it *creates* each LLM span, passing them straight through to the OpenTelemetry tracer.
`logPrompts` and `traces` are checked later, when the span ends, and they govern a different set of attributes.
Neither flag is consulted on the path that writes these two, so both survive `logPrompts: false` and `traces: false` alike.

So a span emitted with `enabled: true` carries at least the following, whatever the other two settings are:

| Attribute | Contents |
| - | - |
| `gen_ai.system_instructions` | The full system prompt, serialized |
| `gen_ai.tool_definitions` | Every tool schema, serialized |
| `gen_ai.request.model` | Model name |
| `gen_ai.prompt.name` | Prompt identifier |
| `gen_ai.conversation.id` | Session identifier |

Fiddler ingests the system prompt from `gen_ai.system_instructions`, so it is stored and visible on the span.

> [!WARNING]
>
> If the system prompt or your tool schemas are sensitive, `logPrompts: false` and `traces: false` are not sufficient.
> Set `enabled: false` to disable telemetry.
> That is the only setting that prevents export, because it stops Gemini CLI initializing the OpenTelemetry SDK at all.

What the two narrower flags *do* control:

* `logPrompts: false` omits `gen_ai.input.messages` and `gen_ai.output.messages` — the conversation, not the system prompt.
* `traces: false` drops the remaining end-of-span attributes, such as token counts, leaving the creation-time attributes above in place.

### Logs and metrics are exported but not ingested

Gemini CLI exports log records and metrics alongside traces and offers no way to disable them individually.
Fiddler's GenAI ingestion consumes traces and rejects the other two signals, which does not affect trace ingestion.
The collector proxy path forwards traces alone and avoids the rejected requests.

### Shared `OTEL_RESOURCE_ATTRIBUTES`

`OTEL_RESOURCE_ATTRIBUTES` is a shared OpenTelemetry environment variable.
If you run multiple agents (for example, Gemini CLI and Claude Code) that target different Fiddler applications, set it per session or use project-scoped settings to avoid cross-tagging traces.

***

## Related Documentation

* [Claude Code Integration](https://docs.fiddler.ai/integrations/agentic-ai/claude-code-integration.md) — Native OTel tracing for Anthropic's CLI coding agent
* [OpenTelemetry Integration](https://docs.fiddler.ai/integrations/agentic-ai/opentelemetry-integration.md) — Manual OTel instrumentation for custom frameworks
* [Strands Agents SDK](https://docs.fiddler.ai/integrations/agentic-ai/strands-sdk.md) — Native monitoring for Strands agent applications
* [Fiddler OTel SDK](https://docs.fiddler.ai/integrations/agentic-ai/fiddler-otel-sdk.md) — Foundation package for custom OTel instrumentation
