Welcome back to Mastering Advanced AI Tooling in Codex! In previous lessons, we configured Codex through config.toml, enabled secure web search, and built custom commands (both simple and argument-based) that encode project-specific workflows.
Today, we are learning about inline shell capture: the ability to run local shell commands directly from the Codex CLI using the ! prefix. When we execute these commands, Codex captures their output and injects it into our conversation history as context. This transforms our interactions from static questions into dynamic ones that reflect the current state of our repository. We will build a practical workflow that gathers repository status, recent commits, and current changes, then asks Codex to propose next steps based on real-time information.
Before diving into syntax, let us understand what inline shell capture solves. When we ask Codex to help with our codebase, it needs context: which files changed, which commits occurred recently, and what is currently staged. Without this information, Codex provides generic advice; with it, responses become specific and actionable.
We could manually run commands like git status and git diff in a separate terminal, copy their output, and paste it into our prompt. This works but creates friction: we repeat the same steps every time, risk copying stale data, and may forget important context. Inline shell capture automates this pattern.
Here is how it works: when we prefix a line with !, Codex executes that command locally, captures its output (stdout and stderr), and adds the captured text to the conversation history as if we had typed it ourselves. The language model then sees this output as user-provided context when processing our next question. This means a command like !git status runs on our machine, produces output, and that output becomes available for the model to reason over—without us copying and pasting anything.
Codex uses the exclamation mark (!) prefix to mark lines as local shell commands. This syntax mirrors environments like IPython and Jupyter notebooks:
Everything after the exclamation mark is treated as a shell command and executed in the session's current working directory (typically your repo root). The command runs subject to your approval settings and sandbox limits—if you have configured approval_policy = "on-request" or restrictive sandbox_mode, you may be prompted or blocked depending on what the command does.
Multiple commands can be run in sequence:
Each command executes independently, captures its own output, and adds that output to the conversation. Once all commands complete, we can ask our question, and the model will have access to all the captured context.
The first piece of context we typically need is the current state of our working directory: which files are modified, which are staged, and which are untracked. We use git status with the --porcelain flag to get machine-readable output:
The --porcelain flag produces stable, parse-friendly output instead of human-oriented messages. Each line shows a two-character status code followed by the file path. For example, M means modified but unstaged, M means staged, ?? means untracked, and A means newly added.
This compact format gives Codex precise information about the repository state without verbose explanations. When the model sees this output in the conversation history, it understands exactly which files need attention: unstaged changes that might need committing, staged changes ready for review, or new files that might need .gitignore entries.
The second piece of context is recent history: what changes landed recently, what the commit messages describe, and how the current branch appears. We use git log with formatting options to keep output concise:
The -n 5 flag limits output to five commits, providing recent context without overwhelming the conversation with the entire project history. The --oneline flag formats each commit as a single line: an abbreviated hash followed by a commit message.
This shows the trajectory of recent work. If commit messages mention fix auth bug and add user validation, Codex understands the current focus area. If the most recent commit is WIP: refactoring database, Codex knows that work is in progress and can suggest the next steps for that refactoring. The hash prefixes also allow us to reference specific commits in follow-up questions.
The third and often most valuable piece of context is the actual diff: line-by-line changes in the working directory. We use git diff without arguments to see all unstaged modifications:
This command produces a unified diff format showing exactly what changed: removed lines prefixed with -, added lines with +, and context lines left unchanged. The diff includes file paths, line numbers, and surrounding code for context.
For Codex, this is the most detailed information available. Rather than just knowing that three files were modified (from status), it sees the specific lines changed, the functions touched, and the patterns in the modifications. This enables precise suggestions: if the diff shows repeated null checks being added, Codex might suggest extracting a validation function; if it shows a new parameter added to several function calls, it might identify remaining call sites that need updating.
To keep output manageable, consider using git diff --stat for a summary view when the full diff would be too large, or git diff -U3 to limit context lines around changes. If your diff is large, start with !git diff --stat and only run !git diff for the specific file you're discussing (!git diff -- path/to/file).
Now, we combine all three commands into a cohesive workflow that establishes context and asks for analysis. In the Codex CLI, we execute the commands in sequence, then follow up with our question:
After running these three commands, their outputs appear in the conversation history. We then ask our question:
This workflow is deliberate: we first gather all the context we need using shell commands, then explicitly reference that context in our question. The instruction "Given the outputs above" tells Codex to look at the recently added context. The word "minimal" guides it toward focused, incremental suggestions rather than broad refactorings.
Some clients also support mixing context commands and questions in one message; if yours doesn't, run the !… lines first, then ask the question separately.
When we use inline shell capture, the commands execute with the following characteristics:
Execution environment: Commands run in the session's current working directory, typically your repo root. They execute on your local machine, not in the cloud.
Approval and sandboxing: Commands are subject to your configured approval settings and sandbox limits. If you have enabled approval prompts, Codex may ask for confirmation before executing commands that modify state or access the network.
Error handling: Both stdout and stderr are captured. If a command fails (non-zero exit code), the error output is still captured and becomes part of the conversation context, allowing you to ask Codex about the error.
Timing: Commands should complete quickly and deterministically. Avoid interactive programs, streaming output, or commands that might hang. Inline commands are meant for gathering information, not for long-running processes.
Inline shell capture is powerful but requires careful use to avoid security risks. The most important principle is: only use commands you would manually run and trust in your repository. Avoid commands that read secrets (cat ~/.ssh/id_rsa, env | grep TOKEN), modify state (git commit, rm -rf), or access the network (curl, wget).
The commands we are using (git status, git log, git diff) are safe because they are read-only, local, and fast. They reveal information we would intentionally share with Codex anyway. However, be cautious with commands that might expose sensitive data. If your repository contains .env files or credential configurations, do not run commands like cat .env; those secrets would end up in the conversation history and potentially in logs or responses.
Remember that Codex applies approval modes and sandbox limits to ! commands. Depending on your configuration, you may be prompted to approve commands before they execute. This provides a safety check: review what the command will do before allowing execution. Commands that modify files, access the network, or perform other potentially risky operations may require explicit approval.
This pattern of capturing repository state in the conversation unlocks several practical workflows. The most common is incremental development guidance: after making changes, run the status and diff commands, then ask Codex for suggestions on tests, documentation, or related updates. The model sees what you changed and can propose logical next steps.
Another application is code review preparation: before creating a pull request, gather the repository state and ask Codex to generate a summary of changes, identify potential issues, and suggest test cases. Since the model sees both the diff and recent commits, it understands the context of the change within recent work.
We can also use this pattern for debugging support: when stuck on an issue, gather the repository state and ask Codex to hypothesize what might be wrong. The model sees modified files, recent commits (which might have introduced the bug), and current changes (your debugging attempts), providing targeted suggestions.
Finally, this pattern enables session resumption: when returning to work after an interruption, run the status and log commands, then ask for a summary. The model recalls the recent direction from commit messages and current changes, suggesting where to continue. This is particularly valuable in long-running feature development or complex refactorings.
In this lesson, we have learned how to use inline shell capture to run local shell commands directly from the Codex CLI and inject their output into our conversation history. We explored the ! syntax for executing commands, built a practical workflow that gathers status, commits, and diffs, and understood the execution characteristics including environment, approval mechanisms, error handling, and timing considerations.
We examined three essential Git commands for establishing context: git status --porcelain for file state, git log -n 5 --oneline for recent history, and git diff for detailed changes. We also covered security considerations: preferring read-only, local, and fast commands; being aware of approval modes and sandbox limits; avoiding secret exposure; and limiting output size to maintain performance and stay within context limits.
The key insight is that inline shell capture transforms our interactions from static questions into dynamic ones that reflect current reality. Rather than describing our repository state in words or manually copying command output, we execute commands directly in the session and let Codex capture the results automatically. This makes our interactions with Codex more precise, our suggestions more relevant, and our workflows more efficient.
It is time to put inline shell capture into practice! The exercises ahead will challenge you to design workflows that gather different types of context, handle various repository states gracefully, and combine command outputs with targeted questions to extract maximum value from Codex's analysis capabilities.
