Problem
When gh-aw is configured with observability.otlp.endpoint pointing at Langfuse (/api/public/otel), the Langfuse Sessions and Users views remain empty. Langfuse builds those views from langfuse.session.id / session.id and langfuse.user.id / user.id attributes (see Langfuse OTEL attribute mapping). gh-aw never sets these keys, even though it already has the right data:
- An automation session is already modelled as gh-aw.episode.id (see actions/setup/js/send_otlp_span.cjs → buildEpisodeAttributesFromContext, defined at line 196). One episode spans the parent run plus any dispatched child workflow_calls, which is exactly what a Langfuse session should be.
- The triggering GitHub user is already emitted as gh-aw.run.actor (login) and github.actor_id (numeric).
A grep -rn 'langfuse.|session.id|user.id' actions/ pkg/ returns zero relevant hits.
Proposal
In both sendJobSetupSpan and sendJobConclusionSpan (and in emit_outcome_spans.cjs), after computing episodeId and actor, push:
if (episodeId) {
attributes.push(buildAttr("langfuse.session.id", episodeId));
attributes.push(buildAttr("session.id", episodeId));
}
if (actor) {
attributes.push(buildAttr("langfuse.user.id", actor));
attributes.push(buildAttr("user.id", actor));
}
langfuse.* is preferred by Langfuse; the plain session.id/user.id aliases also satisfy OpenInference and several other backends, which is consistent with gh-aw's existing dual-emission style (it already emits both gh-aw.hop.id and the legacy gh-aw.workflow_call.id).
Acceptance criteria
- After a workflow run completes, Langfuse Sessions view shows a session keyed by episode.id containing all spans from the run.
- Langfuse Users view shows the GitHub actor with that run's traces.
- Existing tests in pkg/workflow/observability_otlp_test.go and actions/setup/js/*.test.cjs still pass.
- A new unit test asserts the four attributes are present on both setup and conclusion span payloads when episodeId/actor are non-empty.
- No new external dependencies.
References
Problem
When gh-aw is configured with observability.otlp.endpoint pointing at Langfuse (/api/public/otel), the Langfuse Sessions and Users views remain empty. Langfuse builds those views from langfuse.session.id / session.id and langfuse.user.id / user.id attributes (see Langfuse OTEL attribute mapping). gh-aw never sets these keys, even though it already has the right data:
A grep -rn 'langfuse.|session.id|user.id' actions/ pkg/ returns zero relevant hits.
Proposal
In both sendJobSetupSpan and sendJobConclusionSpan (and in emit_outcome_spans.cjs), after computing episodeId and actor, push:
langfuse.* is preferred by Langfuse; the plain session.id/user.id aliases also satisfy OpenInference and several other backends, which is consistent with gh-aw's existing dual-emission style (it already emits both gh-aw.hop.id and the legacy gh-aw.workflow_call.id).
Acceptance criteria
References