Skip to content

Conversation

abhishek-oai
Copy link
Contributor

@abhishek-oai abhishek-oai commented Aug 19, 2025

  • protocol: add Op::RunUserShellCommand to model a user-initiated one-off command

  • core: handle new Op by spawning a cancellable task that runs the command using the user’s default shell; stream output via ExecCommand* events; send TaskStarted/TaskComplete; track as current_task so Interrupt works

  • tui: detect leading '!' in composer submission and dispatch Op::RunUserShellCommand instead of sending a user message

  • No changes to sandbox env var behavior; uses existing exec pipeline and event types.

  • Handles Ctrl-C to send SIGINT to the user command

  • Handles limiting output from a user command to not overflow the tui

Demo video

bang-command-demo-video-1080p.mp4

Copy link

github-actions bot commented Aug 19, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@abhishek-oai abhishek-oai requested a review from gpeal August 19, 2025 21:51
Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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 suggestions.

Reply with @codex fix comments to fix any unresolved comments.

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 that is ready for review, or mark a draft as ready for review. You can also ask for a review by commenting "@codex review".

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

@easong-openai
Copy link
Collaborator

We need to make sure cancellation works, particularly ctr-c. Right now it doesn't actually cancel the command.

If possible, we should show the command we just ran + any output and delineate it as a user command instead of using the shortening UI we do for the model.

Otherwise nice work!

@easong-openai
Copy link
Collaborator

This also doesn't support windows, which isn't necessarily a blocker but we might need to look at.

@abhishek-oai
Copy link
Contributor Author

We need to make sure cancellation works, particularly ctr-c. Right now it doesn't actually cancel the command.

If possible, we should show the command we just ran + any output and delineate it as a user command instead of using the shortening UI we do for the model.

Otherwise nice work!

Happy to send a patch with both! Wanted to get something out to get buy-in first. Thanks for the prompt feedback.

@SebastianSzturo
Copy link

This is great! Would be also fantastic to have a way to run background commands like with Claude Code and have the output continuously attached to any new messages.

Background commands: (Ctrl-b) to run any Bash command in the background so Claude can keep working (great for dev servers, tailing logs, etc.)

Here is also a good description of the feature: sst/opencode#1970

@abhishek-oai abhishek-oai changed the title TUI: ! commands passthrough to shell for execution [tui][core] ! commands passthrough to shell for execution Aug 24, 2025
@abhishek-oai
Copy link
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Aug 24, 2025
@abhishek-oai
Copy link
Contributor Author

We need to make sure cancellation works, particularly ctr-c. Right now it doesn't actually cancel the command.

If possible, we should show the command we just ran + any output and delineate it as a user command instead of using the shortening UI we do for the model.

Otherwise nice work!

Alright both those things should work.

Also, the Tui still remains like the "frontend" and forwards the request to the "core". This is in line with the existing archiecture.

Copy link

Summary

  • Adds local “!” command execution with session events, env isolation, and TUI/CLI display. Updates docs and config to describe usage and line-capping.

Notes

  • codex-rs/README.md: New “Run a local command with !” section and usage tips.
  • codex-rs/config.md: Documents [tui] local_shell_max_lines (example 150; default described as 100).
  • codex-rs/core: Implements local exec runtime, process-group SIGINT on Unix, env derivation via policy, and LocalCommandBegin/End events.
  • codex-rs/tui: Wires local command begin/end into chat history; updates fixture.
  • codex-rs/exec,mcp-server: Handles/ignores new local-command events appropriately.

Review
Overall looks solid: process-group signaling, env hygiene, and event plumbing are well-done. A few small inconsistencies to address:

  • README link: “See config.md#tui.local_shell_max_lines” should point to config.md#tui (no anchor for the key).
  • Apply the documented line cap: local_shell_max_lines (core/src/config_types.rs, config.md) isn’t used; tui/src/history_cell.rs::new_local_command_output currently prints all lines. Consider using existing output_lines(...) with a default of 100 (configurable via Config.tui.local_shell_max_lines) and showing the “… +N lines” summary.
  • Non-Unix interrupt: core/src/local_exec.rs sets a flag but doesn’t actually signal/terminate the process. If acceptable for now, note the limitation; otherwise consider a Windows-friendly cancellation approach.

Follow-up (outside this PR scope)

  • Optionally align the CLI’s MAX_OUTPUT_LINES_FOR_EXEC_TOOL_CALL with the TUI default or make it configurable for consistency.

View workflow run

@tibo-openai
Copy link
Collaborator

@codex review in depth

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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 suggestions.

Reply with @codex fix comments to fix any unresolved comments.

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, or 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 fix this CI failure" or "@codex address that feedback".

@easong-openai
Copy link
Collaborator

Seems worth addressing the codex review notes above ^

@abhishek-oai abhishek-oai enabled auto-merge (squash) August 25, 2025 23:19
@abhishek-oai
Copy link
Contributor Author

Seems worth addressing the codex review notes above ^

Fixed.

@abhishek-oai
Copy link
Contributor Author

@codex review in depth

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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 suggestions.

Reply with @codex fix comments to fix any unresolved comments.

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, or 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 fix this CI failure" or "@codex address that feedback".

@abhishek-oai abhishek-oai force-pushed the bang-command-support branch 2 times, most recently from 771ae55 to 8aaf9f0 Compare August 26, 2025 02:58
@abhishek-oai
Copy link
Contributor Author

Seems worth addressing the codex review notes above ^

All fixed!

@takatoshi-maeda
Copy link

Does this pull request have a planned release schedule?

When I was using a different coding agent, I was able to provide the necessary context with the ! command—for example, executing database queries or checking schemas. Supplying context through the ! command also helped the coding agent experiment autonomously.

With Codex, I’ve been following this workflow by copying and pasting from the shell, which requires some additional steps. For that reason, I’m very much looking forward to the release of this feature.

@bolinfest
Copy link
Collaborator

As discussed offline, I think this needs a new approach that uses more of the existing exec functionality.

@bolinfest bolinfest removed their request for review September 10, 2025 17:41
@abhishek-oai abhishek-oai changed the title [tui][core] ! commands passthrough to shell for execution feature: Add "!cmd" user shell execution Sep 14, 2025
@abhishek-oai
Copy link
Contributor Author

@bolinfest Updated the implementation to align with our discussion offline

Copy link
Collaborator

@bolinfest bolinfest left a comment

Choose a reason for hiding this comment

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

Can you please add a video to the PR body?

@abhishek-oai
Copy link
Contributor Author

Does this pull request have a planned release schedule?

When I was using a different coding agent, I was able to provide the necessary context with the ! command—for example, executing database queries or checking schemas. Supplying context through the ! command also helped the coding agent experiment autonomously.

With Codex, I’ve been following this workflow by copying and pasting from the shell, which requires some additional steps. For that reason, I’m very much looking forward to the release of this feature.

Actively working to land this.

@takatoshi-maeda
Copy link

Thank you, I really appreciate it. I’m looking forward to trying it out.

Copy link
Contributor Author

@abhishek-oai abhishek-oai left a comment

Choose a reason for hiding this comment

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

Addressed all comments

@abhishek-oai
Copy link
Contributor Author

Fix for CI failure (seems like a flake) - #3844

@abhishek-oai
Copy link
Contributor Author

Can you please add a video to the PR body?

Also done

Copy link
Collaborator

@bolinfest bolinfest left a comment

Choose a reason for hiding this comment

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

This is generally good, but there are some things I'd like you to look at!

assert_eq!(deserialized, event);
}

#[test]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can do without this test: it doesn't provide much in the way of additional code correctness.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

/// True when this exec was initiated directly by the user (e.g. bang command),
/// not by the agent/model. Defaults to false for backwards compatibility.
#[serde(default)]
pub user_initiated_shell_command: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about: is_user_shell_command to mirror the name of the Op?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

struct RunningCommand {
command: Vec<String>,
parsed_cmd: Vec<ParsedCommand>,
user_initiated_shell_command: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename this as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

// Special-case: "!cmd" executes a local shell command instead of sending to the model.
if let Some(stripped) = text.strip_prefix('!') {
let cmd = stripped.trim().to_string();
if !cmd.is_empty() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

So if the user types ! by itself, we'll send the message "!" to the agent, correct?

I guess this is fine, though we could take this opportunity to tell the user about the ! feature instead?

body_lines.extend(wrapped.into_iter().map(|l| Line::from(l.to_string().dim())));

if let Some(output) = call.output.as_ref() {
let is_shell_exec_cell = self.calls.iter().any(|c| c.user_initiated_shell_command);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we believe we could have a mix of exec calls in flight, only some of which are user initiated shell commands?

sub_id: String,
command: String,
) {
let spawn_sub_id = sub_id.clone();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do this inside let handle, as well?

Comment on lines 16 to 18
unsafe {
std::env::set_var("CODEX_HERMETIC_TEST_SHELL", "1");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please find another way to do this: this is unsafe for a reason.

use std::path::PathBuf;
use tempfile::TempDir;

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please omit worker_threads unless you have a reason to believe you need them.

Empirically, tests that only pass with more than one worker thread imply bugs in our code, so I would prefer to try to catch them.

@@ -0,0 +1,119 @@
#![cfg(unix)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given these tests are limited to unix for now (which I would prefer not to do), do we really need CODEX_HERMETIC_TEST_SHELL?

// 1) ls should list the file
codex
.submit(Op::RunUserShellCommand {
command: "ls".to_string(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I often use python3 -c as an example for cross-platform shell calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@rtl-ai
Copy link

rtl-ai commented Oct 7, 2025

Any update on the merge timeline for this PR?

- protocol: add Op::RunUserShellCommand to model a user-initiated one-off command
- core: handle new Op by spawning a cancellable task that runs the command using the user’s default shell; stream output via ExecCommand* events; send TaskStarted/TaskComplete; track as current_task so Interrupt works
- tui: detect leading '!' in composer submission and dispatch Op::RunUserShellCommand instead of sending a user message

No changes to sandbox env var behavior; uses existing exec pipeline and event types.
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.

7 participants