otel-as-code-plugin
CLAUDE.md1 starsChanged 47 days agoApache-2.0View on GitHub
This repo IS a Claude Code plugin (commands / skills / agents / hooks), not an app. .claude-plugin/plugin.json holds ONLY metadata — components are AUTO-DISCOVERED from conventional dirs: commands/*.md, agents/*.md, skills/<name>/SKILL.md, hooks/hooks.json. Each command needs description frontmatter; each agent/skill needs name + description. .claude-plugin/marketplace.json makes the repo installable as its own marketplace. Validate structure with claude plugin validate . --strict. Cross-agent instructions live in AGENTS.md (read by Codex et al.); the same capabilities are bridged to Codex: skills in .agents/skills/…
In this repository18 other files it gives its agents.
- AGENTS.mdAGENTS.md
- otel-backendSkill
- otel-business-attrsSkill
- otel-collectorSkill
- otel-evaluateSkill
- otel-initSkill
- otel-instrumentSkill
- otel-remediateSkill
- otel-uninstrumentSkill
- semconv-disciplineSkill
- new-backendSkill
- validate-pluginSkill
- business-attr-uxSkill
- collector-topologySkill
- deployment-remediationSkill
- language-maturitySkill
- semconv-disciplineSkill
- terraform-patternsSkill
The file
We split this CLAUDE.md into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 19
Read stdin JSON keys tool_name and tool_input.file_path (NOT tool/input).
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
otel-as-code — Claude Code plugin
This repo IS a Claude Code plugin (commands / skills / agents / hooks), not an app.
.claude-plugin/plugin.json holds ONLY metadata — components are AUTO-DISCOVERED from
conventional dirs: commands/*.md, agents/*.md, skills/<name>/SKILL.md, hooks/hooks.json.
Each command needs description frontmatter; each agent/skill needs name + description.
.claude-plugin/marketplace.json makes the repo installable as its own marketplace.
Validate structure with claude plugin validate . --strict.
Cross-agent instructions live in AGENTS.md (read by Codex et al.); the same capabilities are
bridged to Codex: skills in .agents/skills/ (thin wrappers pointing back at commands/,
skills/, agents/), and the guardrails in .codex/hooks.json (PreToolUse/PostToolUse adapters
in hooks/codex/ that reuse hooks/*.sh, translating Codex's apply_patch payload +
permissionDecision contract). Keep the bridges in sync when you rename/move a command, skill,
agent, or hook — the validate-codex-bridge CI job checks the skill references resolve.
Hooks (hooks/*.sh, registered in hooks/hooks.json)
- Registered in
hooks/hooks.json(NOT inline in plugin.json): PreToolUse/PostToolUse matcherWrite|Edit→ write-guard / semconv-lint; SessionEnd → session-summary; each invoked asbash "${CLAUDE_PLUGIN_ROOT}/hooks/<name>.sh". - Read stdin JSON keys
tool_nameandtool_input.file_path(NOTtool/input). Parse withpython3, notjq. --forcereaches the write-guard via a path-scoped.claude/.otel-forcesentinel (a slash-command flag can't set env for the hook process). Sentinel entries are matched byhooks/otel-force-match.py, which normalises BOTH sides (Windows drive letters/backslashes ↔ Git Bash/c/…, relative ↔ absolute,./..) — never compare these paths as raw strings, agrep -Fxqcan't match across host conventions and silently turns--forceinto a no-op.hooks/otel-paths.shis the single source of truth for which files the plugin generates (stems × extensions + fixed names);write-guard.shandsession-summary.shboth source it. Add a language or extension there, never in a per-hook list — parallel hand-kept lists are howtelemetry.tsshipped unguarded.- semconv-lint is advisory by default (exit 0); strict mode hard-blocks (exit 2) on severe violations only — service.*-as-span-attr + deprecated http.method/http.url/http.status_code/deployment.environment (Rules 1-4 + 4b, exact deterministic literal matches); heuristic/judgment rules (5-8) stay warn-only, including Rule 8 (a high-cardinality identifier used as a metric-instrument dimension) — CONCEPTUALLY the worst-severity finding this hook can make, per semconv-discipline's cardinality-position ranking, but its detection is a same-file window heuristic that can't bind an
.Add()/.Record()call to the specific instrument a constructor created, only to "some constructor exists somewhere in this file" — a real false positive was found and fixed post-merge, so it doesn't clear the bar strict-mode blocking requires. Opt in viaOTEL_STRICT=1(env, e.g. CI) or a.claude/.otel-strictsentinel (same dual pattern as--force). Codex PostToolUse can't deny, so its adapter reframes the block as a must-fixadditionalContext. The hook gates on file content referencing an OTel API (not filename — a basename-only gate skipped application code entirely, #138), and its attribute-setter matching is language-aware across all seven supported languages, not just the JS/JavasetAttribute(spelling. - Tests:
bash tests/hooks/<name>.test.sh; feed the REAL payload (tool_name/tool_input); wire every new test into thelint-hooksjob in.github/workflows/ci.yml.
Conventions
- Subagents have no
Skilltool and cannot read a skill by name (skills live in the plugin cache, off the target repo, with a path the agent doesn't know). A command that dispatches a subagent MUST hand it the guidance as explicit inputs — a value (e.g.semconvVersion) and/or an absoluteSKILL.mdpath the subagentReads (semconvGuidancePath,languageMaturityPath,terraformPatternsPath, resolved via${CLAUDE_PLUGIN_ROOT}). NEVER write "read theotel-as-code:<skill>skill" in an agent file — it silently fails (the scanner then stampedguidanceVersion: null, the auditor a remembered1.27.0). Only the main agent running a command hasSkill. SEMCONV_VERSIONinskills/semconv-discipline/SKILL.mdis the single source of truth; the lint hook greps it and generators stamp<SEMCONV_VERSION>. Don't hardcode the version elsewhere. It is the spec version — the SDK/semconv packages version independently, so never derive one from the other, and never let generated comments assert which constants a package exports (verify against the installed package or say nothing).agents/repo-context-scanner.mdowns the context-JSON schema AND the cache ownership contract (scanner-owned vs user-owned fields). Commands must pass the existing cache aspriorContextso a refresh MERGES — a bare re-scan silently destroys confirmed business attributes. Don't restate the schema in another file; point at the scanner.- Cache freshness is keyed to the identity-input fingerprint defined in
/otel-initStep 1, not toHEAD. Other commands reference that step rather than re-deriving a rule. language≠runtime./otel-instrumentselects a service filtered byinstrumentable, neverservices[0]; a browser SPA islanguage: nodejs,runtime: browser, and must be refused with a reason rather than emitted for.- Optional external sources: detect, enrich, degrade — never require. An MCP server or hosted service may sharpen what this plugin does (a Terraform registry lookup verifying provider schemas in
terraform-gen; the upstream semconv registry checking the OLD→NEW table indrift_check.py), but it is never a dependency. Three rules: the offline path must keep working unchanged (CI validates golden snapshots with no network and no vendor auth); an unavailable source is reported as "not checked", never as a finding — a broken checker must not read as broken guidance or wrong code; and never claim verification that did not happen, so generated output states which source it was verified against, or says it was not. Vendor MCPs are runtime/query tools against a live account; this plugin generates committed artifacts before one exists. Use them to verify and validate, never to generate — routing generation through a vendor re-introduces the lock-in that vendor-neutral OTel output exists to avoid. backends.txt(repo root) is the single source of truth for the supported vendor list; the CIvalidate-terraformloop,tests/check-snapshots.sh,hooks/session-summary.sh, and/otel-backendvalidation all read it. Don't hardcode the vendor list elsewhere (per-vendor content interraform-patterns.md/terraform-gen.mdis fine).- Terraform golden snapshots:
tests/snapshots/<vendor>/main.tf.snap, self-contained (inlinevariableblocks) so CI validatesmain.tfstandalone.terraformisn't installed — download a pinned binary to validate; introspect unfamiliar providers withterraform providers schema -json. scripts/drift_check.py(weeklydrift-checkCI job; alsoworkflow_dispatch) reports when the pinned semconv / OTel-SDK / TF-provider versions fall behind upstream — informational, never fails CI (tests/drift-check.test.shkeeps its pin parsers honest offline). When it flags drift: bump the pins, regenerate the affected snapshots, re-validate.
Shell
- GitHub Actions runs
run:blocks asbash -eo pipefail; reproduce CI shell logic with that, not the local zsh (zsh doesn't word-split unquoted$VAR— use literal args/arrays).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

