maple-agent-tracing-ag…
Trace Agno agents with Maple: installs the OpenInference Agno instrumentor with an OTLP…
General OpenTelemetry onboarding style for Maple: native APIs, the business-span pattern, signal quality, inline keys, VCS resource attributes, LLM calls, and smoke checks.
$ npx -y skills add mapletechlabs/maple --skill maple-onboarding-style --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maple-onboarding-styleContext preview
The summary Claude sees to decide when to auto-load this skill.
General OpenTelemetry onboarding style for Maple: native APIs, the business-span pattern, signal quality, inline keys, VCS resource attributes, LLM calls, and smoke checks.
name: maple-onboarding-style description: "General OpenTelemetry onboarding style for Maple: native APIs, the business-span pattern, signal quality, inline keys, VCS resource attributes, LLM calls, and smoke checks."
Use native OpenTelemetry APIs. Do not invent helper APIs.
Use `tracer.startActiveSpan` with `try` / `catch` / `finally`: record the exception and set `Error` status before rethrowing, and end the span in `finally`. The callback form keeps the span active for everything inside it, in browsers too, and keeps the function sync or async as it was. Don't hide this behind a local helper (`withSpan`, `traced`, …). Don't add spans around provider SDK calls that OpenInference / provider instrumentation already observes.
Do:
import { metrics, SpanStatusCode, trace } from "@opentelemetry/api"
const tracer = trace.getTracer("orders.api")
const meter = metrics.getMeter("orders.api")
const ordersSubmitted = meter.createCounter("orders.submitted")
export async function submitOrder(tenantId: string, orderId: string) {
return tracer.startActiveSpan("order.submit", async (span) => {
try {
span.setAttributes({ "tenant.id": tenantId, "order.id": orderId })
const receipt = await chargeOrder(orderId)
ordersSubmitted.add(1, { "tenant.id": tenantId, outcome: "success" })
return receipt
} catch (err) {
span.recordException(err as Error)
span.setStatus({ code: SpanStatusCode.ERROR, message: (err as Error).message })
ordersSubmitted.add(1, { "tenant.id": tenantId, outcome: "failure" })
throw err
} finally {
span.end()
}
})
}Do not:
await sendMapleSpan(...) recordCounter(...) withTelemetry(...)
Inline the endpoint and the ingest key directly in the bootstrap source and pass them explicitly to the exporter: its own URL option (`url` in JavaScript, `endpoint` in Python; each language skill shows the exact shape) plus `headers`. Don't read `OTEL_EXPORTER_OTLP_*` env vars and don't write `.env` files. `maple-onboard` Step 0 decides the region and which key goes where.
MAPLE_ENDPOINT = "https://ingest.maple.dev" # EU organizations: https://ingest.eu.maple.dev MAPLE_KEY = "maple_pk_…" # public ingest key, or "MAPLE_TEST" until the user has one
`MAPLE_TEST` is accepted by both regions and dropped, so the bootstrap exercises the full code path before the real key arrives.
If the repo can call telemetry init from multiple paths, guard provider/exporter setup so repeated imports, tests, reloads, or framework callbacks do not install duplicate processors or log handlers. For a single-entrypoint app that starts cleanly, keep this simple.
Set these resource attributes on every service: `service.name` (the app's own name, e.g. its package name without the scope), `service.version` (the package.json version, a release tag, or the commit SHA), `deployment.environment.name`, and the VCS attributes below.
Set `vcs.repository.url.full` on the OTel resource for every instrumented server-side service. The value is the canonical https URL of the repo (e.g. `https://github.com/acme/api`): the URL the user would paste in a browser, not an SSH URL or a local working-tree path. This is the important one; it lets Maple link telemetry back to the source. It is fine to hardcode this string alongside `service.name` in the SDK init; if a build env already exposes the slug (e.g. `VERCEL_GIT_REPO_OWNER` + `VERCEL_GIT_REPO_SLUG`, `RAILWAY_GIT_REPO_OWNER` + `RAILWAY_GIT_REPO_NAME`), prefer reading from env so a fork or rename doesn't drift. `@maple-dev/browser` has no option for it; that is fine.
Also set `vcs.ref.head.revision` (the commit SHA) on a best-effort basis. Read it from whatever env var the runtime/build platform already injects: `VERCEL_GIT_COMMIT_SHA`, `RAILWAY_GIT_COMMIT_SHA`, `GITHUB_SHA`, `SOURCE_COMMIT`, `GIT_COMMIT`, `HEROKU_SLUG_COMMIT`, etc. Do not shell out to `git` from the running process. Many production images have no git binary or working tree. If no env source is available, omit the attribute; skipping the SHA is fine, skipping the URL is not. (`@maple-dev/browser` sets it from `serviceVersion` when that is a commit SHA.)
Use `vcs.repository.url.full` and `vcs.ref.head.revision` exactly as named. These are the OTel semantic-convention keys. Do not invent parallel attributes like `git.repo`, `app.repo_url`, or `deployment.commit_sha`.
If the app uses LLMs, first look for provider instrumentation that already captures model/provider/token/error spans. In JavaScript/TypeScript, prefer OpenInference packages such as `@arizeai/openinference-instrumentation-anthropic` or `@arizeai/openinference-instrumentation-openai` for supported SDKs. Keep the real provider call native and readable.
In Node, `getNodeAutoInstrumentations()` already includes `@opentelemetry/instrumentation-openai` (OTel `gen_ai.*` spans for the `openai` SDK). Use it for OpenAI and don't add OpenInference's OpenAI package as
Repo: mapletechlabs/maple
Trace Agno agents with Maple: installs the OpenInference Agno instrumentor with an OTLP…
Trace Claude Agent SDK agents (TypeScript and Python) and Claude Code CLI sessions with…
Trace Cloudflare Agents SDK agents (AIChatAgent, Agent on Durable Objects, npm `agents` /…
Trace CrewAI crews and flows with Maple: OpenInference CrewAI instrumentor plus the model-SDK…
Trace DSPy programs and ReAct agents with Maple: OpenInference DSPy instrumentor with GenAI…
Trace Genkit (TypeScript/Node.js) agents with Maple: export Genkit's OpenTelemetry spans to…