Skip to main content

Span attribute reference

Every attribute the plugin may set, grouped by span type. See Attribute conventions for the narrative version of the dual-convention mapping (OpenInference llm.* / input.value for Phoenix and OTel GenAI gen_ai.* for Langfuse, Weave and generic dashboards).

Attributes marked optional are only set when the underlying data is available. Previews (input.value, output.value, gen_ai.*.messages, tool args/results) are gated by capture_previews and clipped to preview_max_chars (or the per-category cap); the capture_full_* flags add the untruncated fields noted below.

A test (tests/unit/test_span_attributes_docs.py) fails if the code sets an attribute this page does not list, or this page lists one the code never sets.

Resource (on every span)

AttributeSource
service.namehermes-agent (fixed; override via resource_attributes:)
service.instance.idUUID generated once per process — keeps two Hermes processes on different metric series
service.versionPlugin version, read from the shipped plugin.yaml
process.pidProcess id
openinference.project.nameproject_name / OTEL_PROJECT_NAME (the Phoenix project); optional
host.nameHostname, only when host_metrics: true
wandb.entity, wandb.projectW&B Weave routing (when configured)
telemetry.sdk.*Set by the OTel SDK
any resource_attributes.* / global_tags.*From the config file; resource_attributes wins on key conflict

Every span

AttributeConventionMeaning
openinference.span.kindOpenInferenceAGENT (root, subagent) · LLM (llm.*, api.*) · TOOL (tool.*) · CHAIN (skill, approval)
hermes.turn.numberhermes1-based index of the user prompt within the session (per process; hermes -r restarts at 1). On the root and on every llm.* / api.* / tool.* span of the turn
session.idOTelHermes session id, on the root and on llm.* / api.* / subagent.*
gen_ai.conversation.idgen_aiSame id, gen_ai spelling, wherever gen_ai.operation.name is set
correlation.idhermesCorrelation id Hermes passes on the hook (optional)
user.id, hermes.sender.idOTel / hermesGateway sender identity — only with capture_sender_id: true. user.id is platform:sender

agent / cron (turn root)

The root span is named agent, or cron when the session kind is a cron job. Set at start:

AttributeConventionTypeMeaning
hermes.session.kindhermesstringcli · telegram · discord · cron · …
hermes.session_idhermesstringSession id (pre-existing spelling; session.id is the standard one)
llm.model_name, llm.providerOpenInferencestringModel / platform the turn started with
gen_ai.request.modelgen_aistringModel name
gen_ai.operation.namegen_aistringinvoke_agent
gen_ai.agent.namegen_aistringhermes-agent (Weave shows it as the agent)
wandb.is_turn, wandb.thread_idWeavebool / stringMarks a Weave conversation turn and groups turns by session
weave.agent.versionWeavestringPlugin version (optional)
hermes.session.synthesizedhermesbooltrue when the root was created lazily because on_session_start never fired (optional)
hermes.cron.job_idhermesstringCron job id, cron roots only (optional)
hermes.session.is_subagenthermesbooltrue on a delegated child's own root (optional)
hermes.subagent.role, hermes.subagent.parent_session_idhermesstringOn a delegated child's root (optional)

Set at end (turn summary; empty/zero aggregators are omitted):

AttributeTypeMeaning
hermes.session.completed, hermes.session.interruptedboolHook payload flags
hermes.turn.final_statusstringcompleted · interrupted · incomplete (also timed_out when the orphan sweep closes an abandoned turn)
hermes.turn.tool_count, hermes.turn.toolsint / stringDistinct tool names (sorted CSV, ≤500 chars)
hermes.turn.tool_targets, hermes.turn.tool_commandsstring|-joined distinct paths/URLs and shell commands
hermes.turn.tool_outcomesstringSorted CSV of distinct outcomes
hermes.turn.skill_count, hermes.turn.skillsint / stringSkills that loaded successfully this turn
hermes.turn.api_call_countintpre_api_request hooks fired
gen_ai.response.modelstringModel at turn end
error.typestringMost recent provider error class this turn (optional)
input.value, output.valuestringFirst user message / final assistant response of the turn (previews; optional)

llm.*

One per run_conversation call (span kind LLM).

AttributeConventionTypeMeaning
llm.model_name, llm.providerOpenInferencestringModel / provider
gen_ai.request.modelgen_aistringModel name
gen_ai.operation.namegen_aistringchat
input.value, input.mime_typeOpenInferencestringUser message (text/plain) or, with capture_conversation_history, the conversation JSON (application/json)
gen_ai.input.messagesgen_aistring (JSON)Same content in the gen_ai message shape
output.value, output.mime_typeOpenInferencestringFinal assistant response
gen_ai.output.messagesgen_aistring (JSON)Same in the gen_ai shape
gen_ai.response.modelgen_aistringModel at response time
hermes.conversation.message_counthermesintMessage count when conversation capture is on (optional)

api.*

One per HTTP round-trip to the provider (span kind LLM). Set at start:

AttributeConventionTypeMeaning
llm.model_name, llm.providerOpenInferencestringModel / provider
gen_ai.request.model, gen_ai.system, gen_ai.provider.namegen_aistringModel / provider (gen_ai.system is the legacy spelling Langfuse reads)
gen_ai.operation.namegen_aistringchat
llm.api_modehermesstringchat_completions · anthropic_messages · codex_responses · …
llm.request.message_count, llm.request.approx_input_tokens, llm.request.max_tokenshermesintRequest shape as Hermes reports it
gen_ai.request.max_tokens, gen_ai.request.temperature, gen_ai.request.top_p, gen_ai.request.top_k, gen_ai.request.frequency_penalty, gen_ai.request.presence_penalty, gen_ai.request.stream, gen_ai.request.reasoning.level, gen_ai.request.stop_sequences, gen_ai.request.choice.countgen_aimixedRequest parameters, each only when Hermes passes it (optional)
input.value, input.mime_typeOpenInferencestringRequest preview
llm.input_messages, gen_ai.input.messagesbothstring (JSON)Full request messages — capture_full_prompts: true only
llm.system_prompt, gen_ai.system_instructionsbothstringFull system prompt — capture_full_prompts: true only

Set at end (success):

AttributeConventionTypeMeaning
llm.token_count.prompt, llm.token_count.completion, llm.token_count.totalOpenInferenceintWhole prompt (incl. cache reads/writes), completion, sum
llm.token_count.prompt_details.cache_read, llm.token_count.prompt_details.cache_writeOpenInferenceintCache buckets (optional)
llm.token_count.completion_details.reasoningOpenInferenceintReasoning tokens, a subset of completion (optional)
gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.usage.total_tokensgen_aiintSame three totals
gen_ai.usage.cache_read.input_tokens, gen_ai.usage.cache_creation.input_tokensgen_aiintCache buckets, current spelling (optional)
gen_ai.usage.cache_read_input_tokens, gen_ai.usage.cache_creation_input_tokensgen_aiintSame values, pre-existing alias kept for older dashboards (optional)
gen_ai.usage.reasoning.output_tokensgen_aiintReasoning tokens (optional)
gen_ai.response.model, gen_ai.response.idgen_aistringResponse model / id (optional)
gen_ai.response.finish_reasonsgen_aistring[]["stop"], ["tool_use"], …
llm.response.finish_reasonhermesstringSame, scalar
llm.response.duration_mshermesfloatWall-clock of the request
llm.response.output_chars, llm.response.tool_callshermesintAssistant content length / tool-call count (optional)
output.value, output.mime_typeOpenInferencestringResponse preview
llm.output.content, llm.output.tool_calls, gen_ai.output.messagesbothstring (JSON)Full response — capture_full_responses: true only

api.* on failure (api_request_error)

When the request fails, the span ends with StatusCode.ERROR, an exception event (exception.type / exception.message / exception.escaped), and:

AttributeConventionTypeMeaning
error.typeOTelstringError class reported by Hermes (e.g. RateLimitError)
http.response.status_code, gen_ai.response.status_codeOTel / gen_aiintHTTP status (omitted for network errors)
hermes.retry.count, hermes.max_retries, hermes.retryablehermesint / int / boolRetry state for this request
llm.response.duration_mshermesfloatWall-clock of the failed attempt

The most recent error.type is also stamped on the turn's root span at on_session_end.

tool.*

One per tool call (span kind TOOL), keyed by Hermes' tool_call_id so parallel calls never collide.

AttributeConventionTypeMeaning
tool.name, gen_ai.tool.namebothstringTool name
gen_ai.tool.call.idgen_aistringHermes tool_call_id (falls back to task_id on older Hermes)
gen_ai.operation.namegen_aistringexecute_tool
input.value, gen_ai.tool.call.argumentsbothstringTool args (JSON preview; full for mcp_* tools with capture_full_prompts)
output.value, gen_ai.tool.call.resultbothstringTool result preview
hermes.tool.targethermesstringFirst non-empty path / file_path / target / url / uri arg (optional)
hermes.tool.commandhermesstringFirst non-empty command / cmd arg (optional)
hermes.tool.outcomehermesstringcompleted · error · timeout · blocked · cancelled (or a status the tool reported in its result)
error.messageOTelstringResult error text when the outcome is error (optional)
hermes.skill.name, hermes.skill.sourcehermesstringBare skill name and skill_view / path_match when the call loaded a skill (optional)
hermes.tool.cpu.utilization.avg, hermes.tool.cpu.utilization.peakhermesfloatProcess-tree CPU (0..1) during the call — host_metrics only
hermes.tool.gpu.utilization.avg, hermes.tool.gpu.utilization.peakhermesfloatHost GPU busy ratio (0..1) during the call — host_metrics + GPU only

The utilization attributes are absent when host metrics are off or the tool finished between two samples. See Host & GPU metrics.

skill.*

One per skill that loaded successfully this turn (skill_spans: true), nested under the root; opens when the loading tool call ends and closes at turn end.

AttributeConventionTypeMeaning
hermes.skill.name, gen_ai.skill.namebothstringBare skill name as Hermes names it
hermes.skill.sourcehermesstringskill_view · path_match
hermes.skill.pathhermesstring$HERMES_HOME/skills/<name>
hermes.span_kindhermesstringskill
gen_ai.operation.namegen_aistringexecute_skill
hermes.skill.result_statushermesstringTurn outcome at close (completed · interrupted · …)

approval.*

One per human-in-the-loop (or smart-guardian) approval prompt, named approval.<pattern_key>.

AttributeConventionTypeMeaning
hermes.approval.pattern_key, hermes.approval.pattern_keyshermesstringRule(s) that gated the command
hermes.approval.surfacehermesstringcli · telegram · … (optional)
hermes.approval.command, hermes.approval.descriptionhermesstringGated command and Hermes' description (previews; optional)
gen_ai.tool.call.idgen_aistringCorrelates to the gated tool.* span (optional)
hermes.span_kindhermesstringapproval
hermes.approval.granted, hermes.approval.timed_outhermesboolOutcome flags
hermes.approval.choicehermesstringonce · session · always · deny · timeout · smart_approve · smart_deny · notify_failed
hermes.approval.decided_byhermesstringaux_llm for smart-guardian verdicts, empty for a human answer (optional)
hermes.approval.duration_mshermesfloatDecision wait time

subagent.*

One per delegated child agent (span kind AGENT); the child's own root nests beneath it (or is linked, cross-process).

AttributeConventionTypeMeaning
gen_ai.operation.name, gen_ai.agent.namegen_aistringinvoke_agent / child role
hermes.subagent.role, hermes.subagent.goalhermesstringChild role and delegated goal (preview)
input.valueOpenInferencestringThe goal preview
hermes.subagent.child_session_id, hermes.subagent.child_idhermesstringChild session / sub-agent ids
hermes.subagent.parent_session_id, hermes.subagent.parent_turn_id, hermes.subagent.parent_idhermesstringParent identity
hermes.subagent.status, hermes.subagent.duration_ms, hermes.subagent.summary, output.valuehermesmixedOn stop: reported child_status, wall-clock, result summary

Metrics

Metrics are documented on their own page: Metrics reference.