From 2d5c264ebc26c276ca6cc312389abde453ca69aa Mon Sep 17 00:00:00 2001 From: "Adam Perry @ OpenAI" Date: Wed, 3 Jun 2026 11:29:36 -0700 Subject: [PATCH] [codex] Copy user Bazel settings into Codex worktrees (#25925) ## Why Codex-created linked worktrees do not include ignored files from the main worktree. Bazel users who keep local overrides in `user.bazelrc` therefore lose those settings in every new worktree. The setup must also work on Windows and must not overwrite a file that already exists in the worktree. ## What changed The checked-in Codex environment now invokes `.codex/environments/setup.py`. The script resolves the main worktree and current worktree, then uses `copy_from_main_worktree_to_worktree(repo_relative_path)` to copy ignored files into new worktrees without overwriting existing destinations. `main()` currently copies `user.bazelrc`. Additional repository-relative paths can be added as further calls to the same helper. ## Validation - Ran the setup script in a linked worktree and confirmed it handles a missing main-worktree `user.bazelrc`. - Verified the helper copies a main-worktree file, preserves an existing worktree file, and creates parent directories for a nested path. --- .codex/environments/environment.toml | 2 +- .codex/environments/setup.py | 65 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 .codex/environments/setup.py diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml index 4595a1fa6..39c40eb07 100644 --- a/.codex/environments/environment.toml +++ b/.codex/environments/environment.toml @@ -3,7 +3,7 @@ version = 1 name = "codex" [setup] -script = "" +script = "python ./.codex/environments/setup.py" [[actions]] name = "Run" diff --git a/.codex/environments/setup.py b/.codex/environments/setup.py new file mode 100644 index 000000000..a9d78c940 --- /dev/null +++ b/.codex/environments/setup.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +"""Set up ignored files that should be shared with Codex worktrees.""" + +import shutil +import subprocess +from functools import cache +from pathlib import Path + + +@cache +def worktree_paths() -> tuple[Path, Path]: + script_dir = Path(__file__).resolve().parent + worktree_root = git_path(script_dir / "../..", "--show-toplevel") + common_git_dir = git_path(worktree_root, "--git-common-dir") + return worktree_root, common_git_dir.parent + + +def git_path(working_directory: Path, argument: str) -> Path: + output = subprocess.check_output( + [ + "git", + "-C", + str(working_directory), + "rev-parse", + "--path-format=absolute", + argument, + ], + text=True, + ) + return Path(output.strip()) + + +def copy_from_main_worktree_to_worktree(repo_relative_path: str) -> None: + relative_path = Path(repo_relative_path) + if relative_path.is_absolute() or ".." in relative_path.parts: + raise ValueError(f"path must be repository-relative: {repo_relative_path}") + + worktree_root, main_worktree = worktree_paths() + source_path = main_worktree / relative_path + destination_path = worktree_root / relative_path + + print(f" source: {source_path}") + print(f" destination: {destination_path}") + + if source_path == destination_path: + print(" result: running in the main worktree; nothing to copy") + elif destination_path.exists(): + print(" result: destination already exists; nothing to copy") + elif not source_path.is_file(): + print(" result: source does not exist; nothing to copy") + else: + destination_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source_path, destination_path) + print(f" result: copied {repo_relative_path}") + + +def main() -> None: + print("Codex environment setup:") + # See codex-rs/docs/bazel.md for the repository's Bazel workflow. + copy_from_main_worktree_to_worktree("user.bazelrc") + + +if __name__ == "__main__": + main()