buck2
Skill1.6k starsChanged todayMITView on GitHub
Build, test, query and extend the Overalls Buck2 graph. Use for every BUCK, .bzl, .bxl, .buckconfig, toolchains/ or tools/buck2 change, when adding a target in any language, when selecting affected tests, and when a Buck2 build, cache or daemon misbehaves.
We split this skill into the rules it gives an agent
20 rules. About 0 are common, 1 is distinctive, and 19 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 32
Finding the target for a Nix output: Never use nix build .#…; every output has a Buck2 target:
- Distinctive: line 69
Never call a tool by bare name inside an action.
- Very specific: line 70
Add it to tools in nix/buck/cells.nix.
- Very specific: line 71
Add its name to the nix_tool list in toolchains/BUCK.
- Very specific: line 79
Nothing evaluates the flake's build outputs: Every Nix output Buck2 builds goes through nix_assemble over lib.assemble.
- Very specific: line 89
.buckconfigignores are root-relative: Use /name for nested build directories. - Very specific: line 107
Keep the fetch* hash and vendorHash in the pin registry.
- Very specific: line 110
Use go_binary(source, modules, vendor_mode = "vendor"|"proxy", patches, vendor_patches, overlay, package, ldflags, goos) and …
- Very specific: line 118
Packages: Add the project's importNpmLock tree to inputs.npm in cells.nix.
- Very specific: line 124
Bundles: Use esbuild_bundle(srcs, entry, out, args).
- Very specific: line 214
When they build: Only with -c overalls.non_hermetic=true and on their own OS (target_compatible_with uses toolchains//:non_hermetic_enabled.
- Very specific: line 280
Targets: Every machine check in nix/verification/tests/catalog.nix is a nixos_machine_test (buck/nixos.bzl) in …
- Very specific: line 298
Never edit the generated BUCK files: After changing catalog.nix or a suite's requiredFeatures, run python3 buck/machine_tests.py generate.
- Very specific: line 300
After changing which scenario files a fleet variant reads, run python3 buck/machine_tests.py refresh-scenarios (evaluation only, a few …
- Very specific: line 348
Who writes: Every token holder uploads.
- Very specific: line 412
Fallback: When tools/buck2 server fails, or with OVERALLS_PRECOMMIT_DIRECT=1, the hook scripts run directly with the pinned tools devenv …
- Very specific: line 510
Run one shard: tools/buck2 build '//marshall:test[shard-3]'.
- Very specific: line 522
Sandbox: Every Mix action runs in buck/mix_sandbox.sh:
- Very specific: line 589
Stale toolchain: Check that readlink .buck-cells matches nix build --print-out-paths .#buckCells.x86_64-linux, then run tools/buck2 kill.
- Very specific: line 605
Run the changed targets, the ownership BXL and elixir scripts/check_adrs.exs when records change.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Buck2 in Overalls
Buck2 is the only build entry point
(ADR-0269).
Nix supplies the cells. Use the nix-builds skill for pins and NixOS assembly.
Running
- Always run
tools/buck2 …, never a buck2 fromPATH. The wrapper rebuilds.buck-cellsfrom the flake-pinnedbuckCellsoutput, and it restarts the daemon only when the cells store path changes. - Common commands:
- build:
tools/buck2 build //path:target --show-full-output - test:
tools/buck2 test //path:target - query:
tools/buck2 uquery 'owner(path/to/file)',tools/buck2 uquery 'rdeps(//..., //lilly:srcs)'
- build:
- Target hashes, which feed the selector:
tools/buck2 targets //... --show-unconfigured-target-hash --target-hash-file-mode=paths_and_contents --target-hash-recursive=true. Pass--target-hash-recursive=trueexplicitly: without it a dependency's change (including a toolchain path) does not change the hash.--target-hash-modified-pathsonly applies inpaths_onlymode. - Affected targets:
tools/affected [--base REV] [--all] [--output FILE]compares the base revision with the working tree and prints JSON grouped asmachine_tests(with labels),testsandbuilds. It only loads targets; it never builds.buck2andaffectedin the devenv shell are these wrappers. - Finding the target for a Nix output. Never use
nix build .#…; every output has a Buck2 target:- a
lib.assemblepackage output<name>(nix/assemble/outputs.nix, listed innix/buck/assembly_attrs.bzl) is//:package-<name>; - a machine test is
//nix/verification/tests/machines/<suite>:<name>, and any other check is//:check-<name>; the generated "Find a test" table innix/verification/tests/README.mdlists every one with its target; - a host system is
//fleet/hosts/<host>:deployment(:base,:install); tools/buck2 uquery 'attrregexfilter(attr, "<regex>", //...)'finds thenix_assembletarget for alib.assembleattribute. Anix_assembleoutput is a file holding the store path:cat "$(tools/buck2 build //:package-host --show-full-simple-output)". Anix_store_runtarget makes one runnable (tools/buck2 run //mila:journey-fixture).
- a
- Generated documentation.
tools/docsrewrites the sections thatbuck/bxl/docs.bxlrenders from the graph (the "Find a test" table, from every test target plusnix/verification/tests/find_a_test.bzl);tools/docs --checkfails when one is stale. - Ownership:
tools/buck2 bxl //buck/bxl/ownership.bxl:main -- --files $(git ls-files). Pass list arguments after--; an@argfileis not expanded there.
Layout
- Cells.
rootis the repository.preludeis.buck-cells/prelude, the Nix-pinned buck2's bundled prelude.toolchainsistoolchains/.noneis a stub. - Configuration. The
[nix]section comes from.buck-cells/toolchains.buckconfig, whichnix/buck/cells.nixgenerates. - Rules live in
buck/*.bzl, and BXL scripts inbuck/bxl/. - Ownership. Each top-level directory has a
BUCKfile withnix_owned(). A new directory without one is owned by the root package. That is correct, but coarse.
Rules for writing targets
- Tools come from
toolchains//:<name>. These arenix_tooltargets. Never call a tool by bare name inside an action. To add a tool:- Add it to
toolsinnix/buck/cells.nix. - Add its name to the
nix_toollist intoolchains/BUCK.
- Add it to
- Read configuration at load time.
read_root_configcannot be called during analysis. Read it in a macro and pass the value as an attribute, so it enters the target hash. - Declare every input. Undeclared reads break affected-test selection (ADR-0270).
- Actions that touch
/nix/storeor the Nix daemon arelocal_only = Trueandallow_cache_upload = False. - Nothing evaluates the flake's build outputs. Every Nix output Buck2
builds goes through
nix_assembleoverlib.assemble. Package outputs and non-script checks are defined innix/assemble/outputs.nix, never inflake.nix, and BUCK.v2 declares//:package-<name>and//:check-<name>for each (labelflake_output). After lib.assemble gains or loses one, regenerate the list withnix/buck/assembly-attrs.sh;//buck:assembly_attrs_freshfails until you do. The flake itself only exportsbuckCells,lib.assemble,lib.dependencyPinsandnixosModules; never add apackages,checks,appsornixosConfigurationsconsumer. .buckconfigignores are root-relative. Use**/namefor nested build directories.- Default globs skip dotfiles.
nix_ownedadds**/.*patterns; do the same anywhere hidden files matter.
Adding targets by language
Shared helpers live in buck/checks.bzl:
tool(dep)reads anix_toolpath, andsearch_pathbuildsPATHfrom tools only.- A check is a cached build action that writes a stamp.
buck2 testonly reads the stamp (check_providers), so an unchanged check is a cache hit. nix_owned()also definessrcs_files. It maps each owned file's repository path to its artifact, for checks that run per file.
Go (buck/go.bzl). Third-party source and modules come from Nix:
- Keep the
fetch*hash andvendorHashin the pin registry. - Expose the source and modules in
inputs.goinnix/buck/cells.nix, and list them intoolchains/BUCK. - Use
go_binary(source, modules, vendor_mode = "vendor"|"proxy", patches, vendor_patches, overlay, package, ldflags, goos)andgo_test(packages). Cross-compile by settinggoos.
The rule reproduces buildGoModule and stdenv's strip, so outputs should
match Nix byte for byte. Compare them with diff -r.
JavaScript (buck/npm.bzl):
- Packages. Add the project's
importNpmLocktree toinputs.npmincells.nix. The wrapper already hashes everypackage-lock.json. Then usenpm_package(srcs, node_modules, commands, install):- with
install(dest to package path), the output is a directory; - without it, the target is a check.
- Tools such as Chromium come in through
tools = {"CHROME": …}.
- with
- Bundles. Use
esbuild_bundle(srcs, entry, out, args). It runs the one pinned esbuild. Never useesbuild.install.
Python. //:py-static covers every owned .py file and
pyproject.toml:
- It runs ruff format, ruff check and
antithesis/verification/static-check.sh(ty) with the closure fromnix/buck/python.nix, the same one the precommit hook's direct fallback uses. - One file:
tools/buck2 build '//:py-static[ruff/<path>]'; ty alone:[ty]; the fixed copy of a file:[fix/<path>]. - A new third-party import goes in
nix/buck/python.nix.
Scripts:
script_check(cmd, srcs, path)runs a command from the project root over declared inputs. Reference a file in another package with anexport_file.//:conflict-markers[<path>]checks one file.repo_check(cmd, include, owned, deletions, inventory, local_only)runs a repository-wide command over the owned files matchinginclude(one*matches anything,/included). It carriesPrecommitInfo, so precommit runs it only when a matching file changes.//:adrs,//:pins,//:rust-lints,//:toolchain-versions,//:package-input-lock,//:contracts-testsand//:logging-<app>use it.//:contracts(contract_check) is the contract format and coverage check;[contracts/<path>]checks one file with its ancestorCONTRACTS.nix_store_run(package, program)makes a Nix-built program runnable withbuck2 run, for example//mila:journey-fixture.
Rust (buck/rust.bzl, ADR-0273):
- One toolchain.
toolchains//:rustis the rust-overlay toolchain fromnix/rust-toolchain.nix([nix] rust), andtoolchains//:cxxlinks with the Nix cc wrapper underenv -i([nix] cc_hermetic), so a dev-shellNIX_LDFLAGSnever reaches a link. - Third-party crates come from the generated
rust//cell (nix/buck/rust.nix):reindeer buckifyover a pseudo-package of every member's direct dependencies at the rootCargo.lockversions, with sources fromimportCargoLock. It is generated because the lock is the only pin; nothing underrust//is committed. A crate needing a fixup getsnix/buck/rust/fixups/<crate>/fixups.toml(libc's is the example). - First-party crates. In the top-level directory's
BUCK, calloveralls_rust_crate("<member path>", profile = "hardened"|"release", native_libs = [...], test_env = {...}); a Rustler NIF passeslib_test = False(its harness cannot link outside the BEAM; Marshall's Cedar crate is the example). It reads the member fromrust//:workspace.bzland defines<pkg>-lib, one target per binary,<pkg>-unittest,<pkg>-test-<name>,<pkg>-example-<name>, and the<pkg>-clippyand<pkg>-rustfmtprecommit checks ([rustfmt/<path>]checks one file). A test-only fault-injection build usesoveralls_rust_crate_variant(path, name, replace = {"src/x.rs": ":gen"}, bins = [...]), with the patch made by//buck:replace_boundary.sh(fails if the boundary moves); nix/BUCK's commit-reply cut is the example. Native libraries are[nix] <name>_libdirectories incells.nix. Adding a crate, dependency or Rust file name rebuilds the cell. - Replacing a Nix leaf. Bundle the binaries in the layout the Nix
consumer expects,
nix_store_importit with every rpath store path inruntime_refs, add the name toRUST_ARTIFACTS(buck/rust_artifacts.bzl) and torustArtifactNamesinnix/domains/artifacts/default.nix, and make the consumer readswapLeaf "<name>" <Nix build>(keepsmeta, exposespassthru.nixBuild). A reference constraint goes on the import (allowed_references = []for Lyra's Windows agents). A fixture that patches or rebuilds the source is its own Buck2 target inTEST_ARTIFACTS, never an override of the leaf. Add arust_leaf_parity_test(labelheavy) against a flake attribute with exactly the same executables;tools/precommitruns//buck/bxl/rust_parity_coverage.bxl:main, which fails when aRUST_ARTIFACTSimport has no parity test. The flake (host self-deploy) keeps the Nix build until the M2 activation gate; deletions wait for M11. - Cargo-driven leaves (Lyra's cross builds,
buck/lyra.bzl): when a build needs Cargo itself (zig linkers, SDKs,-sysbuild scripts), put the Nix build phase in a script both systems run, give Buck2 its tools as a realised.drvin the cells, and compare withrust_leaf_parity_test(compare = "bytes"). PinSOURCE_DATE_EPOCHandTZin the script; mask only what differs between two Nix builds. - Machine tests receive
MACHINE_TEST_ARTIFACTS(buck/artifacts.bzl):ASSEMBLY_ARTIFACTS(the merge ofRUST_ARTIFACTSandMIX_ARTIFACTS, which hosts also get) plus the test-onlyTEST_ARTIFACTS; every key must be a name the package set consumes, or evaluation fails.
Mila platforms (buck/mila.bzl, mila/BUCK, ADR-0269 M9). Xcode,
Gradle and .NET need SDKs that Nix does not supply, so these are
non_hermetic targets:
- What they are.
mila_platform(name, os, steps, outputs, env, path_env, require, srcs, check)runsstepsin the checkout throughbuck/mila_platform.py, with the SDKs from the daemon'sPATH, then copiesoutputs(repository paths) into buck-out with aSHA256SUMS. The actions arelocal_onlyand never use a cache. Third-party packages are pinned by lock files, which//:pinsrequires: Gradle'sgradle/verification-metadata.xmland NuGetpackages.lock.jsonrestored in locked mode. - When they build. Only with
-c overalls.non_hermetic=trueand on their own OS (target_compatible_withusestoolchains//:non_hermetic_enabled;osmay list several hosts, as the Android targets do).buck2 build //...,buck2 test //..., verification andtools/affectedskip them. - Targets.
- Apple (macOS):
apple-ffi,apple-ffi-clippy,apple-swift-test,{macos,ios}-{dev,release}(wrappingmila/native/mila-build). - Android (Linux or macOS):
android-debug,android-release,android-ffi-clippy. - Windows:
windows-ffi-published,windows-dotnet,windows-smoke, and the local fallbackwindows-ffi-msvc,windows-ffi-msvc-clippy. - Hermetic, on Linux:
windows-ffi-gnucross-builds the shipped FFI DLL forx86_64-pc-windows-gnuwith cargo-zigbuild and therust//cell's vendored crates, deterministically (SOURCE_DATE_EPOCH=0, remapped paths).windows-ffi-gnu-reproduciblecompares it with the independentwindows-ffi-gnu-rebuild;windows-ffi-gnu-abichecks its exports againstinclude/mila_ffi.hand the .NET imports;windows-ffi-gnu-clippylints it. mila-builds.yml publishes the DLL. - Windows imports that DLL:
windows-ffi-publishedcopiesmila/build/windows-ffi-gnu/mila_ffi.dll(the downloaded artifact) and checks it against itsSHA256SUMSand-c mila.windows_ffi_sha256=<hex>.-c mila.windows_ffi=msvcbuilds the local MSVC fallback instead.
- Apple (macOS):
- The daemon's environment is the SDK. Buck2 local actions inherit the
environment of the daemon, not of the command. Install the SDKs first. Run
tools/buck2 killafter changingPATHor a variable a build reads (the release signing inputs, for example). - macOS.
tools/buck2buildsbuckCells.aarch64-darwin: buck2, the prelude and a few host tools. Every other[nix]tool is a stub, and therust//cell is empty. Its patched nixpkgs source comes from devenv's Cachix. - Windows (no Nix).
tools/buck2 --no-nix …downloads the buck2 release and the prelude named intools/buck2-no-nix.jsonand checks them against the pin registry (buck2WindowsBinary,buck2Prelude). It needspythonandzstd(or Python 3.14). It writes a real.buck-cellsdirectory whose configuration sets[overalls] no_nixandnon_hermetic. Tools resolve fromPATH, and any hermetic target fails at analysis.OVERALLS_BUCK2_KITmay name a//tools:buck2-no-nix-<os>output instead of downloading. Building those kits also checks that the no-Nix pins are exactly the buckCells buck2 and prelude: refreshtools/buck2-no-nix.jsonand the three registry keys with every buck2 bump.- The Linux kit runs this mode on a development host.
- Example (Android, on Linux or macOS): install JDK 17, Gradle 9.3.1, the Android
SDK and NDK and cargo-ndk on
PATH, thentools/buck2 build -c overalls.non_hermetic=true //mila:android-debug.
Dockerfile images (buck/container_image.bzl). container_image(name,
dockerfile, repository, stores) declares <name> (docker buildx build
--load with the repository root as context, then a layer scan for the
Namespace token prefix) and the buck2 run target <name>-publish (--
--registry REG --tag TAG...: push with a registry cache, pull back, scan).
stores maps a build-context name to a nix_assemble target; its closure
goes in as a Nix binary cache the Dockerfile imports with nix copy, so
nothing builds Nix or Buck2 outputs inside the image. Both are
non_hermetic and Linux-only like the Mila platforms; docker and the buildx
builder come from the daemon's environment for the build, so run
tools/buck2 kill after changing them. The OSS scanner image is
//.oss-scanner:image.
Checks that evaluate NixOS (nix-compact-*,
fleet-builds-configuration) are //:check-<name> assemblies of
lib.assemble's checks; tools/buck2 build '//:check-<name>[drv]' evaluates
one without building it.
NixOS machine tests
- Targets. Every machine check in
nix/verification/tests/catalog.nixis anixos_machine_test(buck/nixos.bzl) innix/verification/tests/machines/<suite>/BUCK, named after the check. Fleet variants carry their flags asparamsand only their own scenario files as inputs. Each target buildslib.assemble {}.checks.<name>throughnix_assembleover a copy of its declaredinputsonly, so reading an undeclared file is an evaluation error: add the owning group toinputs(inbuck/inputs.bzlor the generator), not a workaround. - Evaluate without running:
tools/buck2 build '<test>.assembly[drv]'evaluates the same declared tree under the same restrictions and writes the derivation path, building no VM. To check every machine test's declared inputs, build[drv]for each target intools/buck2 uquery 'attrfilter(labels, machine_test_assembly, //...)'. This takes about 15 minutes at-j 24. - Run one:
tools/buck2 test //nix/verification/tests/machines/sysctl:sysctl. Buck2 builds the assembly (the VM run) first; the test command then checks that thenested_kvmlabel matches the check's required features and, for fleet variants, that the declared scenarios match the composed script. - Never edit the generated BUCK files. After changing
catalog.nixor a suite'srequiredFeatures, runpython3 buck/machine_tests.py generate. After changing which scenario files a fleet variant reads, runpython3 buck/machine_tests.py refresh-scenarios(evaluation only, a few minutes) and thengenerate.//buck:machine_tests_freshfails when they are stale. - Labels.
machine_testandnested_kvmcome from the macro.known_inception_failurekeeps Inception (known broken) out ofci.yml; the daily run reports it without failing. - CI.
ci.ymlruns on every trunk push and on dispatch: affected → build → test → one job per affected machine test. When everything is selected it leaves the machine tests to the daily run unless dispatched with-f machine_all=true. The daily backstop isnixos-machine-tests.yml; dispatch it withgh workflow run nixos-machine-tests.yml --ref trunk -f checks="a b".
Remote cache and execution (Namespace)
Namespace (namespace.so) is the Buck2 remote cache and remote-execution backend for developers, hosts and CI under one tenant token (ADR-0276). It replaced the fleet's NativeLink services (ADR-0272), which have been removed from the repository.
- How it turns on.
tools/buck2looks for a token inNAMESPACE_RBE_TOKEN, then/run/overalls-secrets/fleet-namespace/token(fleet hosts: root andwheel), then~/.config/overalls/namespace-rbe-token.json(bearer_token). With one, it writes the untracked.buck-remote.buckconfig(<file:tools/namespace.buckconfig>), which.buckconfigincludes optionally, and exports the token for buckd; the tracked config expands$NAMESPACE_RBE_TOKENin itshttp_headers. Without one, or withOVERALLS_BUCK2_REMOTE=off, it removes the include and builds stay local. Switching restarts the daemon. Namespace's addresses name the cluster's instances and change when Namespace recreates it; wherenscis logged in, the wrapper re-reads them hourly into the untracked.buck-remote.endpoints(delete it to force a re-read), otherwise the committed ones intools/namespace.buckconfigapply. A dead address (404 or no answer to a five-second probe, remembered in.buck-remote.probefor ten minutes) turns the cache off for the build instead of letting Buck2 retry forever. - Nested daemons. A test that runs
.buck-cells/bin/buck2itself sees the checkout's include but not the token (test environments do not carry it), and Buck2 then retries the connection for about 45 s. Pass-c buck2_re_client.engine_address= -c buck2_re_client.action_cache_address= -c buck2_re_client.cas_address= -c buck2_re_client.http_headers=, asbuck/tests/mix_test_failure_uncached.pydoes. - Never write the token into a file in the checkout, argv or the Nix
store.
tools/namespace-token-scanfails if thensrt_prefix appears in the include,buck-out/v2/logor~/.buck; CI runs it after each Buck2 job. - Who writes. Every token holder uploads.
default_allow_cache_upload = truesits in the root.buckconfig, because Buck2 ignores that key in an included file (it readfalsefrom the include and uploaded nothing until 2026-11-01); without a token there is no remote cache, so nothing uploads.local_onlyactions keepallow_cache_upload = False(rule 4). The host updater's.buckconfig.localkeepsremote_execution = falseand retries a failed build once withOVERALLS_BUCK2_REMOTE=off(update.namespace_cacheevent:enabledortoken_missing;update.remote_cachefallback). - CI. ci.yml's Buck2 jobs and nixos-machine-tests.yml set
NAMESPACE_RBE_TOKENfrom the repository secret; mila-builds.yml sets it only on the hermetic source-bundle job. Forks get no secret and build locally. - Rotation and revocation. See
secrets/README.md(nsc bazel create-token,overalls-secrets encrypt fleet-namespace --replace,nsc token revoke). - What runs remotely (
toolchains//:execution_platform, frombuck/platforms.bzl): Linux x86_64, with a cache configured,[nix] cells_idand[overalls] remote_execution = true. Remote execution is the default wherever a token and a matching worker image exist, on developer machines and in CI (the user's decision, 2026-11-01);OVERALLS_BUCK2_REMOTE_EXECUTION=offkeeps one build cache-only. Host deployments stay cache-only.tools/buck2sets[overalls] re_imagewhenevertools/namespace-re-image.locknames a worker image for the checkout'scells_id, so every action carriesoveralls-cells=<cells_id>andcontainer-image=docker://<image>@<digest>in its digest. Namespace starts 16x32 workers on demand inside the workspace's shared 64-vCPU cap and cannot bound or scale them to zero:nsc listshows them (bazel.purpose=worker) andnsc destroy <id> --forcefrees an idle one.local_onlyactions and test commands never go remote. A remote action that fails is retried locally (allow_hybrid_fallbacks_on_failure), so a real failure costs two runs and still fails. - Worker image.
tools/namespace-re-image --push(needsnsc login) builds the image from the buckCells closure without.drvfiles, plus/binlinks to coreutils, findutils, grep and sed, pushes it tonscr.io, runsnsc base-image optimize, and rewrites the lock..github/workflows/namespace-re-image.ymldoes this, and commits the lock, after every trunk change to the cells' inputs; until it lands, those cells build locally with the cache. Optimising starts a temporary 8x16 Namespace maintenance instance. - Checking. The build summary prints
Cache hits: N%andCommands: N (cached: C, remote: R, local: L). Force local withOVERALLS_BUCK2_REMOTE=offorbuck2 build --local-only.
Precommit
tools/precommit is the one precommit entry point: the devenv precommit
command, the single prek hook and CI call it.
- Scopes: the named files or the staged changes (default),
--base REV(merge-base to working tree),--all.--exclude-label LABELdrops checks carrying it (CI's precommit job dropsexpensive: themixjob runs the suites).--planprints the selection as JSON;--fixfirst copies each changed file'sfixsub-target output over it (the only mode that rewrites files). - How it selects (
buck/bxl/precommit.bxl): the universe is every target labelledprecommit. A check'sPrecommitInfo(buck/checks.bzl) says which paths it reads, which sub-targets check one file, which run beside them (shared) and which deleted paths matter. A check without the provider runs whole when an owner of a changed file is among its deps, or a deleted file is below its package. ABUCK,.bzl,.bxl,.buckconfig,toolchains/,nix/buck/,flake.lockor wrapper change selects every check, and unchanged ones are cache hits. Everything selected is onectx.build. - Fallback. When
tools/buck2 serverfails, or withOVERALLS_PRECOMMIT_DIRECT=1, the hook scripts run directly with the pinned tools devenv passes inOVERALLS_PRECOMMIT_*. The ADR, contract, package-input-lock and toolchain checks are then reported as skipped. - Mix projects. Each project's
:checkcarriesPrecommitInfo(contract mix-check-precommit): a changed test module selects[format]alone, top-level prose (*.md,CONTRACTS) selects nothing, and any other source change or a deletion runs the whole check. The:testshards have no provider yet, so a change in a project runs them (cache hits when unchanged). There are no[fix/<path>]sub-targets formix formatyet. CI runs the suites in ci.yml'smixjob and the checks in itsprecommitjob. There is nomix precommitalias any more: every gate it ran is a Buck2 check (ADR-0269 M8), including[unused_deps], diagnostics[schema], Marshall's[monospace]and[localization_*],//:marshall-browserand//:marshall-workspace-types.
Adding a check to precommit (the convention)
- Label the target
precommit(andcheck, sobuck2 testreads it). Never labelflake_outputassemblies or machine testsprecommit. - The default output runs the whole check and fails on any violation.
- Name sub-targets
[<kind>/<repo path>]for one file ([ruff/<path>],[contracts/<path>],[format/<path>]),[<kind>]for one part of the whole check ([ty],[format],[dialyzer],[logging],[gettext],[test_result],[covenant]), and[fix/<repo path>]for a fixed copy of one file.//:conflict-markers[<path>]predates the convention. - Return
PrecommitInfo(inputs, per_file, shared, fix, deletions)to get per-file selection. Leave a checker, configuration orCONTRACTSpath out ofper_file, so changing it runs the whole check. Without the provider, put the check in the package that owns its sources: precommit then runs its default output when those sources change. - Mix rules:
mix_checkandmix_testcarryprecommit.mix_check'sPrecommitInfomaps test modules to[format]; a check with an emptysharedruns whole on a matching deletion. Afix = {path: "fix/" + path}frommix formatwould giveprecommit --fixElixir formatting.
Host deployment targets
- Targets.
fleet/hosts/<host>/BUCKcallsfleet_host()frombuck/fleet.bzl. That declares:deployment(the enrolledoverallsDeploymentbundle the updater activates),:baseand:install.//nix/platform:kexecis the installer kexec. - Revision. Pass
-c overalls.revision=<full commit>so the system names its source. Without it, the system namesunknown(ADR-0271). - A new host directory needs its
BUCKfile and an entry in the rootOWNED_PACKAGES; otherwise its files are missing from the assembly tree. - The updater runs the candidate's own
tools/buck2 --isolation-dir overalls-updatein/var/lib/overalls-auto-update/checkout, withHOMEset to/var/lib/overalls-auto-update/buck2-homeandOVERALLS_GCROOT_DIRset to/var/lib/overalls-auto-update/gcroots. To inspect the updater's daemon on a host, use the same flags; never leave a daemon running there. - Updater machine tests build
nix/verification/tests/support/update-fixture.nixrepositories. Restricted evaluation refusespath:inputs, so fixturelib.assemblenames prebuilt candidates withbuiltins.storePath.
Elixir targets
Rules are in buck/mix.bzl; their contracts are in buck/CONTRACTS.
Per project. A project's
BUCKdeclares twomix_sourcestargets and callsoveralls_mix_project:release_srcsis the release source allowlist (contractrelease-source-allowlist); there is no Nix release any more;test_srcsholds the whole project plus its path dependencies.
The macro creates:
:compile(prod) and:compile_test;:test, whose[test_result]and[covenant]are subtargets;:check, with[format],[logging],[dialyzer](using[plt]) and, where the project has catalogues,[gettext];- for applications,
:release,:release_probeand:<app>_import(the release as a store path with itsself_reference, fornix_assemble(artifacts = …)).
:testand:checkcarry theprecommitlabel, and:testalso carriesexpensive. A failed shard fails its run action and prints every failed test plus the log tail, so no cache keeps it;[test_result]holds every shard's passing record.Shards.
test_shards = N(Marshall: 16) splits a suite into N cachedmix test <files>actions,[shard-1]…[shard-N], each with its own sandbox and PostgreSQL and only its own test files in its tree. One test file's change reruns one shard; a change underlib/reruns them all.- Unweighted files go to the shard their path hashes to (FNV-1a), so
adding a file moves no other file. Slow files listed in
test_shard_weights(seconds) go heaviest-first to the lightest shard. repository_testsprefixes (Marshall:test/architecture/) form a[repository]shard, the only one that seesrepository_support(root//:mix_repository), so a docs or ADR change reruns only it.[shard_plan]is a JSON map of shard -> files: build it to find which shard runs a test.test_schedulers(default 4) sets+S n:nand the action's local weight, so Buck2 never starts more scheduler threads than job slots.[covenant]checks the union of the shards' Covenant results.- Seeds. A cached shard keeps the ExUnit and Hegel draws of the run
that recorded it; the shard log has ExUnit's
Randomized with seed.tools/buck2 build -c mix.test_salt=$(date +%s) //marshall:testreruns every shard with fresh seeds. - Run one shard:
tools/buck2 build '//marshall:test[shard-3]'.
Libraries in
elixir/use a target prefix, for example//elixir:diagnostics_test.- Unweighted files go to the shard their path hashes to (FNV-1a), so
adding a file moves no other file. Slow files listed in
- Dependencies. Mix dependencies come from the
[mix]cells section.deps_<project>_prodanddeps_<project>_testare fixed-output fetches keyed independency-hashes.json.- A new project needs entries in
testDependencyProjectsinnix/domains/artifacts/default.nix, plus a hash. - To find a new hash, put a fake one in the registry, run
nix build --impure --expr '((builtins.getFlake (toString ./.)).lib.assemble { }).packages.testDependencies.<project>', and copy thegot:value.
Sandbox. Every Mix action runs in
buck/mix_sandbox.sh:- bubblewrap, no network, uid 1000;
/buildas the work directory, as in the Nix sandbox, because Mix and Spark embed absolute paths;- a writable overlay on
/nix/store.
Unprivileged user namespaces are required, so these actions are local only.
- Shell state. Actions source the
mixReleaseshell state captured frombeam.mixRelease(nix/buck/mix.nix). Releases therefore run the same hooks and compiler flags as the Nix build. - Self-reference. A release names itself as
/nix/store/00000000000000000000000000000000-overalls-<app>-0.1.0. Assembly rewrites that placeholder to its$out. The probe copies the release to that path inside a sandbox and runs it there. - Variants.
- Encrypted crash dumps and Antithesis builds are
select()s on//buck:encrypted_crash_dumpsand//buck:antithesis_*. Pick one with--target-platforms //buck:<variant>_platform. - Fixture releases are
release_variants, which take extrasrcs, apre_buildsource patch andpost_installlines.
- Encrypted crash dumps and Antithesis builds are
- Parity. To compare a release byte for byte with a Nix build, pass
-c mix.random_seed_<app>=<first 10 characters of the Nix output hash>. This makes stdenv's-frandom-seedmatch. Then compare the trees after replacing the Nix output path with the placeholder. Hermetic tests. Tests run offline:
- Hegel's NIF comes from
HEGEL_NIF_PATH(thehegelNifNix build); - LazyHTML's precompiled NIF is in the test fetch;
- Postgres runs on a socket under
/build/pgs.
Marshall's validator tests read the whole repository, so its
[repository]shard depends onroot//:mix_repository; the other shards and:checkdo not. Other suites get the defaulttest_support: the scripts helpers, Marshall's TLS fixtures and the protocol's test support and vectors. A suite that reads another file outside its project needs amix_sourcesfor it, or it fails withFile.Errorin the sandbox.- Hegel's NIF comes from
Troubleshooting
- Socket path too long (Chromium, Postgres).
buck-outpaths are deep. PointTMPDIRat a shortmktemp -d /tmp/…directory. - Go stamps VCS data or reads
.git. Build outside the checkout, asgo.bzldoes. cmdpaths inscript_check. They are relative to the project root, not to the package.nix_assemblefails with "access to absolute path … is forbidden in restricted mode" or "path … does not exist". The assembly read a file outside its declared tree. Add the owning group to the target'ssrcsorinputs(for machine tests, inbuck/inputs.bzlor the generator), never an--impureescape. Reproduce without building:tools/buck2 build '<target>[drv]'(machine tests:<test>.assembly[drv]).- A failed machine test.
tools/machine-test-log <target> <file>writes the full Nix build log;<test>.assembly[drv]names the exact derivation without building it. - "function is unavailable during analysis". Move the
read_root_configcall into a macro (rule 2). - "File not found … Included in X/BUCK". A glob matched a dangling symlink or a build directory. Add an ignore pattern, or remove the committed build output.
- "duplicate names" from a filegroup. Nested filegroups that share short
paths cannot be merged. Use
owned_setfrombuck/nix.bzl. - "[mix] … is missing".
.buck-cellspredates the Mix section; runtools/buck2once so it rebuilds the cells. - A Mix action fails with
bwrap: … Operation not permitted. The host has no unprivileged user namespaces; run the build where they are enabled. - Stale toolchain. Check that
readlink .buck-cellsmatchesnix build --print-out-paths .#buckCells.x86_64-linux, then runtools/buck2 kill. - Remote cache or execution errors. Rerun with
OVERALLS_BUCK2_REMOTE=offto confirm the build works locally, then check that the token has not expired or been revoked (nsc token list). - Bumping buck2. buck2 comes from
buildNixpkgs. Bumpflake.lock, rerun the spikes in the migration review, and expect every target to be selected. Updatetools/buck2-no-nix.jsonand thebuck2WindowsBinary,buck2LinuxBinaryandbuck2Preludepins in the same change;//tools:buck2-no-nix-linuxfails until they match. - A
non_hermetictarget is "incompatible". Pass-c overalls.non_hermetic=true, and build it on its own OS.
Verification
Run the changed targets, the ownership BXL and elixir scripts/check_adrs.exs
when records change. Buck2 success does not establish NixOS behaviour; that
needs machine tests.
Trending
Quiet since January.thin dataabout the whole repository
Who's talking about ghuntley/loom
- A Hacker News story“If your name is not Geoffrey Huntley then do not use loom”Hacker News · Jan 16, 2026 · 2 points
- daydemir/milhouse-go-legacy“Cross-Session Thread Loading & Replay (from Huntley Loom research)”GitHub · Jan 17, 2026
- daydemir/milhouse-go-legacy“Active System Verification Loops (from Huntley Loom research)”GitHub · Jan 17, 2026
- daydemir/milhouse-go-legacy“Meta-Loop Orchestration: Agents Spawning Sub-Loops (exploratory/major from Huntley Loom research)”GitHub · Jan 17, 2026
- daydemir/milhouse-go-legacy“Structured Audit Threads for Agent Decision Trails (from Huntley Loom research)”GitHub · Jan 17, 2026
The biggest 5 of 14 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 14
Talked about on GitHub and Hacker News (14 times).
On GitHub · 13
- Jan 17, 2026Cross-Session Thread Loading & Replay (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Active System Verification Loops (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Meta-Loop Orchestration: Agents Spawning Sub-Loops (exploratory/major from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Structured Audit Threads for Agent Decision Trails (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Server-Side LLM Proxy for Credential Isolation (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
8 more on GitHub
- Jan 17, 2026Secret Wrapper Type for Auto-Redacting (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Error Classification with Transient/Quota/Permanent (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Thread Persistence with UUID7 & Offline-First Sync (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Post-Tool Hook State for Auto-Commit (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Snippet-Based File Editing (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Proactive OAuth Token Refresh (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Multi-Account LLM Pool with Failover & Cooling (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
- Jan 17, 2026Explicit State Machine for Agent Orchestration (from Huntley Loom research) — daydemir/milhouse-go-legacy0 reactions
On Hacker News · 1
- Jan 16, 2026If your name is not Geoffrey Huntley then do not use loom2 points · 1 comment
In this repository31 other files it gives its agents.
- AGENTS.mdAGENTS.md
- antithesis/AGENTS.mdAGENTS.md
- lilly/AGENTS.mdAGENTS.md
- marshall/AGENTS.mdAGENTS.md
- mila/AGENTS.mdAGENTS.md
- protocol/AGENTS.mdAGENTS.md
- susan/AGENTS.mdAGENTS.md
- adr-maintenanceSkill
- antithesis-agent-browserSkill
- antithesis-debugSkill
- antithesis-documentationSkill
- antithesis-feature-workloadSkill
- antithesis-launchSkill
- antithesis-mutation-testingSkill
- antithesis-query-logsSkill
- antithesis-researchSkill
- antithesis-review-inputsSkill
- antithesis-setup-k8sSkill
- antithesis-setupSkill
- antithesis-skills-feedbackSkill
- antithesis-triageSkill
- antithesis-workloadSkill
- architecture-reviewSkill
- code-contractsSkill
- covenantSkill
- hegel-elixir-testsSkill
- localizationSkill
- monospace-webSkill
- nix-buildsSkill
- security-auditSkill
- test:triageSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

