Skip to content

feat(telemetry): emit skill/session lifecycle events from the hook#1795

Open
gpanaitescu wants to merge 4 commits into
mainfrom
feature/skills_lifecycle_telemetry
Open

feat(telemetry): emit skill/session lifecycle events from the hook#1795
gpanaitescu wants to merge 4 commits into
mainfrom
feature/skills_lifecycle_telemetry

Conversation

@gpanaitescu

@gpanaitescu gpanaitescu commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Shipping plan — merge BEFORE the Sunday 2026-07-12 release cut

  • targetCli pairing — schedule + post-cut verification, not a merge blocker. The v2 hook must ship paired with the first CLI release carrying UiPath/cli#2815 — a pre-lifecycle CLI treats eventName as an unknown field and would emit lifecycle payloads as phantom tool-use events (identifiable/filterable: schemaVersion == 2 with empty toolName). The pairing is enforced by the release train, not by this file: uip skills install pins the skills package to the CLI's own minor, and the skills sprint-release-cut stamps targetCli to the paired line at cut time. So: merge this PR and cli#2815 to their mains before the Sunday 2026-07-12 cut (skills cut 06:00 UTC, CLI cut 12:00 UTC; missing it slips the emitter to the Jul 26 train while CLI 1.199 ships ingestion unpaired) — then verify after the cut that the skills 1.199 release line carries targetCli: ^1.199.0 (the automation's drift check is warn-only). Residual exposure between merge and CLI-1.199 reaching users: only channels tracking the repo directly (marketplace/main dogfooders — overwhelmingly IsInternalUser), bounded by the CLI's self-update.
  • Reconcile with feat(telemetry): support other coding agents and flip gate to opt-out #1745 after it lands — done: rebased on the merged feat(telemetry): support other coding agents and flip gate to opt-out #1745; lifecycle events inherit the flipped opt-out gate (verified: unset sends, 1 drops, 0 sends); its "schemaVersion stays 1" wording updated to v2.

What

Extends the telemetry hook (hooks/send-telemetry.sh) from a single PostToolUse
tool-use event to skill/session lifecycle events, and adds a synchronous
SessionStart step (hooks/set-session-env.sh) that exports UIPATH_SESSION_ID
so native uip command telemetry carries the same session id. This is the
emitter half of UiPath/cli#2786; it requires the CLI ingestion change in
UiPath/cli#2815 (the CLI resolves the eventName token this hook now sends
to a uip.skills.<event> event). Co-versioned via schemaVersion (bumped 1 → 2).

Mapping

send-telemetry.sh is now registered on four more Claude Code hook events and maps
each to a canonical eventName:

Claude Code hook eventName Notes
PostToolUse (existing) tool-use unchanged — per-call, plugin-attribution gated
SessionStart session-start sourcesession_source
Stop completion outcome=ok
StopFailure completion outcome=failure (API-error turn)
SessionEnd session-end reason

Schema v2

  • Adds eventName / session_source / reason.
  • Adds agent_model (UiPath/cli#2785 enrichment, riding the same bump): the
    session's main model from the envelope model — Claude Code sends it on
    SessionStart, Codex on every hook event. Full sanitized slug (model-comparison
    views need version granularity); distinct from subagentModel (spawned child's
    family). Claude sessions get full coverage at query time via the session_id
    join from session-start. Needs a small CLI follow-up to accept the field in
    ALLOWED_FIELDS (until then it is silently dropped — additive-safe).
  • Renames sessionIdsession_id — the canonical casing, matching the CLI
    command stream after UiPath/cli#2800 (uip track still accepts and maps the
    legacy spelling, so no flag-day).
  • Drops environment / baseUrl and the whole resolve_environment path
    (the uip login status call + 1h cache + cache file): since UiPath/cli#2806
    the CLI stamps fresh environment/base_url/region base dimensions on every
    event from its own auth context, so a stale hook-cached copy must not shadow
    them. Removes ~45 lines and the hook's only subprocess call.

Design

  • Lifecycle events are session-scoped: they skip the per-call plugin-attribution
    gate and tool-field derivation, and fire for every session where this plugin is
    installed (the activation-rate denominator).
  • StopFailurecompletion(outcome=failure) so API-error turns aren't lost
    from completion/abandonment metrics. Stop/StopFailure are mutually exclusive
    per turn (Claude Code docs), so completion cannot double-count.
  • set-session-env.sh (new, synchronous): reads the SessionStart payload's
    session_id and appends export UIPATH_SESSION_ID='<id>' to CLAUDE_ENV_FILE,
    so every subsequent uip command inherits it and the CLI stamps the same
    session_id on native command telemetry (UiPath/cli#2800) — skills events and
    command events join at query time. Host-provided value wins; idempotent;
    value sanitized to [A-Za-z0-9._-] before being written into the sourced env
    file; not gated on UIPATH_TELEMETRY_DISABLED (writing a variable transmits
    nothing — the CLI's gate governs whether any event carrying it is sent).
  • Gate inherited from feat(telemetry): support other coding agents and flip gate to opt-out #1745 (merged): lifecycle events pass through the same
    opt-out gate as tool-use — this PR neither moves nor duplicates the gate line,
    and its tests set UIPATH_TELEMETRY_DISABLED explicitly so they hold under
    either polarity.

Scope

This is primarily the Claude Code emitter. Under Codex — whose hooks.json
support and payload envelope match Claude's (#1745) — SessionStart/Stop flow
through this same hook already, so Codex gets session-start/completion for
free (it has no session-end hook; completion is its terminal signal).
Gemini CLI and the Cursor CLI expose the same lifecycle moments under
different hook names/registration formats and are separate follow-ups.
Cursor cloud agents are out of scope (ephemeral remote VM — no local uip, no
auth identity, no session-start/-end trigger point).

Testing

  • pytest contract guards (POSIX/CI): test_send_telemetry_hook.py — eventName
    mapping, lifecycle fields, the v2 key set (canonical session_id/session_source,
    no environment/baseUrl/legacy camel keys), drop paths;
    test_set_session_env_hook.py — export line, host-wins, idempotence, hostile
    session-id sanitization, skip paths. Both wired into test-helpers.yml.
  • Manual end-to-end (stubbed uip): all five Claude hook payloads produce the
    correct v2 JSON; a UIPATH_SKILL=uipath-platform uip or assets list tool call
    still attributes cleanly (uipSubcommand: "or assets").
  • Post-feat(telemetry): support other coding agents and flip gate to opt-out #1745 rebase re-verified the flipped gate end-to-end on the lifecycle
    paths: unset sends, 1 drops, 0 sends; v2 envelope unchanged.
  • Earlier verified against the real uip track (CLI's telemetry-capture.ts):
    maps to uip.skills.session-start/uip.skills.completion, eventName consumed
    and not emitted, session id → stable uuid#hash.
  • bash -n clean on both hooks; hooks.json / version-manifest.json valid JSON.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @gpanaitescu's task in 3m 44s —— View job


PR Review: feat(telemetry): emit skill/session lifecycle events from the hook

  • Read review criteria and project conventions
  • Read full diff and changed files
  • Check shell script correctness
  • Check hooks.json structure
  • Check TELEMETRY.md documentation
  • Check version-manifest.json
  • Verify no secrets/tokens/hardcoded paths
  • Post review findings

Summary

Extends the telemetry hook from a single PostToolUse event to five Claude Code hook events (SessionStart, Stop, StopFailure, SessionEnd), mapping each to a canonical eventName token (session-start, completion, session-end). Schema version bumped 1 → 2 in both the hook and version-manifest.json. Lifecycle events are session-scoped (skip the per-call attribution gate), while the existing tool-use path is unchanged.

Change-by-Change Review

1. hooks/send-telemetry.sh

Severity: OK

Well-structured changes:

  • map_event_name / lifecycle_outcome (lines 314–333): Clean case statements, unrecognized events return empty → main() drops them. Stop/StopFailure both map to completion with distinct outcomes — correct.
  • extract_fields awk (lines 69–72): source and reason added to envelope-level (depth 1) extraction. Region scoping is preserved — these fields can only match at the top level, so embedded customer content can't collide.
  • read_fields (lines 160–189): source correctly mapped to session_source (avoids the CLI-owned source dimension). reason stored as-is.
  • main() refactoring (lines 410–431): The if/else branch cleanly separates tool-use (attribution-gated, derives tool fields, outcome from tool_response) from lifecycle (session-scoped, no attribution gate, outcome from event type). Tool-specific variables (skill_name, uip_subcommand, file_ext, subagent_model) are explicitly initialized to empty in the lifecycle branch so the fixed key set always assembles.
  • build_event_json (lines 370–389): eventName, sessionSource, reason added at appropriate positions.
  • Sanitization (lines 442–459): All new fields pass through san().
  • resolve_environment and read_skills_version correctly stay outside the if/else — all events carry environment info.

2. hooks/hooks.json

Severity: OK

  • SessionStart now includes send-telemetry.sh as the third hook (async), after the sync ensure-uip.sh and suggest-permissions.sh. Since hooks in the same group run in order, uip is guaranteed to be installed before the telemetry hook fires. Correct.
  • SessionEnd, Stop, StopFailure are new top-level entries, each with a single async telemetry hook. No matcher needed (they're not tool-scoped). No once: true (each occurrence should fire). Correct.
  • Valid JSON structure.

3. TELEMETRY.md

Severity: Medium — two stale references

The new §Events table (lines 19–25), updated field docs (lines 96–115), region-scoping table (line 135), outcome semantics (lines 147–163), and correlation section (lines 224–229) are all accurate and thorough.

Issue 1Line 77: "hard-codes the event name uip.skills.tool-use" is stale. With schema v2, uip track now maps the eventName token to uip.skills.<event> — it no longer hard-codes a single event name. The comment at send-telemetry.sh:461 already has the correct wording ("maps our eventName token to the uip.skills.<event> name").

Fix this →

Issue 2Line 89: "Each event is the App Insights event uip.skills.tool-use." is stale. Events now span uip.skills.tool-use, uip.skills.session-start, uip.skills.completion, and uip.skills.session-end.

Fix this →

4. version-manifest.json

Severity: OK

schemaVersion bumped 1 → 2, consistent with the hook. skillsVersion and targetCli unchanged — correct, since this is a hook-level schema change, not a CLI version bump.

What's Missing

  • TELEMETRY.md §"How it works" (lines 63–81): Steps 1–4 still describe only the PostToolUse flow. Now that the hook handles five events, this section could note the lifecycle events. Not blocking — the new §Events table covers the mapping — but the step-by-step reads as if PostToolUse is still the only hook.
  • Nothing else identified.

Area Ratings

Area Status Notes
Frontmatter N/A No skill files changed
E2E Tests N/A Hook/infra change, no skill behavior changed
Skill Body N/A No skill files changed
References & Assets OK TELEMETRY.md updated with two stale lines (see above)
Repo Hygiene OK No secrets, no hardcoded paths, valid JSON, async hooks, cross-platform bash

Issues for Manual Review

  • CLI co-version dependency: This hook sends eventName tokens (session-start, completion, session-end) that require UiPath/cli#2815 on the receiving side. If a user has the updated plugin but an older CLI that still hard-codes uip.skills.tool-use, lifecycle events would be emitted under the wrong name or silently dropped. The targetCli: "^1.198.0" constraint should enforce this, but worth verifying the CLI-side mapping is deployed before this ships.
  • source/reason field bleed: The awk extractor pulls source and reason from any event's envelope — not only SessionStart/SessionEnd. If a future Claude Code version adds a source or reason field to e.g. Stop payloads, those values would silently appear in sessionSource/reason on completion events. Low-risk (the doc says "session-start only" / "session-end only"), but worth noting.

Conclusion

Clean, well-structured change. The shell script logic is correct — lifecycle branching, region-scoped extraction, attribution gating, and sanitization all look right. Two stale references in TELEMETRY.md (lines 77 and 89) should be updated before merge to avoid misleading readers. The "How it works" section is a minor doc gap. Recommend fixing the two stale lines and merging.

This comment was marked as outdated.

@gpanaitescu gpanaitescu marked this pull request as draft July 1, 2026 13:55
@gpanaitescu gpanaitescu force-pushed the feature/skills_lifecycle_telemetry branch 2 times, most recently from 6906d10 to 4ed5517 Compare July 2, 2026 12:47
Companion to UiPath/cli#2815 (the ingestion contract). Registers
hooks/send-telemetry.sh on SessionStart/SessionEnd/Stop/StopFailure in
addition to PostToolUse and maps them to canonical eventName tokens
(session-start, session-end, completion; Stop/StopFailure both map to
completion, distinguished by outcome, so API-error turns are not lost).
Lifecycle events skip the per-call attribution gate — they fire for
every session with the plugin installed (the activation-rate
denominator).

Schema v2:
- adds eventName / session_source / reason
- renames sessionId -> session_id (canonical casing, matching the CLI
  command stream after UiPath/cli#2800)
- drops environment/baseUrl and the whole resolve_environment path
  (uip login status + 1h cache): the CLI stamps fresh
  environment/base_url/region base dimensions on every event since
  UiPath/cli#2806, so a stale hook-cached copy must not shadow them

New hooks/set-session-env.sh — a synchronous SessionStart step that
exports UIPATH_SESSION_ID to CLAUDE_ENV_FILE, so native uip command
telemetry carries the same session_id and the two streams join. A
host-provided value wins, the value is sanitized before being written
into the sourced env file, and the step is not gated (writing a
variable transmits nothing).

Rebased on #1745 (opt-out gate + Codex spawn_agent support): lifecycle
events inherit the flipped gate untouched, and the schema-v1 wording
in its cross-agent doc section is updated to v2. Tests set
UIPATH_TELEMETRY_DISABLED explicitly, so they hold under either
polarity.

Tests: pytest contract guards (POSIX/CI) run both bash hooks as
subprocesses — eventName mapping, lifecycle fields, the v2 key set,
drop paths; and the env step's export/host-wins/idempotence/
sanitization. Wired into test-helpers.yml (hooks/** trigger).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gpanaitescu gpanaitescu force-pushed the feature/skills_lifecycle_telemetry branch from 4ed5517 to 2bf9a47 Compare July 2, 2026 12:59
@gpanaitescu gpanaitescu requested a review from Copilot July 2, 2026 14:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread version-manifest.json
Comment thread hooks/set-session-env.sh
- set-session-env.sh: repair a missing trailing newline on the existing
  CLAUDE_ENV_FILE before appending, so the export line can never be
  concatenated onto another hook's partial last line.
- send-telemetry.sh: enforce per-event field scoping — session_source
  only on session-start, reason only on session-end — so a future
  payload carrying stray source/reason keys on other events cannot
  bleed into those dimensions.
- TELEMETRY.md: "How it works" step 1 now covers the lifecycle events
  (session-scoped, no per-call gate), not just the PostToolUse flow.
- Tests for the newline repair and the no-bleed guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gpanaitescu

Copy link
Copy Markdown
Contributor Author

Re the Claude bot review (it ran on a pre-reconciliation head) — point-by-point:

  • TELEMETRY.md Issues 1 & 2 (hard-coded uip.skills.tool-use at old lines 77/89): already fixed during the feat(telemetry): support other coding agents and flip gate to opt-out #1745 reconciliation — both spots now describe the eventNameuip.skills.<event> mapping.
  • "How it works" reads PostToolUse-only: fixed in b3ace11 — step 1 now covers the lifecycle events (session-scoped, no per-call gate) and points to §Events.
  • CLI co-version dependency: tracked as the unchecked merge-blocker at the top of the PR description (targetCli pairing rides the 2026-07-12 release-train cut; merge order documented there and in cli#2815's body).
  • source/reason field bleed: hardened in b3ace11session_source is now blanked unless the event is session-start, reason unless session-end, with a pytest proving a stray source/reason on a Stop payload comes out empty. The doc's scoping claim is now an enforced invariant.

@gpanaitescu gpanaitescu marked this pull request as ready for review July 3, 2026 07:36
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @gpanaitescu's task in 4m 34s —— View job


PR Review: feat(telemetry): emit skill/session lifecycle events from the hook

  • Read review criteria and project conventions
  • Read PR diff and existing conversation
  • Review each changed file in full
  • Check for security, correctness, and convention issues
  • Post review findings

Summary

Extends the telemetry hook from a single PostToolUse event to five Claude Code hook events, mapping each to a canonical eventName token. Adds a synchronous set-session-env.sh step that exports UIPATH_SESSION_ID to the agent's env file for cross-stream correlation. Schema version bumped 1 → 2 (adds lifecycle keys, renames sessionIdsession_id, drops stale environment/baseUrl). Includes pytest contract guards for both hooks and CI wiring.

The previous Claude review flagged four issues; the author's follow-up commit (b3ace111) resolved all of them. This review covers the post-reconciliation state.

Change-by-Change Review

1. hooks/send-telemetry.sh

Severity: OK

Clean, well-structured refactoring:

  • map_event_name() (line 294) and lifecycle_outcome() (line 307): correct case-statement mapping; unrecognized events return empty → dropped in main().
  • main() if/else branching (lines 399–410): tool-use path gates on attribution and derives tool fields; lifecycle path skips both and uses lifecycle_outcome(). Tool-specific variables explicitly initialized to empty in the lifecycle branch, so the fixed key set always assembles.
  • Field scoping enforcement (lines 416–417): session_source blanked unless session-start, reason blanked unless session-end. Prevents extraction bleed from future payload additions. Test at test_send_telemetry_hook.py:84 confirms.
  • resolve_environment and its cache infrastructure (~45 lines) cleanly removed — the CLI stamps these base dimensions itself since cli#2806.
  • build_event_json() (line 350): eventName, session_source, reason added; sessionIdsession_id; environment/baseUrl removed. Key ordering matches the doc table.
  • All new fields pass through san() (lines 441–442). The awk extractor correctly adds source and reason to the depth==1 interesting set (line 88).

2. hooks/set-session-env.sh (new)

Severity: OK

Defensive, minimal implementation:

  • Guard chain: CLAUDE_ENV_FILE exists → UIPATH_SESSION_ID not already set → file doesn't already export it → payload has session_id (lines 32–44). Each exit path returns 0.
  • Sanitization (line 43): tr -cd 'A-Za-z0-9._-' | cut -c1-64 strips everything dangerous before the value goes into single quotes in a sourced file. Test at test_set_session_env_hook.py:84 confirms hostile input is neutered.
  • Trailing-newline repair (lines 51–53): prevents concatenating onto a partial last line from another hook — a subtle but important edge case for a sourced env file.
  • Correctly NOT gated on UIPATH_TELEMETRY_DISABLED — writing an env var transmits nothing; the CLI governs whether events carrying it are sent.
  • No once: true in hooks.json is intentional: the idempotence check handles repeated SessionStart events (e.g., resume), while allowing the first call to succeed.

3. hooks/hooks.json

Severity: OK

  • SessionStart: set-session-env.sh (sync, timeout 5) inserted as 3rd hook — after ensure-uip.sh and suggest-permissions.sh, before send-telemetry.sh (async). Correct ordering: uip installed before telemetry fires, session env set before first Bash call.
  • SessionEnd, Stop, StopFailure: each a standalone entry with async send-telemetry.sh. No matcher needed (not tool-scoped). No once: true (each occurrence should fire).
  • Valid JSON.

4. TELEMETRY.md

Severity: OK

The two stale references flagged by the previous reviewer (old lines 77 and 89) are now fixed — the current text at lines 85–86 and 98–99 accurately describes the eventNameuip.skills.<event> mapping. The "How it works" section (lines 66–71) now covers lifecycle events in step 1. The new §Events table, field docs, outcome semantics update, and §Cross-stream correlation are all accurate and consistent with the hook implementation.

5. tests/scripts/test_send_telemetry_hook.py (new)

Severity: OK

Covers: eventName mapping for all five events, lifecycle fields (session_source, reason, outcome), schema version assertion, v2 key set validation (no environment/baseUrl/legacy sessionId/sessionSource), field bleed prevention, and three drop paths (non-UiPath tool call, unrecognized event, opt-out). The stubbed uip uses atomic write (tmp + mv) so the poller never reads a partial capture. Correctly pops UIPATH_SESSION_ID from env to prevent CI-env leakage.

6. tests/scripts/test_set_session_env_hook.py (new)

Severity: OK

Covers: happy path, host-wins, idempotence, appending after unrelated lines, trailing-newline repair, hostile session_id sanitization, and two skip paths (no env file, no session_id in payload). Clean test structure.

7. .github/workflows/test-helpers.yml

Severity: OK

Adds hooks/** path trigger and a new telemetry-hook-tests job running both test files. The hooks/** trigger is at the workflow level (affecting all jobs), but all jobs are fast-running and independent — the minor extra CI cost is acceptable vs. maintaining a separate workflow.

8. version-manifest.json

Severity: OK

schemaVersion 1 → 2. skillsVersion and targetCli unchanged (correct — this is a hook schema change, not a CLI version bump; the PR description documents the targetCli pairing plan for the release cut).

What's Missing

Nothing identified. The PR is well-scoped: hook implementation, documentation, tests, and CI wiring are all present and consistent.

Area Ratings

Area Status Notes
Frontmatter N/A No skill files changed
E2E Tests N/A Infrastructure change, not a skill behavior change
Skill Body N/A No skill files changed
References & Assets OK TELEMETRY.md thoroughly updated; all prior-review findings resolved
Repo Hygiene OK No secrets, valid JSON, cross-platform bash, async hooks, scoped changes

Issues for Manual Review

  • CLI co-version pairing: The targetCli: "^1.198.0" in version-manifest.json doesn't yet encode the v2 dependency on cli#2815. The PR description documents this as a release-train concern (merge both before the 2026-07-12 cut, then verify targetCli gets stamped to ^1.199.0). Worth confirming the release-train automation handles this.
  • Codex lifecycle coverage: The PR description notes Codex gets session-start/completion "for free" through the same hook, but has no session-end signal. Whether that gap matters for Codex session-duration queries is a product decision, not a code issue.

Conclusion

This is a clean, well-implemented PR. The shell logic is correct — lifecycle branching, field scoping enforcement, sanitization, and the synchronous env-file step all handle edge cases carefully. The previous review's findings have all been addressed in b3ace111. Tests provide good contract coverage for both hooks. Documentation is thorough and consistent with the implementation. No blocking issues — recommend merging once the CLI-side pairing (cli#2815) is confirmed on track for the same release cut.


@gpanaitescu

Copy link
Copy Markdown
Contributor Author

Note for reviewers — the red ✗ on "Validate task schema (advisory)" is not from this PR.

It fails on two task YAMLs introduced by #1739 (asdd_crosswalk.yaml, attended_reauth.yaml — 59 pydantic errors against the pinned coder_eval schema) and has shown on every PR in the repo since Jul 2. The job is continue-on-error, so nothing is blocked, and a re-run reproduces it identically. This PR touches no task YAMLs (hooks / tests / docs only); the smoke suites are path-skipped for this diff and passed on the pre-rebase head.

…#2785)

Extracts the envelope `model` (Claude Code sends it on SessionStart,
Codex on every hook event) and emits it as `agent_model` — the
session's main model, distinct from subagentModel (a spawned child's
family). Full sanitized slug, no family collapse: the model-comparison
views need version granularity. Claude sessions get full coverage at
query time by joining on session_id from the session-start event.

Rides the same schema v2 bump (still unmerged), avoiding a v3 right
after. Region scoping holds: a "model" key embedded in tool output
cannot false-match the envelope field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread hooks/set-session-env.sh
Comment thread hooks/send-telemetry.sh
Make the Codex event/field parity inspectable instead of implicit
(review ask on the event map):

- TELEMETRY.md: per-agent availability table — Codex fires SessionStart
  and Stop under the same names with a matching envelope (session_id /
  source / model, per the Codex hooks docs), so session-start and
  completion map unchanged; Codex has no SessionEnd (completion is its
  terminal signal) and no StopFailure (outcome is always ok); its
  turn_id / stop_hook_active / last_assistant_message extras are never
  read; duration_ms is absent (durationMs: null).
- TELEMETRY.md: state that cross-stream correlation is Claude Code-only
  — Codex has no env-file equivalent for hooks, and CODEX_THREAD_ID
  equals the payload session_id only for the root thread (verified in
  openai/codex source; subagent threads carry their own thread id), so
  native-command correlation is not available under Codex today.
- map_event_name comment: state the cross-agent contract at the map
  itself.
- pytest: Codex-shaped SessionStart (source + model → session_source +
  agent_model) and Stop (extras never forwarded, incl. the free-text
  last_assistant_message) payload guards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gpanaitescu gpanaitescu force-pushed the feature/skills_lifecycle_telemetry branch from 115068e to 4c66818 Compare July 3, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants