Core0 / Nio
Core0
GitHub v2.4.4
Telemetry · Metrics

# Metrics — three counters and one histogram

Four instruments emitted via OTLP to `<endpoint>/v1/metrics`. Label keys align with matching trace span attributes (`gen_ai.tool.name` matches the tool span, `nio.guard.*` matches the OpenClaw tool-span guard attrs) so cross-signal queries use the same key names.

## Instruments

Instrument | Type | Unit | When recorded
--- | --- | --- | ---
`nio.tool_use.count` | Counter | `{invocations}` | Each `PreToolUse` and `PostToolUse` (and `TaskCreated` / `TaskCompleted` if fired)
`nio.turn.count` | Counter | `{turns}` | Each `Stop` / `SubagentStop` / `SessionEnd` (turn boundary)
`nio.decision.count` | Counter | `{decisions}` | Each guard decision (allow / deny / ask)
`nio.risk.score` | Histogram | `{score}` | Each guard evaluation; 0–1 distribution for avg / p50 / p99

## Labels

Five label keys, used across the four instruments above. Each row below is a unique label.

Attribute | Description | Captured at | Platforms
--- | --- | --- | ---
`gen_ai.tool.name` | Host tool name (`Bash`, `WebFetch`, …); same key as the tool-span attribute | PreToolUse · PostToolUse · guard decision | all
`nio.event` | Hook event firing this counter — `PreToolUse` / `PostToolUse` / `TaskCreated` / `TaskCompleted` | PreToolUse · PostToolUse · TaskCreated · TaskCompleted | all
`nio.platform` | Source platform — `claude-code` / `hermes` / `openclaw` | every metric | all
`nio.guard.decision` | Guard verdict — `allow` / `deny` / `ask` | guard decision | all
`nio.guard.risk_level` | Guard risk level — `low` / `medium` / `high` / `critical` | guard decision | all

## Label sets per instrument

Instrument | Labels
--- | ---
`nio.tool_use.count` | `gen_ai.tool.name` · `nio.event` · `nio.platform`
`nio.turn.count` | `nio.platform`
`nio.decision.count` | `nio.guard.decision` · `nio.guard.risk_level` · `gen_ai.tool.name` · `nio.platform`
`nio.risk.score` | `gen_ai.tool.name` · `nio.platform`

`agent_name` deliberately not a metric label

The user-configured `agent_name` lands on traces (`gen_ai.agent.name`) and on audit-log records (`agent_name` field), but not on metrics. Adding it as a metric label would multiply every series by the number of distinct agent names and inflate the backend's cardinality budget. Use `nio.platform` for host-level metric slicing; query the trace / log layer if you need to attribute metrics back to a specific deployment.

Claude Code · Task → Agent

The user-facing Task tool (subagent dispatch) is reported as `tool_name="Agent"` in Claude Code hook payloads, so PreToolUse / PostToolUse counters use `Agent` as the `gen_ai.tool.name` label. The literal value `Task` only appears as a counter label when `TaskCreated` / `TaskCompleted` fire (Teammates / cloud-agent flows; never fired by the regular Task tool subagent on current Claude Code builds — see `e2e-test/hook-subagent-e2e-task.md`). OpenClaw and Hermes use their own native tool names.

Metrics have no local file — there is no `metrics.jsonl`. If `collector.endpoint` is empty, metrics drop on the floor (the meter provider returns `null`).