| --- |
| tags: |
| - codex |
| - tmux |
| - automation |
| - developer-tools |
| --- |
| |
| # codex_exec |
| |
| `codex_exec` is an unofficial launcher for the interactive OpenAI Codex TUI. |
| It starts a real interactive `codex` session inside `tmux` and runs a watcher |
| that automatically confirms recognized Codex approval and selection overlays. |
|
|
| Despite the repository name, this is not `codex exec` and it does not turn |
| Codex into a non-interactive subprocess. You can attach to the TUI, type |
| follow-up messages, detach, reattach, and resume persisted Codex conversations. |
|
|
| The project is intentionally small and self-contained: |
|
|
| - `codex_auto_run.py`: the launcher and approval watcher. |
| - `test_codex_auto_run.py`: unit tests for detection, argument handling, and |
| daemon lifecycle behavior. |
| - `LOCAL_SETUP.txt`: optional `runx` Bash setup. |
| - `README.md`: this document. |
|
|
| ## Requirements |
|
|
| - Linux. The watcher uses `fcntl`, `/proc`, and `tmux`. |
| - Python 3.10 or newer. |
| - `tmux` available on `PATH`. |
| - Codex CLI installed, authenticated, and available as `codex` on `PATH`, or |
| supplied with `--codex-binary`. |
|
|
| The watcher recognizes text rendered by the Codex TUI. If a future Codex |
| release changes approval wording or layout, detector updates may be required. |
|
|
| ## Current Approval Policy |
|
|
| By default, Codex still starts with `on-request` approvals and the |
| `workspace-write` sandbox. The watcher then confirms recognized overlays after |
| the screen is stable for multiple polls. |
|
|
| The current default is broad auto-approval. It confirms the currently selected |
| option when that option is not an obvious negative or cancel choice. |
|
|
| Automatically confirmed by default: |
|
|
| - shell command approvals; |
| - file edit approvals; |
| - permission approvals; |
| - network access approvals; |
| - MCP/app/tool approvals; |
| - directory trust prompts; |
| - full-access prompts; |
| - hook/plugin prompts; |
| - ordinary multi-choice prompts such as `Questions 1/1`; |
| - persistent approval rows such as "don't ask again", session-wide approvals, |
| or future host approvals, if that row is currently selected. |
|
|
| The watcher will not confirm an option whose label starts with an obvious |
| negative/cancel prefix such as `No`, `Cancel`, `Deny`, `Reject`, `Quit`, |
| `Do not`, or `Don't`. |
|
|
| This removes the human review normally provided by an approval prompt. A |
| mistaken or prompt-injected Codex action may delete files, run untrusted |
| commands, disclose accessible data over the network, request broader |
| permissions, choose an unintended default answer, or act through connected apps. |
| Use this only in an environment where those side effects are acceptable. |
|
|
| Useful opt-out switches: |
|
|
| ```bash |
| ./codex_auto_run.py --no-approve-mcp ... |
| ./codex_auto_run.py --no-auto-trust-directory ... |
| ``` |
|
|
| `--bypass` is more dangerous: it passes Codex's |
| `--dangerously-bypass-approvals-and-sandbox` option and should only be used |
| inside an externally isolated container or VM. |
|
|
| ## Install Or Migrate |
|
|
| Clone the repository on the target machine: |
|
|
| ```bash |
| git clone https://huggingface.co/yitongl/codex_exec |
| cd codex_exec |
| chmod +x codex_auto_run.py |
| PYTHONDONTWRITEBYTECODE=1 python3 -m unittest -v test_codex_auto_run.py |
| ``` |
|
|
| Run directly from the clone: |
|
|
| ```bash |
| ./codex_auto_run.py -C ~/code/my_project -p "Inspect the project and run tests." |
| ``` |
|
|
| ## Optional `runx` Command |
|
|
| `LOCAL_SETUP.txt` provides a Bash function named `runx`. It derives a tmux |
| session prefix from the current directory, so different projects get separate |
| watcher state and logs. |
|
|
| The default `runx` setup expects the launcher at `$HOME/codex_auto_run.py`. |
| Install it like this: |
|
|
| ```bash |
| git clone https://huggingface.co/yitongl/codex_exec ~/codex_exec |
| cp ~/codex_exec/codex_auto_run.py ~/codex_auto_run.py |
| chmod +x ~/codex_auto_run.py |
| cp ~/codex_exec/LOCAL_SETUP.txt ~/.bash_aliases |
| source ~/.bashrc |
| ``` |
|
|
| Then use it from any project directory: |
|
|
| ```bash |
| cd ~/code/my_project |
| runx -p "Implement the requested change and verify it." |
| ``` |
|
|
| If you want to keep the script somewhere else, edit the path in |
| `LOCAL_SETUP.txt` before copying it to `~/.bash_aliases`. |
|
|
| ## Start A Session |
|
|
| ```bash |
| ./codex_auto_run.py \ |
| -C ~/code/my_project \ |
| -p "Implement the requested change, run the tests, and summarize the result." |
| ``` |
|
|
| The launcher creates a uniquely named `tmux` session and normally attaches to |
| it immediately. Startup output includes: |
|
|
| - the tmux session name; |
| - the Codex binary path; |
| - the working directory; |
| - the approval log path; |
| - the reattach command. |
|
|
| Use a UTF-8 prompt file for long tasks: |
|
|
| ```bash |
| ./codex_auto_run.py -C ~/code/my_project --prompt-file task.md |
| ``` |
|
|
| Start without attaching: |
|
|
| ```bash |
| ./codex_auto_run.py --detach -C ~/code/my_project -p "Run the full task." |
| ``` |
|
|
| Reattach later: |
|
|
| ```bash |
| tmux attach -t codex-auto-YYYYMMDD-HHMMSS-PID-RANDOM |
| ``` |
|
|
| Inside `tmux`, press `Ctrl-b d` to detach without stopping Codex. |
|
|
| ## Resume |
|
|
| Resume the most recent interactive conversation for a working directory: |
|
|
| ```bash |
| ./codex_auto_run.py --resume-last -C ~/code/my_project -p "Continue and verify." |
| ``` |
|
|
| Resume a specific Codex session ID or name: |
|
|
| ```bash |
| ./codex_auto_run.py --resume SESSION_ID -C ~/code/my_project -p "Continue." |
| ``` |
|
|
| Open Codex's interactive session picker: |
|
|
| ```bash |
| ./codex_auto_run.py --resume -C ~/code/my_project |
| ``` |
|
|
| The picker form cannot be combined with `-p` or `--prompt-file`; select the |
| conversation first, then type in Codex. |
|
|
| ## Pass Codex Options |
|
|
| Put Codex-specific global options after `--`: |
|
|
| ```bash |
| ./codex_auto_run.py \ |
| -C ~/code/my_project \ |
| -p "Research and implement the task." \ |
| -- \ |
| --search \ |
| --model MODEL_NAME |
| ``` |
|
|
| The wrapper reserves `-p` for the initial or resumed-session follow-up prompt. |
| Use `--codex-profile PROFILE_NAME` for Codex's own profile option. |
|
|
| Some Codex options conflict with wrapper-managed behavior and are rejected, |
| including Codex's own approval, sandbox, working-directory, full-auto, and |
| bypass flags. Use the wrapper's `--sandbox`, `-C`, and `--bypass` options |
| instead. |
|
|
| ## Watcher Status, Logs, And Control |
|
|
| Show status: |
|
|
| ```bash |
| ./codex_auto_run.py --status |
| ``` |
|
|
| Stop the watcher: |
|
|
| ```bash |
| ./codex_auto_run.py --stop-daemon |
| ``` |
|
|
| Start only the watcher: |
|
|
| ```bash |
| ./codex_auto_run.py --start-daemon |
| ``` |
|
|
| Default runtime state and logs are stored under: |
|
|
| ```bash |
| ~/.runtime/<session-prefix>/ |
| ``` |
|
|
| The approval log is: |
|
|
| ```bash |
| ~/.runtime/<session-prefix>/approve-debug.log |
| ``` |
|
|
| For the default direct launcher prefix this is: |
|
|
| ```bash |
| ~/.runtime/codex-auto/approve-debug.log |
| ``` |
|
|
| For `runx`, the prefix is based on the current directory and ends in `-x`. |
| For example, running from `$HOME` uses: |
|
|
| ```bash |
| ~/.runtime/home-x/approve-debug.log |
| ``` |
|
|
| Log events include `daemon_start`, `launcher_ready`, `pending`, `approve`, |
| `approve_failed`, `clear_active`, `daemon_exit`, and `daemon_stop`. |
|
|
| ## Tests |
|
|
| Run the unit tests: |
|
|
| ```bash |
| PYTHONDONTWRITEBYTECODE=1 python3 -m unittest -v test_codex_auto_run.py |
| ``` |
|
|
| The tests do not start a real Codex session. They cover approval-screen |
| detection, broad default approval behavior, opt-out switches, argument |
| validation, resume command construction, binary probing, tmux command |
| construction, and daemon lifecycle safeguards. |
|
|
| ## Project Status |
|
|
| This project is independent and unofficial. It is not an OpenAI product and is |
| not endorsed or supported by OpenAI. |
|
|