Subagents do not inherit Responses API client metadata from parent turns

Open 💬 1 comment Opened Aug 10, 2026 by hancao97

What issue are you seeing?

When an app-server client supplies responsesapiClientMetadata on turn/start, the custom metadata is included in the parent turn's Responses API request, but it is dropped when Codex starts or continues a subagent.

This affects both multi-agent paths:

  • V1 spawn/follow-up submissions do not carry the parent turn's client metadata.
  • V2 mailbox submissions carry parent-turn identity, but have no channel for client metadata.
  • Delegate/review/Guardian child-entry paths have the same gap.

As a result, downstream proxies and telemetry can attribute the root request to the originating client, but nested Responses API requests lose that attribution. Active child follow-ups can also retain stale attribution instead of following the triggering parent turn.

The reserved thread_id and turn_id fields should remain child-owned; the bug concerns inheriting the caller's custom metadata fields.

What steps can reproduce the bug?

  1. Start a Codex thread through app-server.
  2. Call turn/start with non-empty responsesapiClientMetadata, for example:
{
  "client_trace_id": "parent-turn-a",
  "thread_id": "spoofed-thread-id",
  "turn_id": "spoofed-turn-id"
}
  1. Have the parent invoke spawn_agent.
  2. Inspect the parent and child outbound /responses requests, particularly the x-codex-turn-metadata header.
  3. Repeat with Multi-Agent V1 and V2.
  4. For V2, send a follow-up while the child is active using a new value such as parent-turn-b, then inspect the child's next Responses request.

Actual behavior:

  • The parent request contains client_trace_id.
  • The child spawn/follow-up request does not inherit it, or an active child continues with stale metadata.
  • The missing propagation is independent of the child-owned reserved IDs.

What is the expected behavior?

  • A child spawn should inherit the triggering parent turn's custom Responses API client metadata.
  • Active child follow-ups should use the metadata associated with the input batch that triggers the sample.
  • thread_id and turn_id must always be generated from the child thread/turn and must not be inherited or spoofable.
  • V2 mailbox aggregation should treat parent-turn ID and client metadata independently:
  • inherit each unambiguous value;
  • clear stale custom metadata when the contributing inputs disagree or do not provide a single value;
  • let explicit steer metadata win for the batch it accompanies.

Root cause

The metadata currently stops at the parent turn's TurnMetadataState:

  • the V1 spawn path submits child input without the parent metadata;
  • the V2 mailbox models parent-turn ID only;
  • child submission/delegate/review entry points have no shared parent-turn context carrying both values.

This is why merely preserving parent_turn_id does not fix client attribution.

Proposed fix

I prepared a focused implementation that introduces a parent-turn context containing both the optional parent turn ID and filtered custom client metadata, then propagates it through:

  • V1 and V2 spawn/follow-up paths;
  • the V2 mailbox and active-turn update path;
  • delegate, review, and Guardian child entry points;
  • internal Submission plumbing.

It also:

  • filters reserved thread_id / turn_id fields;
  • clears both provenance fields at the public submit_with_id boundary to prevent spoofing;
  • stores explicit steer metadata with its pending input batch so it is applied only when that batch is drained;
  • handles conflicting V2 mailbox contributors without retaining stale attribution.

Prepared implementation:

Validation completed

  • Responses API integration coverage for V1 and V2 subagent spawn.
  • Active V2 follow-up coverage with changed client metadata.
  • Queue aggregation, conflict-clearing, and explicit-steer precedence tests.
  • Public-submit anti-spoof and delegate propagation coverage.
  • cargo check -p codex-core --tests --offline.
  • Focused codex-core tests.
  • just test -p codex-protocol -p codex-mcp-server.
  • just fix -p codex-core -p codex-protocol -p codex-mcp-server.
  • just fmt and cargo fmt --all -- --check.

I did not find an existing issue covering this exact metadata-propagation gap. If this approach aligns with the intended semantics, I would be happy to open the prepared PR with an invitation, per the repository's external contribution policy.

View original on GitHub ↗

1 Comment

hancao97 · 15 days ago

A brief follow-up after checking the changes merged since this report:

PR #37895 added responses_api_metadata, and its configured product metadata is correctly present on both parent and subagent Responses requests. That is useful, but it does not cover this issue: responses_api_metadata is static configuration, whereas turn/start.responsesapiClientMetadata is dynamic app-server metadata that can differ per session/turn.

The remaining affected use case is therefore:

  • session/turn A supplies client metadata A;
  • session/turn B supplies client metadata B;
  • each descendant subagent should inherit the metadata of the parent turn that triggered it;
  • reserved Codex-owned fields must remain child-owned.

I rechecked current main; I do not see a parent-turn channel for carrying responsesapiClientMetadata through subagent submissions/mailboxes, nor an associated PR for #37760.

Could a maintainer confirm whether this dynamic metadata is expected to propagate to subagents? If the proposed semantics in the issue align with the intended design, I can rebase the prepared implementation onto current main and open the PR immediately once invited under the external contribution policy:

If a smaller first step is preferred, I can also split initial spawn inheritance from active-follow-up/mailbox semantics.