From hydra-audit-trail
Streams audit-trail events to OTLP-compatible backends (Datadog LLM Observability, Sentry AI Agent Monitoring) with full span fields per closure F-021/F-024. Use when the developer asks "how do I send audit events to Datadog/Sentry?", sets up production observability, wires an OTLP collector, or asks about exporting tool/policy spans. Auto-triggers on: "send audit to datadog", "sentry ai monitoring", "otlp exporter", "audit observability", "ship audit events", "production observability for hydra", "F-021", "F-024".
How this skill is triggered — by the user, by Claude, or both
Slash command
/hydra-audit-trail:audit-otlpThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
<purpose>
<decision_tree>
IF user asks "how do I send audit events to Datadog/Sentry":
→ Walk them through the three pieces:
1. The exporter at scripts/otel-exporter.py (stdlib, offline-first)
2. The example collector config at scripts/otel-config.example.yaml
3. The required env vars (DD_API_KEY, SENTRY_DSN, OTEL_EXPORTER_OTLP_ENDPOINT)
→ Show the canonical pipe:
python ${CLAUDE_PLUGIN_ROOT}/scripts/otel-exporter.py
${CLAUDE_PLUGIN_ROOT}/state/audit.jsonl --follow
| curl -s -XPOST http://localhost:4318/v1/traces
-H 'content-type: application/json' --data-binary @-
IF user asks for a one-shot export (not follow mode):
→ Run:
python "${CLAUDE_PLUGIN_ROOT}/scripts/otel-exporter.py"
"${CLAUDE_PLUGIN_ROOT}/state/audit.jsonl"
→ Pipe the stdout into their collector or save to a file.
IF user asks "what fields does the span carry": → Quote the closure schema verbatim: agent.id, tool.name, tool.duration_ms, tool.bytes_in, tool.bytes_out, network.dest_host, policy.outcome, error.type, plus trace_id and span_id. Source-row prev_hash rides as audit.prev_hash for forensic correlation.
IF user asks to smoke-test the exporter:
→ Pipe a synthetic line through and confirm OTLP/JSON shape:
echo '{"event":"tool_use","ts":"2026-04-15T14:23:00Z","tool":"Write","duration_ms":42,"bytes_in":120,"bytes_out":0,"prev_hash":"GENESIS","policy_outcome":"allowed"}'
| python "${CLAUDE_PLUGIN_ROOT}/scripts/otel-exporter.py" /dev/stdin
→ Confirm: top-level resourceSpans key, span has traceId/spanId,
attributes include tool.name + policy.outcome.
IF audit.jsonl is empty: → Tell the operator: nothing to export yet; events accumulate as the PostToolUse hook fires.
IF the operator asks about protobuf encoding: → "The exporter emits OTLP/JSON. The OTLP collector handles protobuf encoding to the backend's wire format. This is a deliberate offline- first choice — no OpenTelemetry SDK dependency." </decision_tree>
<output_format>
scripts/otel-exporter.pyscripts/otel-config.example.yamlstate/audit.jsonl (HMAC-chained, R8 EMA-tracked)python scripts/otel-exporter.py state/audit.jsonl --follow \
| curl -s -XPOST $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces \
-H 'content-type: application/json' --data-binary @-
| Attribute | Source row field | Notes |
|---|---|---|
| agent.id | agent_id / session_id | session correlator |
| tool.name | tool | Write/Edit/Bash/etc |
| tool.duration_ms | duration_ms | int |
| tool.bytes_in/out | bytes_in/out | int |
| network.dest_host | dest_host | only for net-touching |
| policy.outcome | policy_outcome | allowed/blocked/warn |
| error.type | error_type | exception class |
| trace_id | derived from prev_hash | 32 hex |
| span_id | UUID v4 (16 hex) | per span |
| </output_format> |
<failure_modes>
npx claudepluginhub enchanter-ai/hydra --plugin audit-trailProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.