When the Build Outgrows the Computer: Bazel and BuildBuddy
On this page
You can edit a large project on a computer that struggles to build it. The problem appears during the first full compilation: the CPU is busy, memory runs short, the disk keeps reading and writing, and the browser and editor start competing with the build.
A workable arrangement is to keep the source and task control close at hand while moving heavy processing to a separate runner. Codex Patched uses Bazel and BuildBuddy for this. Together, they define component build boundaries, send work to the cloud, and provide a verifiable artifact. Here is how that workflow is organized and what to consider before making a similar move.
Where the resources go
Compilation loads the CPU, but the processor is only part of the picture. Several parallel compilers each keep their own data structures in memory. When free memory runs short, pressure on swap and I/O rises. Adding parallel jobs at that point can increase the wait.
A large project also has preparation work: fetching dependencies, running rules, analyzing targets, and constructing the action graph. Intermediate files then need to be written, read, and passed to the next step. Linking at the end can require substantial memory. A profile with LTO adds its own optimization cost.
Evaluate the move across the whole chain. It helps to distinguish environment setup, analysis, execution, queueing, and result delivery. Otherwise, a faster compiler can easily lose its advantage elsewhere.
What Bazel does
Bazel describes a build through targets and actions. An action connects declared inputs, a command, and output files. The graph determines dependencies and which independent parts can run in parallel.
This description provides a basis for reusing results. When an action’s significant inputs match, its result can come from a cache. Changing the compiler, flags, platform, or dependencies can change the action’s identity and require execution again.
A remote cache stores results and their metadata. Remote execution runs actions on executors. A cloud runner adds another level: Bazel itself runs there, including graph analysis. For a resource-constrained computer, that level matters because a locally running Bazel also performs work and consumes memory.
The Codex Patched workflow
In the project’s published design, the local side prepares source inputs and submits a job through the BuildBuddy Run API. Bazel, analysis, compilation, and linking run in the cloud. If the runner is unavailable, the build stops; there is no automatic fallback to a full local build.
The sequence is:
- Pin the public upstream version and a reviewed patch against it.
- Prepare a limited set of source files for additional components.
- Submit the job to the cloud runner and retain its invocation link.
- On the runner, fetch the pinned upstream, apply the patch and selected sources, then build the required target.
- Wait for successful completion and an artifact archive with a checksum.
- Download the selected result, verify it, and only then proceed to packaging and installation.
The project provides separate commands for these stages:
tools/build-codex-release
tools/build-native-bazel statusline
tools/cloud-build-status <invocation-id>
tools/fetch-cloud-artifacts <invocation-id> core
These are repository examples requiring its prepared environment and configured access. The first two start cloud work, the third reads status, and the fourth imports a completed result. An API response accepting a job does not yet provide a file suitable for installation.
Rebuild the selected component
It helps to reduce a large build before choosing the machine. In Codex Patched, the modified CLI, native host, manager, and individual feature libraries have their own build boundaries. A compatible change to one library can be built as a separate target.
That boundary depends on the interface. If a change requires a new Core-owned operation or alters the ABI, the affected host needs rebuilding. Having a .so does not mean every change can be delivered separately.
The current workflow takes the unchanged code mode host, exec server, and resources from the pinned official OpenAI package. Package provenance and hashes are checked. This reduces the amount built by the project and preserves the connection to a particular upstream release.
The claim that “a module change does not rebuild the CLI” needs two checks: target dependencies and the execution log of a real repeat build. Inspecting the graph alone does not establish build duration or actual cache hits.
Cold and repeat builds
A cold build needs its environment, dependencies, and any action results missing from the available caches. A repeat build may reuse a warm workspace and saved results. The benefit depends on exactly what changed and what survived between runs.
The project separates a fast iteration profile from an optimized profile with LTO. They have different parameters and cache identities. Compare times within the same profile, recording the source change and cache state.
A useful experiment is to change one selected component and examine the second execution log. Does it contain only the expected actions? Were the other components’ results retained? How long did queueing and file transfer take? Without that experiment, a claim of a particular speedup remains an assumption.
Reproducibility and delivery
A remote environment quickly exposes hidden dependencies: a tool found through an accidental PATH, a manually installed library, or a file outside the declared inputs. Tool versions, the platform, and required files need descriptions that let each action execute in its own environment.
Access secrets also need a separate channel. In this build workflow, they are excluded from the public patch and reach the runner through the designated secrets mechanism. Ordinary environment parameters and commands can enter metadata and logs, making them a poor and unsafe place for tokens when those logs may later be published.
A completed build includes source provenance, a log, a manifest, and checksums. Importing a selected generation checks the archive and its contents; a successful download does not itself activate a new version. Choosing which verified result to install remains a separate decision.
What remains expensive
The cloud adds queueing, source transfer, dependency retrieval, and artifact downloads. A slow network or frequent changes to shared inputs can consume the benefit of a warm cache. One large sequential step limits the value of additional executors.
Cloud resources also cost money. Evaluate that cost alongside waiting time and data transfer. Increasing resources makes sense after identifying the bottleneck; adopting Bazel does not promise a free build or faster results for every project.
The practical goal is to obtain the required binary predictably while keeping the work computer available for editing and reviewing results. Component boundaries and reproducibility matter just as much as runner capacity.
Frequently asked questions
Is connecting a remote cache enough?
A cache helps reuse results. If Bazel stays on the work computer, its preparation and analysis stay there too. In this workflow, the entire Bazel invocation moves to a cloud runner.
Can you build only the modified module?
Yes, when the target is separate from other components and the change remains compatible with the current interface. A contract change requires reviewing which components need rebuilding.
Why did the repeat build become slow again?
Check the profile, tool versions, platform, and changed inputs. Then separate runner queueing, execution, and transfer time. The new run may have a different cache identity or a cold environment.
When is the result ready?
When the selected invocation succeeds, the expected artifacts are published, and the downloaded result passes provenance and checksum verification. Installation and activation are subsequent, separate actions.
Official implementation references: Bazel remote execution, Bazel remote caching, Bazel rule requirements, BuildBuddy remote runner, and BuildBuddy remote execution.