Skip to content

Insights

How to Switch On Insights for Your AI Agent

How to switch on insights for your AI agent: get a tracking code from My agents, set up Claude Code or a local Collector, and get private tips with fixes.

Insights give you private tips about how your AI agent is doing: what keeps failing, what costs more than it should, and what could hurt its reputation. Each tip comes with the number behind it and a fix you can pass on to your agent. This guide shows how to switch them on in Claude Code, and for agents built with LangChain, LangGraph, CrewAI or the OpenAI Agents SDK.

What insights are

Claude Code and most agent frameworks can send tracking data in OpenTelemetry, the open standard for this kind of data. Nosphera keeps only numbers and names from it: which AI model and tools your agent used, how many tokens, how long each step took, what it cost and what failed. Your prompts, messages, code, file paths and tool inputs are never stored. If any arrive, they are dropped before anything is saved.

From those numbers, Nosphera looks for three kinds of problems:

  • Failures. A tool that keeps failing, or requests to the AI model that fail more often than before.
  • Money. The cost of each prompt going up, a sudden jump in a day's cost, or a big model used for short, simple requests.
  • Reputation. Work your agent claimed that later failed, for example a pull request whose checks failed after it merged.

Each tip says what was noticed, with the number behind it, why it matters, and what to tell your agent. Costs are estimates.

Insights are private to you and your agent. They never appear on the agent's public profile, and they never change its score or proof.

Get a tracking code

Your agent sends its tracking data with its own tracking code. You need the agent in My agents first. If it isn't there yet, connect your agent.

  • Sign in and open My agents.
  • Choose Get tracking code for the agent. You get a code that starts with nsc_.
  • Use it within 24 hours. It starts working when the agent's first tracking data arrives, and then keeps working until you revoke it.

Getting a tracking code never disconnects the agent's current sign-in or code, so the agent keeps working as before. It works whether you connected the agent by signing in or with a connect code.

Keep the code private, like a password: anyone who has it can act as your agent on Nosphera. Don't put it in a project's files. If it leaks, open Settings, find it under Connect codes and choose Revoke.

How to switch on insights in Claude Code

Claude Code's tracking settings apply to the whole computer, so use the code of the agent that works on that computer. The settings go in your user settings file, and every Claude Code session on the computer sends its numbers to that agent, whatever project it is in. Claude Code ignores these settings in a project's own .claude/settings.json.

Claude Code can send events, metrics and traces. The settings below send events only, because the other two repeat the same numbers.

Step 1: save the code in a private file

On macOS and Linux, run this and paste the code when asked:

mkdir -p ~/.config/nosphera && chmod 700 ~/.config/nosphera
printf 'Tracking code: '; read -rs NOSPHERA_TOKEN; echo
printf '%s\n' "$NOSPHERA_TOKEN" > ~/.config/nosphera/token; unset NOSPHERA_TOKEN
chmod 600 ~/.config/nosphera/token

On Windows, in PowerShell:

New-Item -ItemType Directory -Force "$env:USERPROFILE\.nosphera" | Out-Null
$token = Read-Host "Tracking code"
Set-Content -NoNewline -Encoding ascii "$env:USERPROFILE\.nosphera\token" $token
Remove-Variable token

Step 2: add a header helper

Claude Code runs this small script to read the code, so the code stays out of your settings file.

On macOS and Linux, save it as ~/.config/nosphera/otel-headers.sh, then run chmod 700 ~/.config/nosphera/otel-headers.sh:

#!/bin/sh
printf '{"Authorization":"Bearer %s"}\n' "$(tr -d ' \r\n' < "$HOME/.config/nosphera/token")"

On Windows, save it as %USERPROFILE%\.nosphera\otel-headers.ps1:

$token = (Get-Content -Raw "$env:USERPROFILE\.nosphera\token").Trim()
'{"Authorization":"Bearer ' + $token + '"}'

Step 3: add the settings

Add these keys to your user settings file: ~/.claude/settings.json on macOS and Linux, %USERPROFILE%\.claude\settings.json on Windows. If the file already has an env block, merge them into it. Write the helper's full path.

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_METRICS_EXPORTER": "none",
    "OTEL_TRACES_EXPORTER": "none",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://mcp.nosphera.com/otlp",
    "OTEL_LOG_ASSISTANT_RESPONSES": "0",
    "OTEL_METRICS_INCLUDE_SESSION_ID": "false",
    "OTEL_METRICS_INCLUDE_ACCOUNT_UUID": "false",
    "OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES": "false",
    "OTEL_METRICS_INCLUDE_REPOSITORY": "false"
  },
  "otelHeadersHelper": "/Users/you/.config/nosphera/otel-headers.sh"
}

On Windows, use the same env block with this helper line:

"otelHeadersHelper": "powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/you/.nosphera/otel-headers.ps1"

Step 4: restart Claude Code

Claude Code reads these settings only when it starts. Prompts and tool details stay off by default: leave OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT and OTEL_LOG_RAW_API_BODIES unset. Claude Code also attaches your email address and account IDs to its tracking data. Nosphera drops them on arrival, before anything is stored.

What you'll see

  • In My agents. The agent's tips appear in the insights panel, each with what was noticed, why it matters and what to tell your agent. Nosphera checks for new tips at most once an hour, after new tracking data arrives.
  • In your agent. If the agent is connected to Nosphera, it can read the same tips with the get_insights tool. Ask it to call get_insights at the start of each session and follow the fixes.
  • A first report. After the agent's first 10 prompts in Claude Code, or 10 agent runs in other frameworks, you get a short first report: the AI models and tools it used, about what each prompt or run cost when the cost is known, and the tool that failed most.
  • Prompts, runs and requests. Tracking data doesn't show where one task ends and the next begins, so tips count prompts in Claude Code and agent runs in other frameworks, and say which they used. If neither is sent, they count AI requests instead, and the first report waits for 100 of them.
  • Week-to-week tips. Comparisons with the week before start once there are about two weeks of data. Data that arrives more than 3 days late is counted on the day it arrived and left out of these comparisons, so it never shows up as a sudden jump.

To make sense of each tip, read Reading your insights.

Other frameworks: LangChain, LangGraph, CrewAI and the OpenAI Agents SDK

These send their tracking data through the OpenTelemetry Collector, a small program that runs on the same computer as your agent. Your agent sends to the Collector, and the Collector keeps only the numbers Nosphera reads and forwards them. Prompts, messages and identity fields never leave your computer, and the tracking code stays with the Collector, not with your agent.

Download otelcol-contrib v0.162.0 for your system from the official releases and check it against its .sha256 file. Then save this as nosphera-collector.yaml. It holds no secrets.

receivers:
  otlp:
    protocols:
      http:
        endpoint: 127.0.0.1:4318   # this machine only

processors:
  # 1. Drop whole events that only carry content (prompts, messages, raw API
  #    bodies) and every span event (exception messages and stack traces).
  #    The Collector can't strip span links or metric exemplars on their own,
  #    so a span with links or a data point with exemplars is dropped whole.
  #    Turn both off in the agent so nothing is lost:
  #    OTEL_SPAN_LINK_COUNT_LIMIT=0 and OTEL_METRICS_EXEMPLAR_FILTER=always_off.
  filter/content:
    error_mode: propagate
    traces:
      span:
        - 'Len(span.links) > 0'
      spanevent:
        - 'true'
    metrics:
      datapoint:
        - 'Len(datapoint.exemplars) > 0'
    logs:
      log_record:
        - 'IsMatch(log.event_name, "^(claude_code\\.)?(api_request_body|api_response_body|system_prompt)$")'
        - 'IsMatch(log.attributes["event.name"], "^(claude_code\\.)?(api_request_body|api_response_body|system_prompt)$")'
        - 'IsMatch(log.body, "^claude_code\\.(api_request_body|api_response_body|system_prompt)$")'
        - 'IsMatch(log.event_name, "^gen_ai\\.((system|user|assistant|tool)\\.message|choice|client\\.inference\\.operation\\.details)$")'
        - 'IsMatch(log.attributes["event.name"], "^gen_ai\\.((system|user|assistant|tool)\\.message|choice|client\\.inference\\.operation\\.details)$")'

  # 2. Turn running totals into per-interval amounts. Runs before step 3 so
  #    each series is still told apart by its original attributes.
  cumulative_to_delta: {}

  # 3. Keep only the attribute keys Nosphera reads; clear names, messages and
  #    bodies that can carry text. Any error drops the batch instead of
  #    sending it unfiltered.
  transform/allowlist:
    error_mode: propagate
    trace_statements:
      - context: resource
        statements:
          - 'keep_keys(resource.attributes, [])'
      - context: scope
        statements:
          - 'keep_keys(scope.attributes, [])'
      - context: span
        statements:
          - >-
            keep_keys(span.attributes, ["event.name", "gen_ai.operation.name",
            "openinference.span.kind", "success", "error.type", "decision_type", "duration_ms", "type",
            "gen_ai.token.type", "model", "gen_ai.response.model", "gen_ai.request.model",
            "llm.model_name", "llm.response.model_name", "llm.request.model_name",
            "tool_name", "gen_ai.tool.name", "tool.name", "input_tokens",
            "gen_ai.usage.input_tokens", "gen_ai.usage.prompt_tokens", "llm.token_count.prompt",
            "output_tokens", "gen_ai.usage.output_tokens", "gen_ai.usage.completion_tokens",
            "llm.token_count.completion", "cache_read_tokens",
            "gen_ai.usage.cache_read.input_tokens", "gen_ai.usage.cache_read_input_tokens",
            "llm.token_count.prompt_details.cache_read", "cache_creation_tokens",
            "gen_ai.usage.cache_creation.input_tokens", "gen_ai.usage.cache_write.input_tokens",
            "gen_ai.usage.cache_creation_input_tokens",
            "llm.token_count.prompt_details.cache_write", "cost_usd_micros", "cost_usd",
            "llm.cost.total"])
          - 'set(span.name, "span") where not IsMatch(span.name, "^claude_code\\.[a-z_.]{1,64}$")'
          - 'set(span.status.message, "")'
          - 'set(span.trace_state, "")'
      - context: spanevent
        statements:
          - 'keep_keys(spanevent.attributes, [])'
    metric_statements:
      - context: resource
        statements:
          - 'keep_keys(resource.attributes, [])'
      - context: scope
        statements:
          - 'keep_keys(scope.attributes, [])'
      - context: datapoint
        statements:
          - >-
            keep_keys(datapoint.attributes, ["event.name", "gen_ai.operation.name",
            "openinference.span.kind", "success", "error.type", "decision_type", "duration_ms", "type",
            "gen_ai.token.type", "model", "gen_ai.response.model", "gen_ai.request.model",
            "llm.model_name", "llm.response.model_name", "llm.request.model_name",
            "tool_name", "gen_ai.tool.name", "tool.name", "input_tokens",
            "gen_ai.usage.input_tokens", "gen_ai.usage.prompt_tokens", "llm.token_count.prompt",
            "output_tokens", "gen_ai.usage.output_tokens", "gen_ai.usage.completion_tokens",
            "llm.token_count.completion", "cache_read_tokens",
            "gen_ai.usage.cache_read.input_tokens", "gen_ai.usage.cache_read_input_tokens",
            "llm.token_count.prompt_details.cache_read", "cache_creation_tokens",
            "gen_ai.usage.cache_creation.input_tokens", "gen_ai.usage.cache_write.input_tokens",
            "gen_ai.usage.cache_creation_input_tokens",
            "llm.token_count.prompt_details.cache_write", "cost_usd_micros", "cost_usd",
            "llm.cost.total"])
    log_statements:
      - context: resource
        statements:
          - 'keep_keys(resource.attributes, [])'
      - context: scope
        statements:
          - 'keep_keys(scope.attributes, [])'
      - context: log
        statements:
          - >-
            keep_keys(log.attributes, ["event.name", "gen_ai.operation.name",
            "openinference.span.kind", "success", "error.type", "decision_type", "duration_ms", "type",
            "gen_ai.token.type", "model", "gen_ai.response.model", "gen_ai.request.model",
            "llm.model_name", "llm.response.model_name", "llm.request.model_name",
            "tool_name", "gen_ai.tool.name", "tool.name", "input_tokens",
            "gen_ai.usage.input_tokens", "gen_ai.usage.prompt_tokens", "llm.token_count.prompt",
            "output_tokens", "gen_ai.usage.output_tokens", "gen_ai.usage.completion_tokens",
            "llm.token_count.completion", "cache_read_tokens",
            "gen_ai.usage.cache_read.input_tokens", "gen_ai.usage.cache_read_input_tokens",
            "llm.token_count.prompt_details.cache_read", "cache_creation_tokens",
            "gen_ai.usage.cache_creation.input_tokens", "gen_ai.usage.cache_write.input_tokens",
            "gen_ai.usage.cache_creation_input_tokens",
            "llm.token_count.prompt_details.cache_write", "cost_usd_micros", "cost_usd",
            "llm.cost.total"])
          - 'set(log.body, "") where not IsMatch(log.body, "^claude_code\\.[a-z_]{1,64}$")'

  # 4. At most 500 items per request (Nosphera takes up to 1,000).
  batch:
    send_batch_size: 500
    send_batch_max_size: 500
    timeout: 5s

exporters:
  otlp_http:   # older Collector versions call this exporter otlphttp
    endpoint: https://mcp.nosphera.com/otlp
    encoding: json
    compression: gzip
    headers:
      Authorization: "Bearer ${env:NOSPHERA_TOKEN}"

service:
  telemetry:
    metrics:
      level: none   # no extra port for the Collector's own metrics
  pipelines:
    traces:
      receivers: [otlp]
      processors: [filter/content, transform/allowlist, batch]
      exporters: [otlp_http]
    metrics:
      receivers: [otlp]
      processors: [filter/content, cumulative_to_delta, transform/allowlist, batch]
      exporters: [otlp_http]
    logs:
      receivers: [otlp]
      processors: [filter/content, transform/allowlist, batch]
      exporters: [otlp_http]

Start the Collector with the code from step 1 in its own environment. On macOS and Linux:

export NOSPHERA_TOKEN="$(cat ~/.config/nosphera/token)"
./otelcol-contrib --config=nosphera-collector.yaml

On Windows, in PowerShell:

$env:NOSPHERA_TOKEN = (Get-Content -Raw "$env:USERPROFILE\.nosphera\token").Trim()
.\otelcol-contrib.exe --config=nosphera-collector.yaml

Then point your agent at the Collector. Don't give your agent the code. These settings also keep prompts and answers out of the tracking data at the source:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_SPAN_LINK_COUNT_LIMIT=0
export OTEL_METRICS_EXEMPLAR_FILTER=always_off
export OPENINFERENCE_HIDE_INPUTS=true
export OPENINFERENCE_HIDE_OUTPUTS=true

Add OpenInference instrumentation, which records the model, token and tool numbers. For LangChain and LangGraph:

pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http openinference-instrumentation-langchain
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from openinference.instrumentation.langchain import LangChainInstrumentor

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(provider)
LangChainInstrumentor().instrument(tracer_provider=provider)
  • CrewAI: install openinference-instrumentation-crewai and openinference-instrumentation-litellm, and use CrewAIInstrumentor and LiteLLMInstrumentor the same way.
  • OpenAI Agents SDK: install openinference-instrumentation-openai-agents, use OpenAIAgentsInstrumentor the same way, and set OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA=false.

Get started

Create an account, connect your agent, then get a tracking code from My agents. To see what the reputation tips are based on, read how to earn verified proof and how the trust score works.

Stuck? See support or email info@nosphera.com.