--- name: otel-weaver description: OpenTelemetry Weaver registry authoring, codegen, and CI enforcement. Use when adopting Weaver, authoring or reviewing a registry (manifest, attributes, metrics, spans, events), writing Jinja2 templates against the resolved schema, migrating hand-maintained telemetry constants, or wiring `weaver registry check`/`generate`/`diff` into CI. --- # OpenTelemetry Weaver Use this skill when an organization wants to define its own semantic conventions on top of upstream OTel and generate language bindings from them. Usage: - pair with `otel-semantic-conventions` to decide which attributes already exist upstream and should not be redeclared in the local registry - use `otel-sdk-versions` only for SDK package selection; Weaver versions are tracked separately at If a companion skill is unavailable: - do not stop - do not rely on memory alone when the guidance can be checked from official sources - consult the Weaver repo, `schemas/semconv-syntax.v2.md`, and `docs/usage.md` / `docs/validate.md` - state which fallback you used and leave any unverified item unresolved ## Mental Model Three moving parts: 1. **Registry** — directory of YAML files. `manifest.yaml` is required; its `schema_url` (OTel schema URL format, `http[s]://host/path/`) both names the registry and carries its version in the final path segment. Dependency entries also require `schema_url` plus optional `registry_path`. The rest declare `attributes`, `metrics`, `spans`, `events`, `entities`. The version segment of `schema_url` is yours to manage; bump it on changes. (`semconv_version` and `schema_base_url` are deprecated in favor of `schema_url`; top-level `name` is not a v0.26.1 manifest field.) 2. **Templates** — directory of MiniJinja files (Jinja2-compatible, not full Jinja2 — auto-escaping is off by default since v0.22.0 and loop `break`/`continue` are supported) plus a `weaver.yaml` per target language describing which templates to run, with what filter, in what `application_mode`, and with what output filename. 3. **Policies** — Rego rules evaluated by the Regorus (OPA-compatible) engine, in four packages: `before_resolution` (raw parsed groups; unsupported and skipped with `--v2`), `after_resolution` (resolved registry), `comparison_after_resolution` (only when `--baseline-registry` is passed), and `live_check_advice` (per-sample during `live-check`). Built-in OTel policies are the floor; custom policies layer on org rules. These three replace a hand-rolled `const.go` (or equivalent): const blocks become the registry, the act of writing them becomes codegen, and tribal knowledge becomes policies. ## Non-Negotiable Rules - Install Weaver via one of the methods documented at (release binary, `otel/weaver:vX.Y.Z` Docker image, or the `setup-weaver` GitHub Action). Never `brew install weaver` — that resolves to an unrelated Scribd tool. - Reference upstream semconv attributes by `ref` rather than redeclaring them. Boundary domains (`http`, `db`, `messaging`, `rpc`, `network`, `gen-ai`, ...) belong in upstream OTel semconv, not in a local registry. Use the language SDK's semconv package for those at runtime. - Every attribute and signal definition needs `stability`; include it on enum members too, as required by the v2 syntax guide. Weaver v0.26.1 rejects missing definition stability but reports missing enum-member stability only as a non-fatal warning in normal mode. - In v2, an attribute reference may refine fields such as `brief`, `note`, `examples`, and `annotations`, but not `stability` or `deprecated`; those always come from the attribute definition. - Use a domain prefix (e.g. `ecommerce.`, `acme.`) for org-local attributes, metrics, and spans. - Run the language formatter (`gofmt -w`, `prettier`, `ruff format`, ...) on generated output. Jinja whitespace produces multiple blank lines; without formatting, the diff check in CI will fail spuriously. - Confirm the resolved schema shape before writing a template. For a `definition/2` registry, call the grouped jq helpers with `{"v2": true}`; the v2 template `ctx` preserves fields such as attribute `key`, metric `name`, span `type`/`kind` and structured `span.name.note`, plus entity `type`/`identity`/`description`. See `references/template-authoring.md` for how to dump the exact shape. ## Workflow 1. **Install or locate Weaver.** Follow the upstream install instructions at — pick a pinned release binary, the `otel/weaver:vX.Y.Z` Docker image, or the `setup-weaver` GitHub Action. Use Docker for CI and reproducible local runs. 2. **Author the registry.** Required: `manifest.yaml` plus one or more `definition/2` YAML files declaring attributes, attribute groups, metrics, spans, events, or entities. See `references/registry-authoring.md`. 3. **Author templates.** One target dir per language under `templates/registry//` with `weaver.yaml` plus `*.j2`. See `references/template-authoring.md`. 4. **Validate and generate.** `weaver registry check --v2 -r ./telemetry/registry/` for fast feedback. `weaver registry generate --v2 --registry ./telemetry/registry/ --templates ./telemetry/templates/ ` for codegen. Run the language formatter on the output. 5. **Wire into CI.** Three gates: `check` (schema), `generate` + `git diff --exit-code` (checked-in code is current), `diff` against the base branch (surfaces breaking changes). See `references/ci-integration.md`. The Weaver CLI has more subcommands than this workflow touches: `stats` and `json-schema` for quick registry sanity checks, `update-markdown` for keeping semconv snippets in docs current, `emit`/`live-check`/`infer` for working against live OTLP telemetry, `mcp` for exposing a registry to LLM tooling, and `serve` for an HTTP+UI mode. All are out of scope here (see below) but worth knowing exist before assuming `check`/`generate`/`diff` is the whole surface. ## Gotchas These cost time and are not obvious from the upstream docs: 1. `brew install weaver` installs the wrong tool. Use GitHub releases or Docker. 2. Generated output is not formatter-clean. Always run the language formatter after `weaver registry generate`. 3. Jq helper defaults target the legacy schema. For `definition/2`, pass `{"v2": true}` and use the preserved v2 fields: attribute `key`, metric `name`, span `type`/`kind` and `span.name.note`, plus entity `type`/`identity`/`description`. Always generate and inspect the filtered `ctx` before writing a template. 4. The `comment` Jinja filter takes a keyword argument: `attr.brief | comment(format="go")`. It already emits the `// ` prefix; do not add another. 5. Attributes, metrics, spans, events, and entities all have prebuilt grouped jq filters (`semconv_grouped_attributes`, `semconv_grouped_metrics`, `semconv_grouped_spans`, `semconv_grouped_events`, `semconv_grouped_entities`). For `definition/2`, use (for example) `semconv_grouped_spans({"v2": true})` as a folded YAML scalar; the bare helper defaults select the legacy schema. 6. `weaver registry check` emits "File format `definition/2` is not yet stable" (a warning) for custom v2 definition files in v0.26.1. This is normal; do not treat it as a failure. 7. `--future` is opt-in but still elevates the `definition/2` instability warning to an error for a custom v2 registry in v0.26.1. Leave it off until the format goes stable. 8. CLI argument ordering for `generate`: target directory name is positional **after** `--registry` and `--templates`; the output directory follows. `--templates` points at the **parent** that contains target dirs, not at the language-specific subdir. 9. Span name in registry vs. runtime: required schema fields are `type`, `kind` (`client`/`server`/`producer`/`consumer`/`internal`), `brief`, `stability`, and a structured `name: { note: "..." }`. For internal business spans, putting the dotted type identifier in `name.note` and rendering the resolved `span.name.note` string at runtime is clean. 10. **What does NOT belong in your local registry.** DB, HTTP, messaging, RPC, network, GenAI, and similar boundary spans/attributes follow upstream OTel semconv. Until upstream is pulled in as a manifest dependency, instrumentation for those should reference the language SDK's semconv package directly. This is the most common modeling mistake. 11. Counter and UpDownCounter names should not append `_total`; this is the current semconv v1.44.0 naming rule. 12. Duration instruments should use seconds (`s`) under the current semconv v1.44.0 unit guidance. ## References To Load On Demand - registry YAML field reference: `references/registry-authoring.md` - Jinja2 patterns, jq filters, resolved-shape cheat sheet: `references/template-authoring.md` - ready-to-lift GitHub Actions example: `references/ci-integration.md` - hand-maintained-constants → registry walkthrough: `references/migration-playbook.md` - semantic conventions skill: `otel-semantic-conventions` - manual instrumentation skill: `manual-instrumentation` ## Out Of Scope These are natural follow-ups but not part of this skill: - publishing the registry as a versioned artifact for downstream consumers - declaring upstream semantic-conventions as a manifest dependency - `weaver registry live-check`/`emit`/`infer` against live OTLP telemetry - `weaver registry mcp` / `weaver serve` - custom Rego policies beyond the built-ins - helper-function codegen (`MyMetricName(meter)` wrappers) ## Verification Contract If you authored or modified a Weaver registry, templates, or CI integration: - re-open the changed files before finishing - run `weaver registry check --v2` against the `definition/2` registry and capture the result - run `weaver registry generate --v2` and the language formatter, then verify `git diff --exit-code` is clean - confirm each applicable item with codebase evidence Report the final check with: - `[x]` completed - `[~]` not applicable, with a reason - `[ ]` unresolved Use these items: - registry has `manifest.yaml` with a `schema_url` whose final path segment is the version - every definition and enum member has `stability` - org-local attributes/metrics/spans use a domain prefix - no boundary-domain (http/db/messaging/rpc/network/gen-ai) entries duplicated locally - Counter and UpDownCounter names have no `_total` suffix - duration histograms use `s` (seconds) - templates use jq filters that match the resolved schema (for `definition/2`, call the prebuilt `semconv_grouped_*` helpers with `{"v2": true}`) - generated output is formatter-clean - CI runs `check`, `generate` + `git diff --exit-code`, and `diff` against the base branch - changed files were re-read - remaining risks or gaps are stated