You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support injecting command output from background completion into the active Codex session #22003
Support a command-response injection path for background completions so an external watcher or orchestrator can deliver the completed command's output directly into the active Codex session as the next user turn, without requiring tmux send-keys or explicit polling. The intended workflow is:
a background process watches an inbox file or similar event source
when new output arrives, the watcher exits or emits a completion event
Codex receives that output as input automatically in the active conversation context
the session can then act on the injected content and continue the loop
This would make file-based or socket-based orchestration possible for agents that should wake Codex on process completion.
Additional information
I tested a file-watcher prototype where a background process writes JSONL output after new content arrives. In the current harness, the session does not wake up on its own when the watcher exits; output only appears after an explicit poll. A command-response injection mechanism would remove the need for tmux-driven key injection and make event-driven orchestration much cleaner.
Additional environment details from the repro run:
Platform: Darwin 25.4.0 (arm64)
The key behavior observed was that a background watcher could complete, but the active Codex session did not receive a spontaneous wake-up or injected turn; I had to explicitly poll the running session to observe the output.
I ran into the same need while testing file/channel-watch workflows where a background command blocks on an event source and should wake Codex when it emits output.
I put together a discussion branch with one concrete implementation sketch:
I ran into this same gap and ended up building the tool-shaped version of it, so sharing here since this looks like where it's converging.
Instead of a flag on exec_command (#29865) or a generic injection path, I added an agent-callable monitor tool: the model runs a shell command as a background watcher with action=start/stop/list, and each line it prints (stdout or stderr) wakes the idle session and starts a turn. While the watch is quiet the session makes no API calls. It is the same core seam everyone in this thread is describing: background output delivered as a bounded, untrusted synthetic user message through the session's existing idle-start path, only when the session can take it. No protocol change, and the watcher is just a normal sandboxed unified_exec process, so it inherits the existing approval/sandbox/shell handling.
The difference from the flag form is that it is a tool the model reaches for and drops mid-task (named, ephemeral watches it manages via a small per-session registry), rather than a property of one exec call.
I have a working reference and I have been running it live in my own Codex, both the CLI and the Desktop app. It is feature-gated, off by default. Full diff, one commit on the v0.142.0 tag: rust-v0.142.0...yaanfpv:codex:monitor-tool. It carries tests (eight integration plus two unit, clean under fmt and clippy) and a few output-safety bounds (line and byte flood guards, and no silently dropped notifications).
I wrote the full design up as #29922. Happy to fold it in here if this is the better home, and glad to open a PR if the approach is useful.
The branch intentionally contains only the core Rust change; the local VS Code/debug launcher used during development is excluded.
It has two focused commits:
The existing implementation from cf7e731ed804d0e9a13393d55c4ced0bcb032e69, conflict-resolved against current main while preserving its authorship.
A follow-up correctness fix that waits for the unified-exec output pump to drain before constructing the synthetic wake message. This preserves output emitted immediately around process exit and retains a bounded grace-period fallback when the output channel does not close. Regression tests cover both the normal drain path and fallback path, plus late network-denial classification.
Validation on macOS arm64:
just fmt — pass
just fix -p codex-core — pass
just test -p codex-core wake_on_output — pass
just test -p codex-core background_output_wake — pass
just test -p codex-core streaming_output — pass
just test -p codex-core unified_exec::async_watcher::tests — pass
just test -p codex-core tools::handlers::unified_exec::tests — pass
just test -p codex-core shell_spec — pass
git diff --check origin/main...HEAD — pass
I have not opened a pull request because docs/contributing.md currently requires an explicit maintainer invitation for external PRs. If this approach matches the intended direction, I would be happy to open the prepared branch as an invited PR and make any requested architectural adjustments.
The distinction between @fl4p's wake_on_output branch, @yaanfpv's line-oriented monitor, and @bbmumford's output-drain fix matters here: a notification that the command ended is not the same feature as injecting every meaningful output update. I have a working external option for the narrower completion case, and want to keep that scope explicit rather than present it as a replacement for those patches.
In my cc-arch-hands package, cli-run is an opt-in stdio MCP integration. The model submits a named run of non-interactive commands; a detached Node worker captures output to logs and persists exit results. With queue delivery, once all commands in the run finish, it invokes codex queue for the calling thread with the task name, UID, and a brief success/failure count. The model can finish its originating turn and later inspect the saved logs after notification, without repeatedly polling a terminal session.
For a watcher that emits its selected result and then exits, that supplies an interim handoff: watcher exits -> completion message -> inspect the result -> decide the next action. For a watcher that stays alive while emitting a sequence of messages, it does not supply the streaming wake-on-output behavior proposed in this thread. The queued message deliberately contains no command output, and logs retrieves bounded saved tails on demand; it does not continuously push JSONL or stdout into the model's context.
The installation path is:
npx cc-arch-hands@0.15.1 install --codex-skills
It registers the local MCP server, installs the optional Codex skill bundle and marked usage instructions, and needs a Codex restart. No upstream binary patch is involved. Coverage and operational limits are documented here.
Queue delivery still depends on access to an available destination thread. Failures are recorded alongside results, not treated as a successful wake. MCP approval also remains necessary: this detached runner operates outside Codex's per-turn filesystem sandbox and is not equivalent to the sandboxed native monitor described above. Users must make that trust decision explicitly.
So this is a temporary completion-only workaround that can be used now, not an implementation of the full output-injection request. A native, bounded, untrusted-output delivery path that drains output before publishing completion would remain a stronger and better-integrated solution.
Activity
harshitsinghbhandari commentedon May 10, 2026
Additional environment details from the repro run:
The key behavior observed was that a background watcher could complete, but the active Codex session did not receive a spontaneous wake-up or injected turn; I had to explicitly poll the running session to observe the output.
github-actions commentedon May 10, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
harshitsinghbhandari commentedon May 10, 2026
Not a Duplicate.
harshitsinghbhandari commentedon May 10, 2026
@etraut-openai Will this be worked on?
fl4p commentedon Jun 24, 2026
I ran into the same need while testing file/channel-watch workflows where a background command blocks on an event source and should wake Codex when it emits output.
I put together a discussion branch with one concrete implementation sketch:
https://github.com/fl4p/codex/tree/feat/wake-on-background-output
High-level behavior in the branch:
wake_on_outputboolean to unifiedexec_command.exec_commandtool call has yielded is batched and delivered as a bounded synthetic user message.Local validation on that branch:
just fmtpassedjust fix -p codex-corepassedjust test -p codex-core wake_on_outputpassedjust test -p codex-core background_output_wakepassedjust test -p codex-core shell_specpassedI also opened #29865 before finding this issue; I’m closing that one as a duplicate and leaving the patch link/details here instead.
docs: note background-injection support gap for Codex/OpenCode
yaanfpv commentedon Jun 24, 2026
I ran into this same gap and ended up building the tool-shaped version of it, so sharing here since this looks like where it's converging.
Instead of a flag on
exec_command(#29865) or a generic injection path, I added an agent-callablemonitortool: the model runs a shell command as a background watcher withaction=start/stop/list, and each line it prints (stdout or stderr) wakes the idle session and starts a turn. While the watch is quiet the session makes no API calls. It is the same core seam everyone in this thread is describing: background output delivered as a bounded, untrusted synthetic user message through the session's existing idle-start path, only when the session can take it. No protocol change, and the watcher is just a normal sandboxedunified_execprocess, so it inherits the existing approval/sandbox/shell handling.The difference from the flag form is that it is a tool the model reaches for and drops mid-task (named, ephemeral watches it manages via a small per-session registry), rather than a property of one exec call.
I have a working reference and I have been running it live in my own Codex, both the CLI and the Desktop app. It is feature-gated, off by default. Full diff, one commit on the v0.142.0 tag: rust-v0.142.0...yaanfpv:codex:monitor-tool. It carries tests (eight integration plus two unit, clean under fmt and clippy) and a few output-safety bounds (line and byte flood guards, and no silently dropped notifications).
I wrote the full design up as #29922. Happy to fold it in here if this is the better home, and glad to open a PR if the approach is useful.
ilyes-i-ben commentedon Jul 2, 2026
+1
bbmumford commentedon Jul 26, 2026
I rebased the existing wake-on-output implementation onto the current
openai/codexmain(20dafe201) and published a clean discussion branch here:main...bbmumford:codex:feat/wake-on-background-output
The branch intentionally contains only the core Rust change; the local VS Code/debug launcher used during development is excluded.
It has two focused commits:
cf7e731ed804d0e9a13393d55c4ced0bcb032e69, conflict-resolved against currentmainwhile preserving its authorship.Validation on macOS arm64:
just fmt— passjust fix -p codex-core— passjust test -p codex-core wake_on_output— passjust test -p codex-core background_output_wake— passjust test -p codex-core streaming_output— passjust test -p codex-core unified_exec::async_watcher::tests— passjust test -p codex-core tools::handlers::unified_exec::tests— passjust test -p codex-core shell_spec— passgit diff --check origin/main...HEAD— passI have not opened a pull request because
docs/contributing.mdcurrently requires an explicit maintainer invitation for external PRs. If this approach matches the intended direction, I would be happy to open the prepared branch as an invited PR and make any requested architectural adjustments.docs: explain temporary cli-run workaround (openai/codex#42908, opena…
PHPCraftdream commentedon Oct 1, 2026
The distinction between @fl4p's
wake_on_outputbranch, @yaanfpv's line-oriented monitor, and @bbmumford's output-drain fix matters here: a notification that the command ended is not the same feature as injecting every meaningful output update. I have a working external option for the narrower completion case, and want to keep that scope explicit rather than present it as a replacement for those patches.In my cc-arch-hands package,
cli-runis an opt-in stdio MCP integration. The model submits a named run of non-interactive commands; a detached Node worker captures output to logs and persists exit results. With queue delivery, once all commands in the run finish, it invokescodex queuefor the calling thread with the task name, UID, and a brief success/failure count. The model can finish its originating turn and later inspect the saved logs after notification, without repeatedly polling a terminal session.For a watcher that emits its selected result and then exits, that supplies an interim handoff: watcher exits -> completion message -> inspect the result -> decide the next action. For a watcher that stays alive while emitting a sequence of messages, it does not supply the streaming wake-on-output behavior proposed in this thread. The queued message deliberately contains no command output, and
logsretrieves bounded saved tails on demand; it does not continuously push JSONL or stdout into the model's context.The installation path is:
It registers the local MCP server, installs the optional Codex skill bundle and marked usage instructions, and needs a Codex restart. No upstream binary patch is involved. Coverage and operational limits are documented here.
Queue delivery still depends on access to an available destination thread. Failures are recorded alongside results, not treated as a successful wake. MCP approval also remains necessary: this detached runner operates outside Codex's per-turn filesystem sandbox and is not equivalent to the sandboxed native monitor described above. Users must make that trust decision explicitly.
So this is a temporary completion-only workaround that can be used now, not an implementation of the full output-injection request. A native, bounded, untrusted-output delivery path that drains output before publishing completion would remain a stronger and better-integrated solution.