npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@skein-js/otel

v0.13.1

Published

OpenTelemetry spans and metrics for skein-js runs — works with any OTLP backend.

Readme

@skein-js/otel

npm downloads license

OpenTelemetry spans and metrics for skein-js runs — works with any OTLP backend.

Part of skein-js — the open-source alternative to LangGraph Platform for TypeScript: a self-hosted Agent Protocol server for LangGraph.js, and a drop-in replacement for the LangGraph CLI.

What's here

One skein.run span per run, plus a run counter and a duration histogram.

This package depends on the OpenTelemetry API only — never the SDK, never an exporter. That is the whole reason one small package covers Datadog, Grafana, Honeycomb, Jaeger, New Relic, Sentry and anything else that speaks OTLP: your app owns the SDK, the resource, and where data goes, exactly as it already does for the rest of your service. skein just contributes spans and metrics to it.

If no SDK is registered, the API's no-op implementation takes over and this costs almost nothing.

Install

pnpm add @skein-js/otel @opentelemetry/api

You also need an OTel SDK in your app (@opentelemetry/sdk-node or a vendor distribution) — that's what actually exports the data.

Usage

import { createOtelTelemetry } from "@skein-js/otel";
import { embedInMemoryGraphs } from "@skein-js/server-kit";
import { createExpressServer } from "@skein-js/express";

const server = await createExpressServer({
  deps: embedInMemoryGraphs({ agent }, { overrides: { telemetry: createOtelTelemetry() } }),
});

Unlike the LangSmith and PostHog sinks this never returns undefined: there is nothing to configure. Whether anything is recorded is decided by whether your host registered an SDK.

Using the CLI? Declare it in langgraph.json instead:

{ "telemetry": { "otel": true } }

See docs/observability.md.

What it emits

Span skein.run <graph_id>, from the moment a run starts executing to the moment it settles:

| Attribute | | | ------------------------------------------------------------------------ | -------------------------------------------- | | skein.run.id · skein.thread.id · skein.assistant.id | identity | | skein.graph.id · skein.run.trigger · skein.run.status | what ran, how it started, how it ended | | skein.run.queue_ms · skein.run.frames | queue wait (background runs), frames emitted | | skein.run.failing_nodes | the node(s) that threw, when identifiable | | gen_ai.operation.name · gen_ai.agent.name · gen_ai.conversation.id | GenAI semconv equivalents |

A failed run records the exception (stack and cause chain intact) and sets an ERROR status.

Metricsskein.runs (counter) and skein.run.duration (histogram, ms), both dimensioned by graph, trigger, and status. Deliberately low-cardinality: no run, thread, or user id, so these stay cheap in Prometheus and friends.

Spans inside the graph

skein reports the run. For LLM- and tool-level spans, add a LangChain instrumentation — @traceloop/node-server-sdk or @arizeai/openinference-instrumentation-langchain.

Those spans are correlated with the run span, not nested under it. Nesting would need the run span to be active in the OTel context for the whole of the graph's execution, and the sink seam is a pair of one-shot notifications with no way to hold a context open between them. Join on skein.run.id or gen_ai.conversation.id and you get the same grouping in a query — but you won't see generations indented under the run in a trace waterfall.

API

  • createOtelTelemetry(options?): TelemetrySink — always returns a sink.
    • scopeName / scopeVersion — instrumentation scope; defaults to "@skein-js/otel"
    • metrics — emit the counter and histogram (default true)
    • api — a pre-resolved { tracer, meter }, to pick a specific provider or capture spans in tests

Learn more

License

Apache-2.0