/opik
Reference for the Opik SDK — tracing, span types, framework integrations, threads, and the prompt library (Python, TypeScript, REST). Use for "what span types exist", "how do I flush", "track_openai", "add OpikTracer", "version a prompt". To instrument a repo end to end, use the
Claude Code
$ npx -y skills add comet-ml/opik-mcp --skill opik --agent claude-code
Codex
$ npx skills add comet-ml/opik-mcp --skill opik -a codex -y
Cursor
$ npx skills add comet-ml/opik-mcp --skill opik -a cursor -y
Gemini CLI
$ npx skills add comet-ml/opik-mcp --skill opik -a gemini-cli -y
GitHub Copilot
$ npx skills add comet-ml/opik-mcp --skill opik -a github-copilot -y
OpenCode
$ npx skills add comet-ml/opik-mcp --skill opik -a opencode -y
Windsurf
$ npx skills add comet-ml/opik-mcp --skill opik -a windsurf -y
SKILL.md
opik.SKILL.mdname: opik
description: Reference for the Opik SDK — tracing, span types, framework integrations, threads, and the prompt library (Python, TypeScript, REST). Use for "what span types exist", "how do I flush", "track_openai", "add OpikTracer", "version a prompt". To instrument a repo end to end, use the `opik-instrument` skill.
compatibility: Tested with Claude Code; works with any Agent Skills-compatible host (Cursor, VS Code Copilot, Codex). A reference — needs no Opik connection to read; the snippets assume the `opik` Python or TypeScript SDK 2.x. The task-shaped skills (opik-instrument, opik-diagnose, opik-explain, opik-test, opik-compare, opik-evaluate, opik-online-eval, opik-optimize, opik-verify) read this skill's references and expect it installed beside them.
allowed-tools:
- Read
- Grep
- Glob
metadata:
last_updated: "2026-10-23"
source_commit: "2.0.0"
Opik SDK Reference
Opik is an open-source LLM observability platform. This skill is a **reference** for the SDK. To instrument a codebase step by step (detect frameworks, add config, emit and verify a trace), use the task-shaped `opik-instrument` skill.
Core concepts
A trace is one execution path (one request → one response). Spans are the operations inside it and form a hierarchy.
Span types — the ONLY valid values
| Type | Use for | |------|---------| | `general` | orchestration, agent entry points | | `llm` | model calls | | `tool` | tools, retrieval, API / DB calls | | `guardrail` | safety / validation checks |
Do NOT use `retrieval` or any other value.
Python — tracing
import opik
@opik.track(name="agent", type="general")
def agent(query: str) -> str:
return generate(retrieve(query))
@opik.track(type="tool")
def retrieve(query): ...
@opik.track(type="llm")
def generate(ctx): ...
opik.flush_tracker() # required in scriptsTypeScript — tracing
import { Opik } from "opik";
const client = new Opik({ projectName: "my-project" });
const trace = client.trace({ name: "agent", input: { query } });
const span = trace.span({ name: "llm-call", type: "llm" });
span.end({ output });
trace.end({ output });
await client.flush();Framework integrations
Prefer an integration over manual `@opik.track` — integrations capture tokens, model, and cost automatically. Patterns (full list in `references/integrations.md`):
- **wrap-the-client** — `track_openai(OpenAI())`, `track_anthropic(...)`
- **global-enable** — `track_crewai(crew=crew)`
- **callback** — `dspy.configure(callbacks=[OpikCallback()])`
- **tracer** — `OpikTracer()` for LangChain / LangGraph / LlamaIndex
- **agent-specific** — `track_adk_agent_recursive(agent, OpikTracer())`
LiteLLM inside `@opik.track` (common trap)
If code uses `litellm` **and** you add `@opik.track`, pass `current_span_data` via metadata on every completion call — otherwise `OpikLogger` emits **orphaned** top-level traces instead of nesting under your span.
from opik.opik_context import get_current_span_data
@opik.track
def call_llm(messages):
return litellm.completion(
model="gpt-4o",
messages=messages,
metadata={"opik": {"current_span_data": get_current_span_data()}},
)Threads (conversations)
Group turns with `thread_id` — one turn = one trace, shared `thread_id` = one thread. Use for chat / multi-turn; skip for single-shot.
@opik.track(entrypoint=True)
def handle(session_id: str, message: str) -> str:
opik.update_current_trace(thread_id=session_id)
return reply(message)To tag a thread with an environment (`production`, `staging`, ...), set `environment` on its traces: `@opik.track(environment="production")`, `client.trace(..., environment=...)`, or `OPIK_ENVIRONMENT` as the default. The thread takes the environment of its **first** trace and keeps it, so use the same environment for every turn. Use this field, not tags or metadata.
Prompt library
Version prompts with `client.get_prompt` / `create_prompt` (chat variants: `get_chat_prompt` / `create_chat_prompt`). Store model + temperature in the prompt `metadata` so they version with the text. Call `get_prompt` **inside** a `@opik.track` function so the version links to the trace.
@opik.track(entrypoint=True)
def run(question: str) -> str:
p = client.get_prompt(name="system") or client.create_prompt(
name="system",
prompt="You help with {{product}}.",
metadata={"model": "gpt-4o", "temperature": 0.7},
)
return llm(p.format(product="Opik"), model=p.metadata["model"])How a project is doing
With the MCP connected, start at the project, not at its traces:
read("project", "<project name or id>")One call returns the last 7 days against the 7 before — trace count, error rate, average duration, total cost, SDK traffic only, which is what the Logs page's four cards show — plus the score names and usage keys the project actually records, and the freshest experiment, dataset, prompt version and optimization run in it. `since`/`until` pick another window; `since="30d"` is what the UI opens on. A rate or an average over a window with no traces comes back `null` rather than `0`, because a rate over no samples is undefined and "0% errors" is advice someone may act on.
Then attribute the change rather than restating it:
list("project_metric", project_name="<project>", metric_type="trace_cost")
list("project_metric", project_name="<project>", metric_type="span_count",
breakdown="model", since="30d")Rows are time buckets, not records — `interval` is `hourly`/`daily`/`weekly`/ `total`, and `page`/`size`/`sort` do not apply. `schema("list.project_metric")` is the metric list, what each is about, and which groupings each accepts; seven of them accept none. The score names the overview returned are the ones worth filtering on, and `list("score_name", project_name=…)` has the rest.
Searching traces
One filter grammar
Read more
name: opik description: Reference for the Opik SDK — tracing, span types, framework integrations, threads, and the prompt library (Python, TypeScript, REST). Use for "what span types exist", "how do I flush", "track_openai", "add OpikTracer", "version a prompt". To instrument a repo end to end, use the `opik-instrument` skill. compatibility: Tested with Claude Code; works with any Agent Skills-compatible host (Cursor, VS Code Copilot, Codex). A reference — needs no Opik connection to read; the snippets assume the `opik` Python or TypeScript SDK 2.x. The task-shaped skills (opik-instrument, opik-diagnose, opik-explain, opik-test, opik-compare, opik-evaluate, opik-online-eval, opik-optimize, opik-verify) read this skill's references and expect it installed beside them. allowed-tools: - Read - Grep - Glob metadata: last_updated: "2026-10-23" source_commit: "2.0.0"
Opik SDK Reference
Opik is an open-source LLM observability platform. This skill is a **reference** for the SDK. To instrument a codebase step by step (detect frameworks, add config, emit and verify a trace), use the task-shaped `opik-instrument` skill.
Core concepts
A trace is one execution path (one request → one response). Spans are the operations inside it and form a hierarchy.
Span types — the ONLY valid values
| Type | Use for | |------|---------| | `general` | orchestration, agent entry points | | `llm` | model calls | | `tool` | tools, retrieval, API / DB calls | | `guardrail` | safety / validation checks |
Do NOT use `retrieval` or any other value.
Python — tracing
import opik
@opik.track(name="agent", type="general")
def agent(query: str) -> str:
return generate(retrieve(query))
@opik.track(type="tool")
def retrieve(query): ...
@opik.track(type="llm")
def generate(ctx): ...
opik.flush_tracker() # required in scriptsTypeScript — tracing
import { Opik } from "opik";
const client = new Opik({ projectName: "my-project" });
const trace = client.trace({ name: "agent", input: { query } });
const span = trace.span({ name: "llm-call", type: "llm" });
span.end({ output });
trace.end({ output });
await client.flush();Framework integrations
Prefer an integration over manual `@opik.track` — integrations capture tokens, model, and cost automatically. Patterns (full list in `references/integrations.md`):
- **wrap-the-client** — `track_openai(OpenAI())`, `track_anthropic(...)`
- **global-enable** — `track_crewai(crew=crew)`
- **callback** — `dspy.configure(callbacks=[OpikCallback()])`
- **tracer** — `OpikTracer()` for LangChain / LangGraph / LlamaIndex
- **agent-specific** — `track_adk_agent_recursive(agent, OpikTracer())`
LiteLLM inside `@opik.track` (common trap)
If code uses `litellm` **and** you add `@opik.track`, pass `current_span_data` via metadata on every completion call — otherwise `OpikLogger` emits **orphaned** top-level traces instead of nesting under your span.
from opik.opik_context import get_current_span_data
@opik.track
def call_llm(messages):
return litellm.completion(
model="gpt-4o",
messages=messages,
metadata={"opik": {"current_span_data": get_current_span_data()}},
)Threads (conversations)
Group turns with `thread_id` — one turn = one trace, shared `thread_id` = one thread. Use for chat / multi-turn; skip for single-shot.
@opik.track(entrypoint=True)
def handle(session_id: str, message: str) -> str:
opik.update_current_trace(thread_id=session_id)
return reply(message)To tag a thread with an environment (`production`, `staging`, ...), set `environment` on its traces: `@opik.track(environment="production")`, `client.trace(..., environment=...)`, or `OPIK_ENVIRONMENT` as the default. The thread takes the environment of its **first** trace and keeps it, so use the same environment for every turn. Use this field, not tags or metadata.
Prompt library
Version prompts with `client.get_prompt` / `create_prompt` (chat variants: `get_chat_prompt` / `create_chat_prompt`). Store model + temperature in the prompt `metadata` so they version with the text. Call `get_prompt` **inside** a `@opik.track` function so the version links to the trace.
@opik.track(entrypoint=True)
def run(question: str) -> str:
p = client.get_prompt(name="system") or client.create_prompt(
name="system",
prompt="You help with {{product}}.",
metadata={"model": "gpt-4o", "temperature": 0.7},
)
return llm(p.format(product="Opik"), model=p.metadata["model"])How a project is doing
With the MCP connected, start at the project, not at its traces:
read("project", "<project name or id>")One call returns the last 7 days against the 7 before — trace count, error rate, average duration, total cost, SDK traffic only, which is what the Logs page's four cards show — plus the score names and usage keys the project actually records, and the freshest experiment, dataset, prompt version and optimization run in it. `since`/`until` pick another window; `since="30d"` is what the UI opens on. A rate or an average over a window with no traces comes back `null` rather than `0`, because a rate over no samples is undefined and "0% errors" is advice someone may act on.
Then attribute the change rather than restating it:
list("project_metric", project_name="<project>", metric_type="trace_cost")
list("project_metric", project_name="<project>", metric_type="span_count",
breakdown="model", since="30d")Rows are time buckets, not records — `interval` is `hourly`/`daily`/`weekly`/ `total`, and `page`/`size`/`sort` do not apply. `schema("list.project_metric")` is the metric list, what each is about, and which groupings each accepts; seven of them accept none. The score names the overview returned are the ones worth filtering on, and `list("score_name", project_name=…)` has the rest.
Searching traces
One filter grammar
The official Model Context Protocol (MCP) server for Opik, the open-source LLM observability and evaluation platform, built by Comet.
Other skills on opik-mcp.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about opik.
- Which coding agents can use opik?
- opik installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

