--- name: opik-instrument description: Add Opik tracing to an existing app and verify a real trace lands. Installs the Opik package, detects the language and LLM framework, adds the minimum tracing, runs a safe representative path, confirms a trace in Opik, and returns the trace link. Use for "instrument my code", "add opik tracing", "add observability", "trace my agent". Not for building a new app from scratch, or a review-only pass with no code changes. compatibility: Tested with Claude Code; works with any Agent Skills-compatible host (Cursor, VS Code Copilot, Codex). Requires a Python or TypeScript project. Install the `opik` skill alongside this one — it holds the shared SDK and integration references; without it, this skill falls back to the public docs. allowed-tools: - Read - Edit - Write - Grep - Glob - Bash metadata: last_updated: "2026-09-10" source_commit: "2.0.0" argument-hint: "[optional: file or directory path]" --- # Instrument — Add Opik Tracing and Verify a Real Trace **Definition of done:** a representative, safely-executed path produces a trace that is confirmed in Opik and a direct trace link is returned. If verification can't be completed safely or autonomously, stop at the **first** genuine blocker and return **exactly one** concrete next step. Code edits alone are not success. Operate: **opinionated in execution, conservative in code changes, automatic in routine decisions, uncompromising about verifying value — but never by running something unsafe.** ## Inputs The entry point is just `/opik-instrument` (optionally `/opik-instrument `). Infer everything else; treat these only as **optional overrides** the user may pass, never as required setup: - target path (default: project root) · project name (default: inferred from the repo) · run command (default: an inferred safe path) · `migrate_prompts` (default: **false**). Never turn inference into a questionnaire. Ask only when you hit a genuine, non-inferable blocker (see **Blockers**). ## Activation — the only in-scope work ### 1. Configure Opik (one source of truth) - If `~/.opik.config` exists or `OPIK_API_KEY` is set, use it as-is. - Otherwise run the official flow: `opik configure` (Python) / `npx opik-ts configure` (TypeScript). - **Verify the config before instrumenting:** run `opik healthcheck` — it validates the config, the install, and backend/workspace reachability. If it fails, stop at that Blocker and fix config or connectivity before adding any tracing. - Only add project-local `.env` vars if the project **already** uses that pattern. Never introduce a second config mechanism; never copy secret values between mechanisms. ### 2. Detect language & framework Python (`*.py`, `pyproject.toml`) or TypeScript (`*.ts`, `package.json`). Identify the LLM framework from imports and pick its integration: | Import | Integration | |---|---| | `openai` / `anthropic` | `track_openai` / `track_anthropic` | | `langchain` / `langgraph` | `OpikTracer` callback | | `crewai` / `dspy` / google-genai / bedrock / `llama_index` / `litellm` | `track_crewai` / `OpikCallback` / `track_genai` / `track_bedrock` / `LlamaIndexCallbackHandler` / `OpikLogger` | | TS: `opik-openai` / `opik-vercel` / `opik-langchain` | `trackOpenAI` / `OpikExporter` / `OpikCallbackHandler` | Full list: read `../opik/references/integrations.md` (the `opik` skill, installed beside this one). If that file isn't there, read — never settle for manual spans on a framework that has a native integration just because the reference was unreachable. If the project is **already instrumented**, audit and add only what's missing — do not re-instrument. ### 3. Add the minimum tracing Decision policy, in order: 1. Prefer the **framework-native integration** for provider LLM spans. 2. Add manual `@opik.track` spans only for orchestration/tools the integration doesn't cover (`type="tool"` / `"llm"` / `"guardrail"`). A bare `@opik.track` produces the default span type, **`general`** — the right choice for an entrypoint/orchestrator. 3. Never instrument the same operation twice (no `@opik.track(type="llm")` on top of `track_openai`). 4. Mark **one entrypoint per independently-runnable agent/service** — not necessarily one per repo. 5. Decorator order relative to framework decorators (e.g. `@app.route`) is **framework-dependent** — verify per framework; do not assume a universal order. 6. Scripts: flush at the end (`opik.flush_tracker()` / `await client.flush()`). LiteLLM inside `@opik.track`: pass `metadata={"opik": {"current_span_data": get_current_span_data()}}` or traces orphan. Make the **smallest change** that lets one representative path emit a trace. ### 4. Install the Opik package (by default) Add **only** the required Opik package(s) via the repo's detected package manager (pip / uv / poetry / npm / pnpm / yarn), through normal project conventions. **Preserve the lockfile**; do not run generic upgrades; do not install globally; treat unusual lifecycle scripts cautiously. Surface it as a change (e.g. "added `opik` to `pyproject.toml`"). If the environment blocks installation → **Blocker** with the one exact command. ### 5. Run a safe representative path Infer a safe command — prefer an existing **test, example, or dev script**, then a bounded single-request entrypoint. **Never** run anything that looks like production or does irreversible/expensive work (writes, emails, purchases, mass API calls). If no safe path is inferable → **Blocker** ("which dev command safely exercises this agent?"). Print the command, then run it. If the run needs an **LLM provider credential** (e.g. `OPENAI_API_KEY`) and it's absent, that's a Blocker — the app can't produce a trace. Note some SDK clients raise at **construction** (module load), before any span runs, so there is **no partial trace** to wait on: return blocked with the one next step, don't wait on a flush that never happened. ### 6. Verify ingestion Confirm a trace actually arrived — don't assume. **Prefer the SDK for verification**: it's already installed as part of instrumenting (zero extra moving parts), whereas the Opik MCP is optional and may not be connected. The SDK read of one trace and its spans: `references/verify-ingestion.md` (**SDK check**). To find the newest trace instead of using a known id, use the client's trace search (e.g. `search_traces`) scoped to the project. Optionally, if the Opik MCP is connected, `list` recent traces then `read` the newest. Traces are asynchronous — allow a few seconds after the run and make sure the flush ran. **Verify coverage, not just arrival.** A trace arriving is necessary but not sufficient — batching can silently drop or truncate spans, so a trace can land *incomplete* and still look fine. Before reporting `verified`: - **Count vs. expected.** Compare `len(spans)` (the `search_spans` call in `references/verify-ingestion.md`, `project_name` included) against the call sites you instrumented on the path you ran (entrypoint + each traced tool/LLM). Fewer spans than expected means spans were dropped — do not report `verified`. - **Every span is well-formed.** Each span has a non-empty `name` and `type`; LLM spans carry input/output (and usage where the integration provides it). A span returned with an empty `name`/`type` is the batching-race symptom in `references/verify-ingestion.md`, not a real span. **With the Opik MCP connected, verify there instead.** `read(entity_type="trace", id=tid)` returns `{trace, spans, spansTruncated}` with the span tree inlined (up to 200 spans), so both checks above run over that one call, no script needed: count the spans against the instrumented call sites, and confirm each has a `name`/`type` and the LLM spans carry input/output. If `spansTruncated` is true, count with the SDK instead. The SDK stays the default because it is already installed; the MCP is the shortcut when it is there. If the trace is empty, partial, or has unnamed spans, check `references/verify-ingestion.md` (**Common ingestion traps**) before changing the instrumentation. ### 7. Report Return a short human result + the trace link (see **Output**), then make the single expansion offer. ## Blockers When you genuinely can't proceed, stop at the **earliest** blocker and return **exactly one** next step — never a checklist — and still report the changes already made (`blocked` carries `changes`). An unsupported language or shape is `unsupported` and modifies nothing. Examples: - "Run `opik configure`, then rerun `/opik-instrument`." - "Install dependencies with `uv sync`, then rerun `/opik-instrument`." - "Which dev command safely exercises this agent?" - "Instrumented and installed, but the run needs a provider credential — set `OPENAI_API_KEY` (or the relevant provider key) and rerun." - "Instrumented and ran, but this environment can't query Opik — open the project and confirm trace `` arrived." ## Expansion — after the trace lands (one offer, not a funnel) Do **not** migrate prompts, add threading, or broaden spans during activation. After verification, make a **single consolidated offer** of what you found, e.g.: > Tracing is verified. I also found ways to deepen it: 3 Prompt Library candidates, missing conversation threading, and 2 untraced tools. Expand? ## Output **User-facing:** a short human message — what was instrumented, the trace link, and the one expansion offer (or, if blocked, the single next step plus what changed). Not raw JSON. **Underneath** (for composition / evals), a small state model, with its invariants: `references/output-shape.md`. ## Examples Worked runs (no LLM framework, OpenAI, already instrumented): `references/examples.md`. ## Anti-patterns Double-wrapping (integration + manual span on the same call); orphaned LiteLLM traces (missing `current_span_data`); missing flush in scripts; overwriting or duplicating config; **running an unsafe/production path just to force a trace**; broad dependency upgrades when only `opik` is needed; migrating prompts during activation. ## References SDK detail lives in the `opik` skill, installed beside this one. Read the files directly — paths are relative to this file: `../opik/references/tracing-python.md`, `../opik/references/tracing-typescript.md`, `../opik/references/integrations.md`, `../opik/references/observability.md`. If your host lays skills out differently, locate the `opik` skill's `references/` directory. If the `opik` skill isn't installed, say so in the report and use rather than working from memory.