agentleFS
radra23radra23/otel-as-code-plugin/CLAUDE.md

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/…

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
  1. Very specific:

    Read stdin JSON keys tool_name and tool_input.file_path (NOT tool/input).

    line 19

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

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 matcher Write|Edit → write-guard / semconv-lint; SessionEnd → session-summary; each invoked as bash "${CLAUDE_PLUGIN_ROOT}/hooks/<name>.sh".
  • Read stdin JSON keys tool_name and tool_input.file_path (NOT tool/input). Parse with python3, not jq.
  • --force reaches the write-guard via a path-scoped .claude/.otel-force sentinel (a slash-command flag can't set env for the hook process). Sentinel entries are matched by hooks/otel-force-match.py, which normalises BOTH sides (Windows drive letters/backslashes ↔ Git Bash /c/…, relative ↔ absolute, ./..) — never compare these paths as raw strings, a grep -Fxq can't match across host conventions and silently turns --force into a no-op.
  • hooks/otel-paths.sh is the single source of truth for which files the plugin generates (stems × extensions + fixed names); write-guard.sh and session-summary.sh both source it. Add a language or extension there, never in a per-hook list — parallel hand-kept lists are how telemetry.ts shipped 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 via OTEL_STRICT=1 (env, e.g. CI) or a .claude/.otel-strict sentinel (same dual pattern as --force). Codex PostToolUse can't deny, so its adapter reframes the block as a must-fix additionalContext. 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/Java setAttribute( spelling.
  • Tests: bash tests/hooks/<name>.test.sh; feed the REAL payload (tool_name/tool_input); wire every new test into the lint-hooks job in .github/workflows/ci.yml.

Conventions

  • Subagents have no Skill tool 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 absolute SKILL.md path the subagent Reads (semconvGuidancePath, languageMaturityPath, terraformPatternsPath, resolved via ${CLAUDE_PLUGIN_ROOT}). NEVER write "read the otel-as-code:<skill> skill" in an agent file — it silently fails (the scanner then stamped guidanceVersion: null, the auditor a remembered 1.27.0). Only the main agent running a command has Skill.
  • SEMCONV_VERSION in skills/semconv-discipline/SKILL.md is 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.md owns the context-JSON schema AND the cache ownership contract (scanner-owned vs user-owned fields). Commands must pass the existing cache as priorContext so 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-init Step 1, not to HEAD. Other commands reference that step rather than re-deriving a rule.
  • language ≠ runtime. /otel-instrument selects a service filtered by instrumentable, never services[0]; a browser SPA is language: 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 in drift_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 CI validate-terraform loop, tests/check-snapshots.sh, hooks/session-summary.sh, and /otel-backend validation all read it. Don't hardcode the vendor list elsewhere (per-vendor content in terraform-patterns.md/terraform-gen.md is fine).
  • Terraform golden snapshots: tests/snapshots/<vendor>/main.tf.snap, self-contained (inline variable blocks) so CI validates main.tf standalone. terraform isn't installed — download a pinned binary to validate; introspect unfamiliar providers with terraform providers schema -json.
  • scripts/drift_check.py (weekly drift-check CI job; also workflow_dispatch) reports when the pinned semconv / OTel-SDK / TF-provider versions fall behind upstream — informational, never fails CI (tests/drift-check.test.sh keeps its pin parsers honest offline). When it flags drift: bump the pins, regenerate the affected snapshots, re-validate.

Shell

  • GitHub Actions runs run: blocks as bash -eo pipefail; reproduce CI shell logic with that, not the local zsh (zsh doesn't word-split unquoted $VAR — use literal args/arrays).

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.