diff --git a/.codex/skills/bazel-hot-cache/SKILL.md b/.codex/skills/bazel-hot-cache/SKILL.md new file mode 100644 index 0000000000..37b77ee50d --- /dev/null +++ b/.codex/skills/bazel-hot-cache/SKILL.md @@ -0,0 +1,115 @@ +--- +name: bazel-hot-cache +description: Use the CI-warmed BuildBuddy cache for fast local or Applied devbox Bazel builds without uploading local artifacts. +--- + +# Bazel Hot Cache + +Use this skill when a Codex developer wants a fast Bazel build from the +BuildBuddy cache warmed by post-merge CI, especially for +`//codex-rs/cli:codex`. + +## Why This Exists + +The checked-in helper `scripts/run-bazel-hot-cache-build.sh` consumes the +BuildBuddy keyspace warmed by the platform-matching `verify-release-build` lane +on successful `main` pushes. That CI lane is the relevant writer because it +builds release-shaped Rust code in Bazel `fastbuild` mode with Rust debug +assertions disabled, which matches the developer build shape this helper is +for. + +The helper is read-only from a developer machine or devbox: + +```text +--noremote_upload_local_results +``` + +Do not change this to upload laptop or devbox artifacts unless the user +explicitly asks for a cache-warming writer flow. + +## Local Flow + +From a Codex checkout with `gh` auth and `BUILDBUDDY_API_KEY` in the command +environment: + +```bash +hot_sha="$(scripts/run-bazel-hot-cache-build.sh --print-latest-hot-main-commit)" +git worktree add ../codex-hot-cache "${hot_sha}" +cd ../codex-hot-cache +scripts/run-bazel-hot-cache-build.sh +``` + +If the current checkout is already at the desired hot SHA, run the helper in +place. Pass Bazel target patterns after the script name to build something +other than the default `//codex-rs/cli:codex`. + +For routine developer use, keep Bazel's normal persistent user root and +repository cache. A fresh worktree already gives Bazel a fresh workspace/output +base while preserving the shared local Bazel state that makes the workflow +predictable. Only set `BAZEL_OUTPUT_USER_ROOT` when intentionally running an +isolated diagnostic proof; that discards useful local Bazel state and can be +substantially slower even when remote cache hits are 100%. + +## Applied Devbox Flow + +The same helper works on a Linux Applied devbox mirror. The helper selects +`ci-linux` on Linux and `ci-macos` on macOS. Applied rsync mirrors commonly +exclude `.git`, so forward the checkout SHA as `CODEX_BAZEL_COMMIT_SHA` for +that remote command. The helper itself does not use `tmux`. + +Portable shape: + +```bash +commit_sha="$(git rev-parse HEAD)" +remote_repo="" +BUILDBUDDY_API_KEY_STDIN="$BUILDBUDDY_API_KEY" \ + ssh "bash -lc 'read -r BUILDBUDDY_API_KEY; export BUILDBUDDY_API_KEY; export CODEX_BAZEL_COMMIT_SHA=${commit_sha}; cd ${remote_repo}; export PATH=\$HOME/code/openai/project/dotslash-gen/bin:\$HOME/.local/bin:\$PATH; scripts/run-bazel-hot-cache-build.sh'" \ + <<< "$BUILDBUDDY_API_KEY_STDIN" +``` + +Replace `` and `` with the caller's actual host +and mirrored checkout path. Do not persist the BuildBuddy key on the devbox for +this flow. + +## Cache-Key Rules + +The helper intentionally owns the Bazel option order. Keep the explicit Rust +debug-assertion flags before the platform CI config. The CI config adds Rust +flags too, and Bazel action keys include generated Rust params-file bytes, so +moving `--config=ci-macos` or `--config=ci-linux` before those explicit flags +can turn a CI-hot action into a remote miss. + +The helper sets: + +- `--config=buildbuddy-openai-rbe` +- `--compilation_mode=fastbuild` +- Rust `-Cdebug-assertions=no` flags for target and exec Rust actions +- `--build_metadata=COMMIT_SHA=` +- `--build_metadata=TAG_job=verify-release-build` +- `--build_metadata=TAG_rust_debug_assertions=off` +- `--config=ci-macos` on macOS or `--config=ci-linux` on Linux +- `--remote_download_toplevel` +- `--noremote_upload_local_results` + +## Reading Results + +Read Bazel summaries as: + +```text +cacheable_hit_rate = remote cache hit / (all processes - internal) +``` + +Do not include Bazel `internal` processes in the denominator; they are local +bookkeeping, not cache misses. + +## Limits + +- Build mode supports macOS and Linux only. +- `--print-latest-hot-main-commit` requires `gh` auth. +- Build mode requires `BUILDBUDDY_API_KEY`. +- This is command/config specific. A successful `main` Bazel run is a good hot + default for this helper's `verify-release-build` shape, not proof that every + other Bazel command is hot. +- Routine latency claims should be measured from fresh worktrees using the + normal persistent Bazel user root, not from fresh `BAZEL_OUTPUT_USER_ROOT` + diagnostics. diff --git a/codex-rs/docs/bazel.md b/codex-rs/docs/bazel.md index 085c15992f..3bd72bb9c6 100644 --- a/codex-rs/docs/bazel.md +++ b/codex-rs/docs/bazel.md @@ -132,6 +132,41 @@ run in `openai/codex`. A missing or malformed pull request event payload fails closed to the generic host. For local OpenAI host access, use the `user.bazelrc` configuration above. +### Use the CI-warmed developer cache + +The platform-matching `verify-release-build` Bazel lane on `main` warms a +developer fastbuild keyspace for release-shaped Rust builds with debug +assertions off. On a local Mac or Linux Applied devbox with +`BUILDBUDDY_API_KEY` set in that command's environment, use +`scripts/run-bazel-hot-cache-build.sh` to consume that cache without uploading +locally built artifacts: + +```bash +hot_sha="$(scripts/run-bazel-hot-cache-build.sh --print-latest-hot-main-commit)" +git worktree add ../codex-hot-cache "${hot_sha}" +cd ../codex-hot-cache +scripts/run-bazel-hot-cache-build.sh +``` + +If the current checkout is already at a known hot commit, run the script in +place instead of creating another worktree. On an Applied Linux devbox, run +the same script from the synced mirror with `BUILDBUDDY_API_KEY` and +`CODEX_BAZEL_COMMIT_SHA` forwarded only for that remote command; it selects the +Linux `verify-release-build` cache keyspace instead of the macOS one. Pass +Bazel target patterns after the script name to build something other than the +default `//codex-rs/cli:codex`. + +For routine developer use, keep Bazel's normal persistent user root and +repository cache. A fresh worktree already gives Bazel a fresh workspace/output +base while preserving the shared local Bazel state that makes this workflow +predictable. Set `BAZEL_OUTPUT_USER_ROOT` only for isolated diagnostic proofs; +that discards useful local Bazel state and can be much slower even when remote +cache hits are 100%. + +Keep the script-owned option order. Bazel action keys include the generated +Rust params-file bytes, so moving the platform CI config before the explicit +Rust debug-assertion flags can turn a hot CI action into a local cache miss. + ## Evolving the setup When you add or change Rust dependencies, update the Cargo.toml/Cargo.lock as normal. diff --git a/scripts/run-bazel-hot-cache-build.sh b/scripts/run-bazel-hot-cache-build.sh new file mode 100755 index 0000000000..234668396c --- /dev/null +++ b/scripts/run-bazel-hot-cache-build.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +set -euo pipefail + +readonly OPENAI_REPOSITORY="openai/codex" +readonly DEFAULT_TARGET="//codex-rs/cli:codex" + +usage() { + cat <<'EOF' +Usage: + scripts/run-bazel-hot-cache-build.sh [bazel target patterns...] + scripts/run-bazel-hot-cache-build.sh --print-latest-hot-main-commit + +Build the current checkout against the BuildBuddy keyspace warmed by the +platform-matching verify-release-build Bazel CI lane. If no target is +provided, builds //codex-rs/cli:codex. + +Requires: + - macOS or Linux for build mode + - BUILDBUDDY_API_KEY in the environment for build mode + - gh auth for --print-latest-hot-main-commit +EOF +} + +print_latest_hot_main_commit() { + if ! command -v gh >/dev/null 2>&1; then + echo "gh is required to find the latest hot main commit." >&2 + exit 1 + fi + + local hot_commit + hot_commit="$( + gh run list \ + --repo "${OPENAI_REPOSITORY}" \ + --workflow Bazel \ + --branch main \ + --event push \ + --limit 20 \ + --json headSha,status,conclusion \ + --jq '[.[] | select(.status == "completed" and .conclusion == "success") | .headSha][0] // empty' + )" + if [[ -z "${hot_commit}" ]]; then + echo "No successful Bazel main push run found." >&2 + exit 1 + fi + + printf '%s\n' "${hot_commit}" +} + +case "${1:-}" in + --help | -h) + usage + exit 0 + ;; + --print-latest-hot-main-commit) + print_latest_hot_main_commit + exit 0 + ;; +esac + +if [[ -z "${BUILDBUDDY_API_KEY:-}" ]]; then + echo "BUILDBUDDY_API_KEY must be set to read the OpenAI BuildBuddy cache." >&2 + exit 1 +fi + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +repo_root="$(cd "${script_dir}/.." && pwd -P)" +cd "${repo_root}" + +targets=("$@") +if [[ ${#targets[@]} -eq 0 ]]; then + targets=("${DEFAULT_TARGET}") +fi + +bazel_bin="${CODEX_BAZEL_BIN:-bazel}" +repository_cache="${BAZEL_REPOSITORY_CACHE:-${HOME}/.cache/bazel-repo-cache}" +commit_sha="${CODEX_BAZEL_COMMIT_SHA:-${GITHUB_SHA:-}}" +if [[ -z "${commit_sha}" ]] && command -v git >/dev/null 2>&1; then + commit_sha="$(git rev-parse HEAD 2>/dev/null || true)" +fi +if [[ -z "${commit_sha}" ]]; then + echo "Could not determine COMMIT_SHA; set CODEX_BAZEL_COMMIT_SHA for rsynced mirrors without .git." >&2 + exit 1 +fi +bazel_ci_config="" +case "$(uname -s)" in + Darwin) + bazel_ci_config="ci-macos" + ;; + Linux) + bazel_ci_config="ci-linux" + ;; + *) + echo "scripts/run-bazel-hot-cache-build.sh supports macOS and Linux only." >&2 + exit 1 + ;; +esac +bazel_startup_args=() +if [[ -n "${BAZEL_OUTPUT_USER_ROOT:-}" ]]; then + bazel_startup_args+=("--output_user_root=${BAZEL_OUTPUT_USER_ROOT}") +fi + +# Keep the explicit Rust debug-assertion flags before the platform CI config. +# That matches the verify-release-build CI action key ordering that warms this +# cache. +exec "${bazel_bin}" \ + "${bazel_startup_args[@]}" \ + --noexperimental_remote_repo_contents_cache \ + build \ + --config=buildbuddy-openai-rbe \ + "--remote_header=x-buildbuddy-api-key=${BUILDBUDDY_API_KEY}" \ + --compilation_mode=fastbuild \ + --@rules_rust//rust/settings:extra_rustc_flag=-Cdebug-assertions=no \ + --@rules_rust//rust/settings:extra_exec_rustc_flag=-Cdebug-assertions=no \ + "--build_metadata=COMMIT_SHA=${commit_sha}" \ + --build_metadata=TAG_job=verify-release-build \ + --build_metadata=TAG_rust_debug_assertions=off \ + "--config=${bazel_ci_config}" \ + --remote_download_toplevel \ + "--repository_cache=${repository_cache}" \ + --noremote_upload_local_results \ + -- \ + "${targets[@]}"