Repository: block/goose
File: crates/goose/src/providers/codex.rs (Rust)

Code before:

            for content in &message.content {
                if let MessageContent::Text(text_content) = content {
                    full_prompt.push_str(&text_content.text);
                    full_prompt.push('\n');
                }
            }
            full_prompt.push('\n');
        }

        full_prompt.push_str("Assistant: ");
        full_prompt
    }

    /// Apply permission flags based on GOOSE_MODE setting
    fn apply_permission_flags(cmd: &mut Command) -> Result<(), ProviderError> {
        let config = Config::global();
        let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);

        match goose_mode {
            GooseMode::Auto => {
                // --yolo is shorthand for --dangerously-bypass-approvals-and-sandbox
                cmd.arg("--yolo");
            }
            GooseMode::SmartApprove => {
                // --full-auto applies workspace-write sandbox and approvals only on failure
                cmd.arg("--full-auto");
            }
            GooseMode::Approve => {
                // Default codex behavior - interactive approvals
                // No special flags needed
            }
            GooseMode::Chat => {
                // Read-only sandbox mode
                cmd.arg("--sandbox").arg("read-only");
            }
        }
        Ok(())
    }

    /// Execute codex CLI command
    async fn execute_command(
        &self,
        system: &str,
        messages: &[Message],
        _tools: &[Tool],
    ) -> Result<Vec<String>, ProviderError> {
        let prompt = self.messages_to_prompt(system, messages);

        if std::env::var("GOOSE_CODEX_DEBUG").is_ok() {
            println!("=== CODEX PROVIDER DEBUG ===");

Review comment (bug):
nit: ignoring the possible error here means that we'll fail later, inside prepare_input, when we try to create the temp file, which could be more confusing than if we failed here.

Code after:
            GooseMode::SmartApprove => {
                // --full-auto applies workspace-write sandbox and approvals only on failure
                cmd.arg("--full-auto");
            }
            GooseMode::Approve => {
                // Default codex behavior - interactive approvals
                // No special flags needed
            }
            GooseMode::Chat => {
                // Read-only sandbox mode
                cmd.arg("--sandbox").arg("read-only");
            }
        }
        Ok(())
    }

    /// Execute codex CLI command
    async fn execute_command(
        &self,
        system: &str,
        messages: &[Message],
        _tools: &[Tool],
    ) -> Result<Vec<String>, ProviderError> {
        // Single pass: text → prompt (stdin), images → temp files (-i flags)
        let image_dir = Paths::state_dir().join("codex/images");
        std::fs::create_dir_all(&image_dir).ok();
        let (prompt, temp_files) = prepare_input(system, messages, &image_dir)?;

        if std::env::var("GOOSE_CODEX_DEBUG").is_ok() {
            println!("=== CODEX PROVIDER DEBUG ===");
            println!("Command: {:?}", self.command);
            println!("Model: {}", self.model.model_name);
            println!("Reasoning effort: {}", self.reasoning_effort);
            println!("Skip git check: {}", self.skip_git_check);
            println!("Prompt length: {} chars", prompt.len());
            println!("Prompt: {}", prompt);
            println!("Image files: {}", temp_files.len());
            println!("============================");
        }

        let mut cmd = Command::new(&self.command);
        configure_command_no_window(&mut cmd);

        // Use 'exec' subcommand for non-interactive mode
        cmd.arg("exec");

        // Only pass model parameter if it's in the known models list
        // This allows users to set GOOSE_PROVIDER=codex without needing to specify a model
        if CODEX_KNOWN_MODELS.contains(&self.model.model_name.as_str()) {
            cmd.arg("-m").arg(&self.model.model_name);
        }