Skip to content

feat(webhook): let a codex session RECEIVE deliveries, not just subscribe - #489

Open
defangdevs wants to merge 2 commits into
masterfrom
feat/codex-webhook-delivery
Open

feat(webhook): let a codex session RECEIVE deliveries, not just subscribe#489
defangdevs wants to merge 2 commits into
masterfrom
feat/codex-webhook-delivery

Conversation

@defangdevs

Copy link
Copy Markdown
Owner

Problem

A codex session on this box could manage subscriptions — that is what
agent-box-webhook is for — but nothing could deliver into one. Its agent
polled, or learned late: the exact cost the webhook wiring exists to remove.

The missing piece was never in the box. codex cannot host a channel plugin (no
channel notification to receive), and it spawns its MCP servers with a scrubbed
environment, so nothing on that side could even learn which thread it belongs to.

What changed

local-webhook 0.26.0 (defangdevs/local-channels#52) closes it from the other
end: subscribe run inside a codex session starts a small detached peer for
that session's own thread, and each delivery is handed over with
codex queue --thread <id> --message <text>, landing as a message at that
session's next turn boundary. The thread id comes from CODEX_THREAD_ID, which
codex exports into its shell tool's environment — where the agent's own CLI call
runs.

Everything before that last inch is the code the claude path already uses,
peer socket included, so a codex session's --claim suppresses a standing-watch
spawn exactly like a claude session's does.

So this PR is only:

  • nix/webhook-pin.nix → 0.26.0 (789b374), plus a webhook.rev
    description paragraph. That description had been left at 0.23.0 while the pin
    moved on, so it now also records 0.24.0's foreign-sender shape and 0.25.0's
    per-watch spawnConfig.
  • modules/src/default-agents-webhook.md → the shipped guide tells a codex
    session that subscribing also wires delivery, and names the one sharp edge: a
    subscription seeded from outside the session (a spawn wrapper, a script)
    writes the claim but delivers nothing until the session subscribes once itself.
  • the regenerated modules/agent-box.nix and the golden fixture.

Nothing else is needed: the peer is started by the session's own CLI call,
resolves codex from that session's PATH, and stops itself when the last
subscription goes. agent-box-webhook status already passes local-webhook's
JSON through, so the new codexThread / codexPeer fields show up there.

User-visible and security effects

A codex session now gets webhook deliveries as ordinary queued messages, carrying
the same [UNTRUSTED webhook:<source>] … ⟪UNTRUSTED:…⟫ framing a claude session
sees; the delivery text is passed as one argv element with no shell involved. No
new listener, no new endpoint, no new sudo grant, no AWS/IAM/networking change.
A claude session is unaffected (asserted upstream).

Checks run (aarch64-linux)

check result
module-generated-up-to-date pass
golden-snapshot pass
one-spec-both-backends pass
multi-user pass
module-single-file pass
scripts/check_backend_parity.py OK
scripts/check_one_spec.py PARTIAL (its Nix half is the flake check above)

The golden diff is the guide paragraph and nothing else.

Upstream verification for the mechanism itself (real codex session, real signed
delivery, 177 tests) is in defangdevs/local-channels#52.

…ribe

A codex session on this box could manage subscriptions (that is what
`agent-box-webhook` is for) but nothing could deliver into one, so its agent
polled or learned late — the cost the webhook wiring exists to remove. The
missing piece was never in the box: codex cannot host a channel plugin, and its
MCP servers are spawned with a scrubbed environment, so nothing on that side
could even learn which thread it belongs to.

local-webhook 0.26.0 (defangdevs/local-channels#52) closes it from the other
end. `subscribe` run INSIDE a codex session starts a small detached peer for
that session's own thread — codex exports CODEX_THREAD_ID into its shell tool's
environment, which is where the agent's own CLI call runs — and each delivery is
handed over with `codex queue`, landing as a message at that session's next turn
boundary. Everything before that last inch is the code the claude path already
uses, including the peer socket, so a codex session's `--claim` suppresses a
standing-watch spawn exactly like a claude session's does.

This change is the pin bump plus the guide line, because the box needs nothing
else: the peer is started by the session's own CLI call, resolves `codex` from
that session's PATH, and stops itself when the last subscription goes. The
`webhook.rev` option description records what came with the two intermediate
versions (0.24.0's foreign-sender shape, 0.25.0's per-watch spawnConfig), since
the pin had been bumped past 0.23.0 without it.

The shipped guide's webhook section now tells a codex session that subscribing
also wires delivery, and — the one sharp edge — that a subscription seeded from
OUTSIDE the session (a spawn wrapper, a script) writes the claim but delivers
nothing until the session subscribes once itself.

Checks run (aarch64-linux): module-generated-up-to-date, golden-snapshot,
one-spec-both-backends, multi-user, module-single-file — all pass;
check_backend_parity.py OK, check_one_spec.py PARTIAL (its Nix half is the
flake check above). The golden diff is the guide paragraph and nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBDHCBttvBEHQJJH24MfxF
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 8 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: ef104770-a0d0-4ddf-9f7c-94550801bd9e

📥 Commits

Reviewing files that changed from the base of the PR and between ca23acd and 2988467.

📒 Files selected for processing (2)
  • tests/native/expected/etc/agent-box-guides/AGENTS.agent.md
  • tests/native/expected/etc/agent-box-guides/AGENTS.robot.md

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 2cf182eb-7fe6-4c0e-874e-285146430ed5

📥 Commits

Reviewing files that changed from the base of the PR and between 6c6462d and ca23acd.

📒 Files selected for processing (5)
  • modules/agent-box.nix
  • modules/agent-box.nix.in
  • modules/src/default-agents-webhook.md
  • nix/webhook-pin.nix
  • tests/golden/web/etc/agent-box-guides/AGENTS.agent.md

Included review availability: Your plan provides up to 8 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change updates pinned webhook sources and documents local-webhook version history and Codex session delivery. The documentation covers subscriptions, delivery peers, queued events, peer lifecycle, external subscriptions, inherited subscriptions, and status diagnostics.

Changes

Webhook updates

Layer / File(s) Summary
Update pinned webhook sources
modules/agent-box.nix, nix/webhook-pin.nix
The pinned local-webhook and local-channels revisions and hashes are updated.
Document Codex webhook delivery
modules/agent-box.nix, modules/agent-box.nix.in, modules/src/default-agents-webhook.md, tests/golden/web/etc/agent-box-guides/AGENTS.agent.md
The documentation describes in-session subscriptions, per-thread delivery peers, queued events, peer lifecycle, external and inherited subscriptions, codex queue, PATH resolution, and status diagnostics.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to ca23a

This localized change enables webhook delivery for codex sessions and updates the shipped documentation and generated artifacts; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: lionello, claude

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: enabling Codex sessions to receive webhook deliveries.
Description check ✅ Passed The description directly explains the Codex delivery problem, the local-webhook 0.26.0 update, documentation changes, security effects, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (5 skipped: 5 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/codex-webhook-delivery

Comment @coderabbitai help to get the list of available commands.

The shipped guide is embedded by BOTH renderers, and only the web golden had
been updated: the native fixture check (tests/test_agentbox.py, run by CI as
agentbox-render-ok) failed on etc/agent-box-guides/AGENTS.agent.md. Regenerated
with `python3 tests/test_agentbox.py --update`; the diff is the same codex
paragraph in AGENTS.agent.md and AGENTS.robot.md and nothing else.

Local: tests/test_agentbox.py 77 tests OK (1 skipped); one-spec-both-backends
and golden-snapshot pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBDHCBttvBEHQJJH24MfxF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant