From 968e8fa9ff36f5b9e3fea29253bcf637d6593908 Mon Sep 17 00:00:00 2001
From: "promptless[bot]" <179508745+promptless[bot]@users.noreply.github.com>
Date: Sun, 19 Oct 2025 18:46:02 +0000
Subject: [PATCH 1/4] Documentation updates from Promptless
---
external/extension.mdx | 314 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 314 insertions(+)
create mode 100644 external/extension.mdx
diff --git a/external/extension.mdx b/external/extension.mdx
new file mode 100644
index 0000000..76ad493
--- /dev/null
+++ b/external/extension.mdx
@@ -0,0 +1,314 @@
+---
+title: 'Module extensions'
+---
+
+
+# Module extensions
+
+
+Module extensions allow users to extend the module system by reading input data
+from modules across the dependency graph, performing necessary logic to resolve
+dependencies, and finally creating repos by calling [repo
+rules](/external/repo). These extensions have capabilities similar to repo
+rules, which enables them to perform file I/O, send network requests, and so on.
+Among other things, they allow Bazel to interact with other package management
+systems while also respecting the dependency graph built out of Bazel modules.
+
+You can define module extensions in `.bzl` files, just like repo rules. They're
+not invoked directly; rather, each module specifies pieces of data called *tags*
+for extensions to read. Bazel runs module resolution before evaluating any
+extensions. The extension reads all the tags belonging to it across the entire
+dependency graph.
+
+## Extension usage
+
+Extensions are hosted in Bazel modules themselves. To use an extension in a
+module, first add a `bazel_dep` on the module hosting the extension, and then
+call the [`use_extension`](/rules/lib/globals/module#use_extension) built-in function
+to bring it into scope. Consider the following example — a snippet from a
+`MODULE.bazel` file to use the "maven" extension defined in the
+[`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external)
+module:
+
+```python
+bazel_dep(name = "rules_jvm_external", version = "4.5")
+maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
+```
+
+This binds the return value of `use_extension` to a variable, which allows the
+user to use dot-syntax to specify tags for the extension. The tags must follow
+the schema defined by the corresponding *tag classes* specified in the
+[extension definition](#extension_definition). For an example specifying some
+`maven.install` and `maven.artifact` tags:
+
+```python
+maven.install(artifacts = ["org.junit:junit:4.13.2"])
+maven.artifact(group = "com.google.guava",
+ artifact = "guava",
+ version = "27.0-jre",
+ exclusions = ["com.google.j2objc:j2objc-annotations"])
+```
+
+Use the [`use_repo`](/rules/lib/globals/module#use_repo) directive to bring repos
+generated by the extension into the scope of the current module.
+
+```python
+use_repo(maven, "maven")
+```
+
+Repos generated by an extension are part of its API. In this example, the
+"maven" module extension promises to generate a repo called `maven`. With the
+declaration above, the extension properly resolves labels such as
+`@maven//:org_junit_junit` to point to the repo generated by the "maven"
+extension.
+
+Note: Module extensions are evaluated lazily. This means that an extension will
+typically not be evaluated unless some module brings one of its repositories
+into scope using `use_repo` and that repository is referenced in a build. While
+testing a module extension, `bazel mod deps` can be useful as it
+unconditionally evaluates all module extensions.
+
+## Extension definition
+
+You can define module extensions similarly to [repo rules](/external/repo),
+using the [`module_extension`](/rules/lib/globals/bzl#module_extension)
+function. However, while repo rules have a number of attributes, module
+extensions have [`tag_class`es](/rules/lib/globals/bzl#tag_class), each of which
+has a number of attributes. The tag classes define schemas for tags used by this
+extension. For example, the "maven" extension above might be defined like this:
+
+```python
+# @rules_jvm_external//:extensions.bzl
+
+_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
+_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
+maven = module_extension(
+ implementation = _maven_impl,
+ tag_classes = {"install": _install, "artifact": _artifact},
+)
+```
+
+These declarations show that `maven.install` and `maven.artifact` tags can be
+specified using the specified attribute schema.
+
+The implementation function of module extensions are similar to those of repo
+rules, except that they get a [`module_ctx`](/rules/lib/builtins/module_ctx) object,
+which grants access to all modules using the extension and all pertinent tags.
+The implementation function then calls repo rules to generate repos.
+
+```python
+# @rules_jvm_external//:extensions.bzl
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") # a repo rule
+def _maven_impl(ctx):
+ # This is a fake implementation for demonstration purposes only
+
+ # collect artifacts from across the dependency graph
+ artifacts = []
+ for mod in ctx.modules:
+ for install in mod.tags.install:
+ artifacts += install.artifacts
+ artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]
+
+ # call out to the coursier CLI tool to resolve dependencies
+ output = ctx.execute(["coursier", "resolve", artifacts])
+ repo_attrs = _process_coursier_output(output)
+
+ # call repo rules to generate repos
+ for attrs in repo_attrs:
+ http_file(**attrs)
+ _generate_hub_repo(name = "maven", repo_attrs)
+```
+
+### Extension identity
+
+Module extensions are identified by the name and the `.bzl` file that appears
+in the call to `use_extension`. In the following example, the extension `maven`
+is identified by the `.bzl` file `@rules_jvm_external//:extension.bzl` and the
+name `maven`:
+
+```python
+maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
+```
+
+Re-exporting an extension from a different `.bzl` file gives it a new identity
+and if both versions of the extension are used in the transitive module graph,
+then they will be evaluated separately and will only see the tags associated
+with that particular identity.
+
+As an extension author you should make sure that users will only use your
+module extension from one single `.bzl` file.
+
+## Repository names and visibility
+
+Repos generated by extensions have canonical names in the form of `{{ ""
+}}module_repo_canonical_name{{ "" }}+{{ "" }}extension_name{{
+"" }}+`repo_name``. Note that the canonical name
+format is not an API you should depend on — it's subject to change at any time.
+
+This naming policy means that each extension has its own "repo namespace"; two
+distinct extensions can each define a repo with the same name without risking
+any clashes. It also means that `repository_ctx.name` reports the canonical name
+of the repo, which is *not* the same as the name specified in the repo rule
+call.
+
+Taking repos generated by module extensions into consideration, there are
+several repo visibility rules:
+
+* A Bazel module repo can see all repos introduced in its `MODULE.bazel` file
+ via [`bazel_dep`](/rules/lib/globals/module#bazel_dep) and
+ [`use_repo`](/rules/lib/globals/module#use_repo).
+* A repo generated by a module extension can see all repos visible to the
+ module that hosts the extension, *plus* all other repos generated by the
+ same module extension (using the names specified in the repo rule calls as
+ their apparent names).
+ * This might result in a conflict. If the module repo can see a repo with
+ the apparent name `foo`, and the extension generates a repo with the
+ specified name `foo`, then for all repos generated by that extension
+ `foo` refers to the former.
+* Similarly, in a module extension's implementation function, repos created
+ by the extension can refer to each other by their apparent names in
+ attributes, regardless of the order in which they are created.
+ * In case of a conflict with a repository visible to the module, labels
+ passed to repository rule attributes can be wrapped in a call to
+ [`Label`](/rules/lib/toplevel/attr#label) to ensure that they refer to
+ the repo visible to the module instead of the extension-generated repo
+ of the same name.
+
+### Overriding and injecting module extension repos
+
+The root module can use
+[`override_repo`](/rules/lib/globals/module#override_repo) and
+[`inject_repo`](/rules/lib/globals/module#inject_repo) to override or inject
+module extension repos.
+
+#### Example: Replacing `rules_java`'s `java_tools` with a vendored copy
+
+```python
+# MODULE.bazel
+local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository")
+local_repository(
+ name = "my_java_tools",
+ path = "vendor/java_tools",
+)
+
+bazel_dep(name = "rules_java", version = "7.11.1")
+java_toolchains = use_extension("@rules_java//java:extension.bzl", "toolchains")
+
+override_repo(java_toolchains, remote_java_tools = "my_java_tools")
+```
+
+#### Example: Patch a Go dependency to depend on `@zlib` instead of the system zlib
+
+```python
+# MODULE.bazel
+bazel_dep(name = "gazelle", version = "0.38.0")
+bazel_dep(name = "zlib", version = "1.3.1.bcr.3")
+
+go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
+go_deps.from_file(go_mod = "//:go.mod")
+go_deps.module_override(
+ patches = [
+ "//patches:my_module_zlib.patch",
+ ],
+ path = "example.com/my_module",
+)
+use_repo(go_deps, ...)
+
+inject_repo(go_deps, "zlib")
+```
+
+```diff
+# patches/my_module_zlib.patch
+--- a/BUILD.bazel
++++ b/BUILD.bazel
+@@ -1,6 +1,6 @@
+ go_binary(
+ name = "my_module",
+ importpath = "example.com/my_module",
+ srcs = ["my_module.go"],
+- copts = ["-lz"],
++ cdeps = ["@zlib"],
+ )
+```
+
+## Best practices
+
+This section describes best practices when writing extensions so they are
+straightforward to use, maintainable, and adapt well to changes over time.
+
+### Put each extension in a separate file
+
+When extensions are in a different files, it allows one extension to load
+repositories generated by another extension. Even if you don't use this
+functionality, it's best to put them in separate files in case you need it
+later. This is because the extension's identify is based on its file, so moving
+the extension into another file later changes your public API and is a backwards
+incompatible change for your users.
+
+### Specify reproducibility and use facts
+
+If your extension always defines the same repositories given the same inputs
+(extension tags, files it reads, etc.) and in particular doesn't rely on
+any [downloads](/rules/lib/builtins/module_ctx#download) that aren't guarded by
+a checksum, consider returning
+[`extension_metadata`](/rules/lib/builtins/module_ctx#extension_metadata) with
+`reproducible = True`. This allows Bazel to skip this extension when writing to
+the `MODULE.bazel` lockfile, which helps keep the lockfile small and reduces
+the chance of merge conflicts. Note that Bazel still caches the results of
+reproducible extensions in a way that persists across server restarts, so even
+a long-running extension can be marked as reproducible without a performance
+penalty.
+
+If your extension relies on effectively immutable data obtained from outside
+the build, most commonly from the network, but you don't have a checksum
+available to guard the download, consider using the `facts` parameter of
+[`extension_metadata`](/rules/lib/builtins/module_ctx#extension_metadata) to
+persistently record such data and thus allow your extension to become
+reproducible. `facts` is expected to be a dictionary with string keys and
+arbitrary JSON-like Starlark values that is always persisted in the lockfile and
+available to future evaluations of the extension via the
+[`facts`](/rules/lib/builtins/module_ctx#facts) field of `module_ctx`.
+
+`facts` are not invalidated even when the code of your module extension changes,
+so be prepared to handle the case where the structure of `facts` changes.
+Bazel also assumes that two different `facts` dicts produced by two different
+evaluations of the same extension can be shallowly merged (i.e., as if by using
+the `|` operator on two dicts). This is partially enforced by `module_ctx.facts`
+not supporting enumeration of its entries, just lookups by key.
+
+An example of using `facts` would be to record a mapping from version numbers of
+some SDK to the an object containing the download URL and checksum of that
+version. The first time the extension is evaluated, it can fetch this mapping
+from the network, but on later evaluations it can use the mapping from `facts`
+to avoid the network requests.
+
+### Specify dependence on operating system and architecture
+
+If your extension relies on the operating system or its architecture type,
+ensure to indicate this in the extension definition using the `os_dependent`
+and `arch_dependent` boolean attributes. This ensures that Bazel recognizes the
+need for re-evaluation if there are changes to either of them.
+
+Since this kind of dependence on the host makes it more difficult to maintain
+the lockfile entry for this extension, consider
+[marking the extension reproducible](#specify_reproducibility) if possible.
+
+### Only the root module should directly affect repository names
+
+Remember that when an extension creates repositories, they are created within
+the namespace of the extension. This means collisions can occur if different
+modules use the same extension and end up creating a repository with the same
+name. This often manifests as a module extension's `tag_class` having a `name`
+argument that is passed as a repository rule's `name` value.
+
+For example, say the root module, `A`, depends on module `B`. Both modules
+depend on module `mylang`. If both `A` and `B` call
+`mylang.toolchain(name="foo")`, they will both try to create a repository named
+`foo` within the `mylang` module and an error will occur.
+
+To avoid this, either remove the ability to set the repository name directly,
+or only allow the root module to do so. It's OK to allow the root module this
+ability because nothing will depend on it, so it doesn't have to worry about
+another module creating a conflicting name.
+
From 0914e0d18195897b26b217939842853d0820d8c8 Mon Sep 17 00:00:00 2001
From: "promptless[bot]" <179508745+promptless[bot]@users.noreply.github.com>
Date: Sun, 19 Oct 2025 19:08:19 +0000
Subject: [PATCH 2/4] Sync documentation updates from Promptless agent
---
docs.json | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/docs.json b/docs.json
index b79de5b..9934f36 100644
--- a/docs.json
+++ b/docs.json
@@ -229,6 +229,15 @@
"rules/lib/overview",
"rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "external/extension",
+ "external/module",
+ "external/lockfile",
+ "external/repo"
+ ]
}
]
},
@@ -254,6 +263,7 @@
{
"group": "Programs",
"pages": [
+ "community/update",
"community/sig",
"community/experts",
"community/partners",
@@ -499,6 +509,14 @@
"8.4.2/rules/lib/overview",
"8.4.2/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "8.4.2/external/advanced",
+ "8.4.2/external/module",
+ "8.4.2/external/lockfile"
+ ]
}
]
},
@@ -524,6 +542,7 @@
{
"group": "Programs",
"pages": [
+ "8.4.2/community/update",
"8.4.2/community/sig",
"8.4.2/community/experts",
"8.4.2/community/partners",
@@ -769,6 +788,14 @@
"8.3.1/rules/lib/overview",
"8.3.1/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "8.3.1/external/advanced",
+ "8.3.1/external/module",
+ "8.3.1/external/lockfile"
+ ]
}
]
},
@@ -794,6 +821,7 @@
{
"group": "Programs",
"pages": [
+ "8.3.1/community/update",
"8.3.1/community/sig",
"8.3.1/community/experts",
"8.3.1/community/partners",
@@ -1039,6 +1067,14 @@
"8.2.1/rules/lib/overview",
"8.2.1/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "8.2.1/external/advanced",
+ "8.2.1/external/module",
+ "8.2.1/external/lockfile"
+ ]
}
]
},
@@ -1064,6 +1100,7 @@
{
"group": "Programs",
"pages": [
+ "8.2.1/community/update",
"8.2.1/community/sig",
"8.2.1/community/experts",
"8.2.1/community/partners",
@@ -1309,6 +1346,14 @@
"8.1.1/rules/lib/overview",
"8.1.1/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "8.1.1/external/advanced",
+ "8.1.1/external/module",
+ "8.1.1/external/lockfile"
+ ]
}
]
},
@@ -1334,6 +1379,7 @@
{
"group": "Programs",
"pages": [
+ "8.1.1/community/update",
"8.1.1/community/sig",
"8.1.1/community/experts",
"8.1.1/community/partners",
@@ -1579,6 +1625,14 @@
"8.0.1/rules/lib/overview",
"8.0.1/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "8.0.1/external/advanced",
+ "8.0.1/external/module",
+ "8.0.1/external/lockfile"
+ ]
}
]
},
@@ -1604,6 +1658,7 @@
{
"group": "Programs",
"pages": [
+ "8.0.1/community/update",
"8.0.1/community/sig",
"8.0.1/community/experts",
"8.0.1/community/partners",
@@ -1849,6 +1904,14 @@
"7.6.2/rules/lib/overview",
"7.6.2/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "7.6.1/external/advanced",
+ "7.6.1/external/module",
+ "7.6.1/external/lockfile"
+ ]
}
]
},
@@ -1874,6 +1937,7 @@
{
"group": "Programs",
"pages": [
+ "7.6.2/community/update",
"7.6.2/community/sig",
"7.6.2/community/experts",
"7.6.2/community/partners",
@@ -2119,6 +2183,14 @@
"6.5.0/rules/lib/overview",
"6.5.0/rules/lib/globals"
]
+ },
+ {
+ "group": "External dependencies",
+ "pages": [
+ "6.5.0/external/advanced",
+ "6.5.0/external/module",
+ "6.5.0/external/lockfile"
+ ]
}
]
},
@@ -2144,6 +2216,7 @@
{
"group": "Programs",
"pages": [
+ "6.5.0/community/update",
"6.5.0/community/sig",
"6.5.0/community/experts",
"6.5.0/community/partners",
@@ -2414,6 +2487,7 @@
{
"group": "Programs",
"pages": [
+ "5.4.1/community/update",
"5.4.1/community/sig",
"5.4.1/community/experts",
"5.4.1/community/partners",
@@ -2549,4 +2623,4 @@
}
]
}
-}
+}
\ No newline at end of file
From 92e29ebecb85ddde08a5657c1d54d0ef88b12a42 Mon Sep 17 00:00:00 2001
From: "promptless[bot]" <179508745+promptless[bot]@users.noreply.github.com>
Date: Sun, 19 Oct 2025 19:19:43 +0000
Subject: [PATCH 3/4] Sync documentation updates from Promptless agent
---
docs.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs.json b/docs.json
index 9934f36..84b2dbb 100644
--- a/docs.json
+++ b/docs.json
@@ -2623,4 +2623,4 @@
}
]
}
-}
\ No newline at end of file
+}
From 8b3b1cc38956af294113e34b32ffa8d7461ecb9f Mon Sep 17 00:00:00 2001
From: "promptless[bot]" <179508745+promptless[bot]@users.noreply.github.com>
Date: Sun, 19 Oct 2025 19:33:58 +0000
Subject: [PATCH 4/4] Sync documentation updates from Promptless agent
---
external/extension.mdx | 4 ----
1 file changed, 4 deletions(-)
diff --git a/external/extension.mdx b/external/extension.mdx
index 76ad493..b320e82 100644
--- a/external/extension.mdx
+++ b/external/extension.mdx
@@ -2,10 +2,6 @@
title: 'Module extensions'
---
-
-# Module extensions
-
-
Module extensions allow users to extend the module system by reading input data
from modules across the dependency graph, performing necessary logic to resolve
dependencies, and finally creating repos by calling [repo