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

# AI Coding Tools

> Send usage telemetry from Claude Code, GitHub Copilot, OpenAI Codex, and LiteLLM into Navigara to measure AI adoption, cost, and impact.

Navigara measures how your organization actually uses AI coding assistants — cost, tokens, models, and which developers are active — by ingesting **usage telemetry** from the tools themselves. Every AI tool emits [OpenTelemetry](https://opentelemetry.io) (OTLP), and Navigara exposes an OTLP endpoint that turns that stream into per-developer, per-model spend on the [Tool Spend](https://app.navigara.com/tool-spend) dashboard.

<Info>
  **Any plan or license works — we support them all.** Ingestion is pure OpenTelemetry, independent of how you pay for the tool. There's nothing to buy or upgrade to be measured.
</Info>

<Note>
  **You control what leaves the workstation.** By default Navigara collects only **usage metadata** — session and user IDs, model, cost, token counts, durations, and tool names. Each tool's own telemetry flags let you opt into richer signals (prompt text, tool inputs/outputs, raw API bodies) — for Claude Code, for example, `OTEL_LOG_USER_PROMPTS`, `OTEL_LOG_TOOL_DETAILS`, `OTEL_LOG_TOOL_CONTENT`, and `OTEL_LOG_RAW_API_BODIES`. Send as much or as little as you choose.
</Note>

## How it works

```mermaid theme={null}
graph LR
    Tool["AI tool<br/>(Claude Code / Copilot / Codex / LiteLLM)"] -->|OTLP/HTTP| OTLP["Navigara OTLP endpoint<br/>/api/otlp"]
    OTLP -->|attributed by email| Spend["Tool Spend dashboard"]
```

1. **You mint an ingest token** — a write-only API token scoped to your organization.
2. **You configure the tool** to export OTLP metrics (and logs, for identity) to Navigara's endpoint with that token as a bearer header.
3. **Navigara attributes usage to contributors** by email and materializes it into cost and token metrics. Usage shows up in **Tool Spend** within a few minutes.

## Set up a connection (recommended)

The fastest path is the built-in wizard — it mints the token and generates the exact config for you:

<Steps>
  <Step title="Open the AI tools group">
    Go to **Settings → Connections**. Alongside **Source control** and **Task tracking**, there is an **AI tools** group — "Usage telemetry from AI coding assistants".
  </Step>

  <Step title="Pick a tool and name the connection">
    Choose Claude Code, GitHub Copilot, OpenAI Codex, or LiteLLM, then give the connection a name (e.g. by team, region, or backend). You can add more than one connection per tool.
  </Step>

  <Step title="Generate the token and config">
    Click **Generate token & config**. Navigara mints a write-only ingest token and drops it into a ready-to-copy config block. The token is shown once — copy it now. (Use **Preview config** to see the snippet with a `<YOUR_INGEST_TOKEN>` placeholder without minting anything.)
  </Step>

  <Step title="Roll the config out">
    Apply the config to your workstations, fleet, or proxy using the per-tool instructions below. Usage appears in **Tool Spend** within a few minutes.
  </Step>
</Steps>

## The ingest endpoint and token

If you'd rather wire it up by hand, everything the wizard produces comes down to two values.

**Endpoint** — Navigara serves OTLP/HTTP at `/api/otlp`. OTLP clients append the signal path (`/v1/metrics`, `/v1/logs`) themselves.

| Deployment        | OTLP endpoint                             |
| ----------------- | ----------------------------------------- |
| Cloud SaaS        | `https://app.navigara.com/api/otlp`       |
| Full on-premises  | `https://<your-navigara-host>/api/otlp`   |
| On-prem collector | `http://<collector-host>:<OPS_PORT>/otlp` |

**Ingest token** — create one at **Settings → API Tokens → Create API Token**. Any token works, but a dedicated **Ingest only** token (write-only, cannot read your data) is recommended; the AI-tools wizard mints exactly this. Pass it on every request as:

```
Authorization: Bearer <YOUR_INGEST_TOKEN>
```

<Note>
  **Identity is matched by email.** Navigara joins usage to a contributor using the email the tool reports. Where a tool can't emit an email natively, the snippets below set `enduser.id` (usually from the developer's git email) — make sure it matches the email Navigara already knows the contributor by. Usage that can't be matched still counts toward org totals; it just shows as unattributed until an email resolves.
</Note>

***

## Claude Code

Claude Code has native OpenTelemetry support. It emits cost and token **metrics**, and — on Claude.ai (Team / Enterprise) sign-in — the developer's email, account, and organization IDs on **logs**, which is how usage is attributed.

<Tabs>
  <Tab title="Managed settings (fleet)">
    Ship this file via MDM so developers can't override it:

    * macOS: `/Library/Application Support/ClaudeCode/managed-settings.json`
    * Linux: `/etc/claude-code/managed-settings.json`
    * Windows: `C:\Program Files\ClaudeCode\managed-settings.json`

    ```json theme={null}
    {
      "env": {
        "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
        "OTEL_METRICS_EXPORTER": "otlp",
        "OTEL_LOGS_EXPORTER": "otlp",
        "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
        "OTEL_EXPORTER_OTLP_ENDPOINT": "https://app.navigara.com/api/otlp",
        "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer <YOUR_INGEST_TOKEN>"
      }
    }
    ```
  </Tab>

  <Tab title="Shell snippet (per developer)">
    Add to the shell profile or a `claude` launcher wrapper:

    ```bash theme={null}
    export CLAUDE_CODE_ENABLE_TELEMETRY="1"
    export OTEL_METRICS_EXPORTER="otlp"
    export OTEL_LOGS_EXPORTER="otlp"
    export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
    export OTEL_EXPORTER_OTLP_ENDPOINT="https://app.navigara.com/api/otlp"
    export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <YOUR_INGEST_TOKEN>"
    ```
  </Tab>
</Tabs>

### Attribution by auth model

* **Claude.ai sign-in (Team / Enterprise)** — Claude Code emits the user's email and account IDs natively. Nothing else to add.
* **API key / Bedrock / Vertex** — only an anonymous installation ID is emitted, so set `enduser.id` yourself. Because managed settings are identical on every machine, this belongs in a per-developer launcher, not the shared JSON:

  ```bash theme={null}
  # enduser.id is how usage gets attributed to a developer under API key / Bedrock / Vertex auth.
  attrs="enduser.id=${USER}"
  if git rev-parse --git-dir >/dev/null 2>&1; then
    attrs+=",git.branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo detached)"
    attrs+=",git.repo=$(basename "$(git rev-parse --show-toplevel)")"
    attrs+=",git.commit=$(git rev-parse --short HEAD)"
  fi
  export OTEL_RESOURCE_ATTRIBUTES="$attrs"
  ```

***

## GitHub Copilot

Copilot CLI telemetry is off by default. Copilot configures OTLP through **environment variables only** — its `~/.copilot/config.json` has no telemetry settings — so for a fleet-wide rollout drop these into a shared profile (e.g. `/etc/profile.d/`) or a `copilot` launcher wrapper.

```bash theme={null}
export COPILOT_OTEL_ENABLED="true"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://app.navigara.com/api/otlp"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <YOUR_INGEST_TOKEN>"

# Copilot emits no developer identity on any stream — enduser.id is the only
# attribution lever, matched to a contributor by email. Defaults to your git
# email; override if that isn't the email Navigara knows you by.
export OTEL_RESOURCE_ATTRIBUTES="enduser.id=$(git config user.email)"
```

<Note>
  Copilot CLI does not ship protobuf export yet, so the protocol is pinned to `http/json` — the encoding Navigara accepts for Copilot.
</Note>

***

## OpenAI Codex

Codex configures OTLP through `~/.codex/config.toml`, not environment variables. Telemetry is off by default; this turns on its OTLP exporter and points it at Navigara. Usage rides **metrics**; identity rides **logs**.

```toml theme={null}
# ~/.codex/config.toml
[otel.metrics_exporter.otlp-http]
endpoint = "https://app.navigara.com/api/otlp/v1/metrics"
protocol = "binary"
headers = { Authorization = "Bearer <YOUR_INGEST_TOKEN>" }

[otel.exporter.otlp-http]
endpoint = "https://app.navigara.com/api/otlp/v1/logs"
protocol = "binary"
headers = { Authorization = "Bearer <YOUR_INGEST_TOKEN>" }
```

Codex token-usage metrics carry no developer identity, so set `enduser.id` per workstation. It's a per-developer value, so it belongs in the shell profile, not the shared config file:

```bash theme={null}
export OTEL_RESOURCE_ATTRIBUTES="enduser.id=$(git config user.email)"
```

<Note>
  Codex sets `service.name` per surface (`codex_exec`, `codex_tui`); Navigara collapses these to one `codex` source automatically.
</Note>

***

## LiteLLM

Run one LiteLLM proxy in front of your providers and Navigara captures **proxy-wide** token and cost usage for every tool that routes through it. Requires **LiteLLM 1.89 or newer** — earlier proxies read `OTEL_ENDPOINT` instead and don't append the `/v1/metrics` path, so usage won't arrive.

<Steps>
  <Step title="Enable the OTel callback in config.yaml">
    ```yaml theme={null}
    litellm_settings:
      callbacks: ["otel"]
    ```
  </Step>

  <Step title="Set these on the proxy deployment">
    ```bash theme={null}
    # The otel callback ships spans by default; metrics (token + cost) are opt-in.
    export LITELLM_OTEL_INTEGRATION_ENABLE_METRICS="true"
    export OTEL_EXPORTER="otlp_http"
    export OTEL_EXPORTER_OTLP_ENDPOINT="https://app.navigara.com/api/otlp"
    export OTEL_HEADERS="Authorization=Bearer <YOUR_INGEST_TOKEN>"
    ```
  </Step>

  <Step title="Attribute usage to developers">
    Pick whichever matches how developers authenticate to the proxy. All three land the email in `metadata.user_api_key_*`, which Navigara resolves to a contributor.

    <Tabs>
      <Tab title="Per-user virtual keys">
        Mint a virtual key per developer (`/key/generate` or `/user/new`) and set that user's `user_email` to their git/commit email. LiteLLM exports it as `metadata.user_api_key_user_email`.
      </Tab>

      <Tab title="JWT / OIDC SSO">
        Developers present their SSO token; LiteLLM extracts the email claim. Add to the same `config.yaml`, pointing at whichever claim holds the email:

        ```yaml theme={null}
        general_settings:
          enable_jwt_auth: true
          litellm_jwtauth:
            user_email_jwt_field: "email"
        ```
      </Tab>

      <Tab title="User request parameter">
        Each client sets the OpenAI-compatible `user` field to the developer's email. LiteLLM exports it as `metadata.user_api_key_end_user_id`. Cheapest option — nothing to manage in LiteLLM, but every calling tool must set `user`:

        ```bash theme={null}
        curl $LITELLM_PROXY/v1/chat/completions \
          -H "Authorization: Bearer $YOUR_LITELLM_KEY" \
          -d '{
            "model": "gpt-4o",
            "messages": [{"role": "user", "content": "..."}],
            "user": "dev@yourcompany.com"
          }'
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

***

## Troubleshooting

* **Nothing in Tool Spend after a few minutes** — confirm the endpoint ends in `/api/otlp` (no `/v1/...` suffix except where a tool takes a full per-signal path, like Codex), and that the `Authorization` header carries a valid ingest token. Restart the tool/proxy so it re-reads its config.
* **Usage shows up as unattributed** — the tool isn't emitting a resolvable email. For Copilot and Codex, set `OTEL_RESOURCE_ATTRIBUTES="enduser.id=..."`; for Claude Code under API-key auth, add the `enduser.id` launcher; for LiteLLM, wire one of the three identity models. The email must match the contributor's known email.
* **Attribution resolves a day or two late** — Navigara re-attributes a trailing window automatically, so late-arriving emails backfill without action.
* **LiteLLM sends traces but no cost/tokens** — set `LITELLM_OTEL_INTEGRATION_ENABLE_METRICS=true` and upgrade to LiteLLM ≥ 1.89.
* **Copilot export fails on protobuf** — keep `OTEL_EXPORTER_OTLP_PROTOCOL=http/json`; the CLI doesn't ship protobuf export yet.
