Skip to content

Upload Codex activity across all native hooks - #2

Open
bcdonadio wants to merge 3 commits into
mainfrom
feat/incremental-hook-uploads
Open

bcdonadio wants to merge 3 commits into
mainfrom
feat/incremental-hook-uploads

Conversation

@bcdonadio

@bcdonadio bcdonadio commented Oct 10, 2026 •

Copy link
Copy Markdown

Long-running Codex turns stay invisible when uploads run only at Stop. Large automatic exports can also fail while the uploader later records successful delivery.

This fork uploads changed observations across all 12 native hooks. Eight live activity hooks run asynchronously. Stop, SubagentStop, Interrupt, and SessionEnd flush synchronously because native Codex cancels outstanding async work during shutdown; the latter two retain the native three-second limit. Private durable inboxes, bounded kernel locks, stable observation IDs, and acknowledged checkpoints preserve retries and late child activity.

Requests contain at most 16 observations or 8 MiB of encoded JSON, with a one-second flush interval and sequential delivery. Larger individual observations remain untruncated up to 256 MiB. Semantic turn and step caches avoid reconstructing acknowledged history.

Validation

  • 155 tests passed; TypeScript, formatting, and staged secret scanning passed.
  • Live local Langfuse readback verified all 12 hook events and 19 unique observations. A tool result became visible before turn completion in approximately 1.6 seconds; a later child retained its parent's trace.
  • The 1,261-observation example took 0.63 seconds for an unchanged hook, down from 4.1 seconds before caching.
  • CI rebuilds and checks the shipped bundle against source. The only new direct dependency is the exact, Socket-reviewed OTLP serializer already present transitively in the lockfile.

Review

Start with plugins/tracing/src/index.ts, trace.ts, sidecar.ts, and instrumentation.ts, then their regressions. dist/index.mjs is generated and committed so the Git marketplace installs a standalone hook without a build step. Linux flock is required. Codex has no hook for streamed model tokens; shutdown timeouts retain pending work for retry.

Stop-only uploads hide long-running activity, and rejected automatic exports
can be mistaken for successful delivery.

Upload changed observations from all 12 hooks with durable queues, stable IDs,
small sequential batches, and bounded async execution. Preserve child parenting
and acknowledge only accepted observations. SessionEnd stays synchronous within
Codex's three-second limit; other hooks run async.

Ship the standalone fork bundle for Git marketplace installation and verify
source/bundle parity in CI. Linux flock is required. Streamed model tokens have
no Codex hook.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
@bcdonadio bcdonadio self-assigned this Oct 10, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T21:12:42.379201Z 30284e0 New commits
🔒 Security Review ✅ Completed 2026-10-10T21:13:53.222555Z 30284e0 New commits

Security findings

Advisory findings (1)

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d6b7c347f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"type": "command",
"command": "node \"${PLUGIN_ROOT}/dist/index.mjs\"",
"timeout": 30,
"async": true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make async handlers exit after durable enqueue

When Langfuse is slow or unavailable and more than eight hook events arrive, these 30-second async invocations occupy Codex's entire background-hook pool while waiting for upload/locking; later events remain only in Codex's in-memory queue and never reach enqueueHook. Codex 0.162.1 limits this pool to eight tasks and aborts all queued tasks during shutdown (command runtime, shutdown path), so a final SessionEnd cannot recover payloads whose processes never started. Have the async command persist its payload and exit promptly, with delivery performed separately, to preserve the stated durable-queue guarantee.

Useful? React with 👍 / 👎.

Comment on lines +763 to +765
const turn = hook.input.turn_id
? turns.find((t) => t.turnId === hook.input.turn_id)
: turns.filter((candidate) => candidate.startTime <= hook.timestamp).at(-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not attach SessionStart to the previous turn

On a resumed or post-compaction session, SessionStart has no turn_id in the Codex hook contract (0.162.1 schema), while the transcript already contains completed turns. This fallback therefore selects the most recent old turn, mutates the event with that turn's ID, and permanently emits the start event as a child of the wrong trace; it should remain session-level or be retained for the upcoming turn instead. The timestamp fallback is appropriate for terminal events such as SessionEnd, but not for SessionStart.

Useful? React with 👍 / 👎.

The committed standalone bundle embeds unchanged dependency code. Scan the\nTypeScript sources and tests while CI verifies byte-for-byte bundle parity.\nUse advanced CodeQL setup for this fork with the default query suite.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

🛡️ Codex Security Review · Automatically triggered

Here are some automated security review suggestions for this pull request.

Reviewed commit: f1acda1a3a

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

]
}
],
"SessionStart": [

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛡️ Codex Security Review · Automatically triggered

P1 Badge Security: Reject project endpoints that inherit global credentials

When the plugin is globally enabled/trusted with credentials, starting Codex in an untrusted checkout whose .codex/langfuse.json overrides only base_url runs this new hook. getConfig() inherits public_key/secret_key from ~/.codex but accepts the checkout's endpoint, and the standalone path immediately sends those inherited values in Basic auth. I reproduced credential capture without a transcript. Previously only Stop was registered, so this makes starting the session sufficient rather than requiring a completed turn. Bind the endpoint and credentials to the same trusted source or reject mixed-provenance config.

Useful? React with 👍 / 👎.

Native Codex cancels async hooks before SessionEnd. A real CLI probe
confirmed that an async Stop could disappear before enqueueing its payload.

Keep activity hooks async, but flush Stop, SubagentStop, Interrupt, and
SessionEnd synchronously. The hook deadlines and durable retries remain
bounded. Increment the fork prerelease for cache and hook review identity.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30284e0279

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +159 to +161
const instrumentation = setupInstrumentation(config, {
acknowledged: await loadObservationCheckpoint(file),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Namespace delivery checkpoints by Langfuse destination

When base_url, public_key, or secret_key is changed for an existing session, this reloads acknowledgements created for the previous destination. The stored fingerprints cover only serialized span contents, while the destination and credentials exist only in the HTTP URL/headers, so unchanged observations are skipped against the new backend; newly uploaded hook spans can consequently reference parent observations that exist only in the old Langfuse project. Include a destination identity in the checkpoint or discard acknowledgements when it changes.

Useful? React with 👍 / 👎.

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.

1 participant