refactor: examples folder standalone (#25)

diff --git a/.bazelignore b/.bazelignore
index 2559413..7bd5d5c 100644
--- a/.bazelignore
+++ b/.bazelignore
@@ -1 +1,2 @@
-e2e/
\ No newline at end of file
+e2e/
+examples/
diff --git a/.bazelrc b/.bazelrc
index 3c13c42..2d791cb 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -2,21 +2,6 @@
 # Take care to document any settings that you expect users to apply.
 # Settings that apply only to CI are in .github/workflows/ci.bazelrc
 
-# The main ingredient: allow us to register toolchains other than com_google_protobuf targets
-common --incompatible_enable_proto_toolchain_resolution
-common --@aspect_rules_py//py:interpreter_version=3.9.18
-
-# See https://github.com/bazelbuild/rules_python/issues/1069#issuecomment-1942053014
-common --action_env=RULES_PYTHON_ENABLE_PYSTAR=0
-
-# Don’t want to push a rules author to update their deps if not needed.
-# https://bazel.build/reference/command-line-reference#flag--check_direct_dependencies
-# https://bazelbuild.slack.com/archives/C014RARENH0/p1691158021917459?thread_ts=1691156601.420349&cid=C014RARENH0
-common --check_direct_dependencies=off
-
-# Force rules_go to disable CGO even though we have a (fake) C++ toolchain registered.
-common --host_platform=//:no_cgo_host_platform
-
 # Load any settings specific to the current user.
 # .bazelrc.user should appear in .gitignore so that settings are not shared with team members
 # This needs to be last statement in this
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 2d15f9e..e21346c 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -20,10 +20,11 @@
   test:
     uses: bazel-contrib/.github/.github/workflows/bazel.yaml@v6
     with:
-      folders: '[".", "e2e/smoke"]'
+      folders: '[".", "e2e/smoke", "examples"]'
       exclude: |
         [
           {"bazelversion": "6.4.0"},
           {"folder": ".", "bzlmodEnabled": false},
+          {"folder": "examples", "bzlmodEnabled": false},
           {"folder": ".", "os": "windows-latest"}
         ]
diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh
index e931644..be6752e 100755
--- a/.github/workflows/release_prep.sh
+++ b/.github/workflows/release_prep.sh
@@ -16,9 +16,9 @@
 SHA=$(shasum -a 256 $ARCHIVE | awk '{print $1}')
 
 cat << EOF
-## Using Bzlmod with Bazel 6
+## Using Bzlmod with Bazel 6 or later
 
-1. Enable with \`common --enable_bzlmod\` in \`.bazelrc\`.
+1. (Bazel 6 only) Enable with \`common --enable_bzlmod\` in \`.bazelrc\`.
 2. Add to your \`MODULE.bazel\` file:
 
 \`\`\`starlark
@@ -33,6 +33,9 @@
     # Pin to any version of protoc
     version = "v26.0",
 )
+use_repo(protoc, "com_google_protobuf", "toolchains_protoc_hub")
+
+register_toolchains("@toolchains_protoc_hub//:all")
 \`\`\`
 
 ## Using WORKSPACE
diff --git a/BUILD.bazel b/BUILD.bazel
index 60d5013..8400706 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -1,8 +1,7 @@
-load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS")
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
 
-platform(
-    name = "no_cgo_host_platform",
-    constraint_values = HOST_CONSTRAINTS + [
-        "@rules_go//go/toolchain:cgo_off",
-    ],
+# Placeholder until there are docs tests
+build_test(
+    name = "tautology",
+    targets = ["//:BUILD.bazel"],
 )
diff --git a/MODULE.bazel b/MODULE.bazel
index e65604e..940b2fb 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -11,43 +11,13 @@
 bazel_dep(name = "rules_proto", version = "6.0.0")
 bazel_dep(name = "platforms", version = "0.0.10")
 
-protoc = use_extension("//protoc:extensions.bzl", "protoc")
+bazel_dep(name = "aspect_bazel_lib", version = "2.8.1", dev_dependency = True)
+bazel_dep(name = "buildifier_prebuilt", version = "6.1.2", dev_dependency = True)
+
+protoc = use_extension("@toolchains_protoc//protoc:extensions.bzl", "protoc")
 protoc.toolchain(
-    google_protobuf = "com_google_protobuf",
     version = "v27.3",
 )
-use_repo(protoc, "com_google_protobuf", "toolchains_protoc_hub")
+use_repo(protoc, "toolchains_protoc_hub")
 
 register_toolchains("@toolchains_protoc_hub//:all")
-
-# Assert no CC compilation occurs
-register_toolchains(
-    "//tools/toolchains:all",
-    dev_dependency = True,
-)
-
-bazel_dep(name = "aspect_bazel_lib", version = "1.32.1", dev_dependency = True)
-bazel_dep(name = "buildifier_prebuilt", version = "6.1.2", dev_dependency = True)
-bazel_dep(name = "aspect_rules_py", version = "0.7.1", dev_dependency = True)
-bazel_dep(name = "rules_java", version = "7.4.0", dev_dependency = True)
-bazel_dep(name = "rules_python", version = "0.32.2", dev_dependency = True)
-bazel_dep(name = "rules_go", version = "0.48.0", dev_dependency = True)
-bazel_dep(name = "rules_uv", version = "0.10.0", dev_dependency = True)
-
-register_toolchains(
-    "//examples/lang_toolchains:all",
-    dev_dependency = True,
-)
-
-# Shows how a typical Python user fetches all the dependencies of their app, including the protobuf runtime
-dev_pip = use_extension(
-    "@rules_python//python/extensions:pip.bzl",
-    "pip",
-    dev_dependency = True,
-)
-dev_pip.parse(
-    hub_name = "pypi",
-    python_version = "3.11",
-    requirements_lock = "//examples/lang_toolchains:requirements.txt",
-)
-use_repo(dev_pip, "pypi")
diff --git a/README.md b/README.md
index e4deb90..c6be85c 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 - Nearly every Bazel user has waited for `protoc` to compile from sources many, MANY times.
   This universally slows down builds, especially due to issues like https://github.com/bazelbuild/bazel/issues/7095 where it is observed to be easily cache-busted.
 - The protobuf Bazel module is quite complex and maintenance and support from the protobuf team has been inconsistent.
-  By using pre-built artifacts, Bazel users can follow the same well-tested as users of other build systems.
+  By using pre-built artifacts, Bazel users can follow the same well-tested codepaths as users of other build systems.
 - Relying on the protobuf runtime for each language from the `@com_google_protobuf` repo forces you to use
   the same version of the runtime for all languages in a monorepo, and matching protoc.
   This makes it difficult to migrate to a monorepo, allowing some applications to move from their separate repo without
diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel
index 1633df2..53b52af 100644
--- a/WORKSPACE.bazel
+++ b/WORKSPACE.bazel
@@ -1,11 +1 @@
 # Marker that this is the root of a Bazel workspace.
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")
-
-# Note: this is simpler than using rules_jvm_external with a maven installation,
-# but users would probably get this JAR file that way.
-http_jar(
-    name = "protobuf-java",
-    sha256 = "0532ad1024d62361561acaedb974d7d16889e7670b36e23e9321dd6b9d334ef9",
-    urls = ["https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/4.27.0-RC3/protobuf-java-4.27.0-RC3.jar"],
-)
diff --git a/examples/.bazelrc b/examples/.bazelrc
new file mode 100644
index 0000000..7e8772b
--- /dev/null
+++ b/examples/.bazelrc
@@ -0,0 +1,9 @@
+# The main ingredient: allow us to register toolchains other than com_google_protobuf targets
+common --incompatible_enable_proto_toolchain_resolution
+common --@aspect_rules_py//py:interpreter_version=3.9.18
+
+# See https://github.com/bazelbuild/rules_python/issues/1069#issuecomment-1942053014
+common --action_env=RULES_PYTHON_ENABLE_PYSTAR=0
+
+# Force rules_go to disable CGO even though we have a (fake) C++ toolchain registered.
+common --host_platform=//tools:no_cgo_host_platform
diff --git a/examples/.bazelversion b/examples/.bazelversion
new file mode 100644
index 0000000..1502020
--- /dev/null
+++ b/examples/.bazelversion
@@ -0,0 +1 @@
+7.3.0
diff --git a/examples/BUILD b/examples/BUILD.bazel
similarity index 100%
rename from examples/BUILD
rename to examples/BUILD.bazel
diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel
new file mode 100644
index 0000000..8ce28f5
--- /dev/null
+++ b/examples/MODULE.bazel
@@ -0,0 +1,58 @@
+bazel_dep(name = "toolchains_protoc", version = "0.0.0")
+bazel_dep(name = "aspect_bazel_lib", version = "2.8.1")
+bazel_dep(name = "aspect_rules_py", version = "0.7.1")
+bazel_dep(name = "rules_java", version = "7.6.5")
+bazel_dep(name = "rules_proto", version = "6.0.0")
+bazel_dep(name = "rules_python", version = "0.32.2")
+bazel_dep(name = "rules_go", version = "0.48.0")
+bazel_dep(name = "rules_uv", version = "0.10.0")
+
+# This example is in the same repo with the ruleset, so we should point to the code at HEAD
+# rather than use any release on the Bazel Central Registry.
+local_path_override(
+    module_name = "toolchains_protoc",
+    path = "..",
+)
+
+####### PROTOBUF ##########
+protoc = use_extension("@toolchains_protoc//protoc:extensions.bzl", "protoc")
+protoc.toolchain(
+    google_protobuf = "com_google_protobuf",
+    # Demonstrate overriding the default version
+    version = "v28.0",
+)
+use_repo(protoc, "com_google_protobuf", "toolchains_protoc_hub")
+
+register_toolchains("@toolchains_protoc_hub//:all")
+
+register_toolchains("//tools/toolchains:all")
+
+####### PYTHON ##########
+# Shows how a typical Python user fetches all the dependencies of their app, including the protobuf runtime
+dev_pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
+dev_pip.parse(
+    hub_name = "pypi",
+    python_version = "3.11",
+    requirements_lock = "//tools:requirements.txt",
+)
+use_repo(dev_pip, "pypi")
+
+####### JAVA ##########
+# Note: this is simpler than using rules_jvm_external with a maven installation,
+# however it can cause version skew on the classpath if Coursier resolves a different version
+# from the constraint solution.
+# Users with a maven.install should instead do something like
+# maven.install(
+#     artifacts = [
+#         "com.google.protobuf:protobuf-java:4.27.1",
+#         "io.grpc:grpc-all:1.51.1",
+#     ],
+#     lock_file = "//:maven_install.json",
+# )
+http_jar = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")
+
+http_jar(
+    name = "protobuf-java",
+    sha256 = "0532ad1024d62361561acaedb974d7d16889e7670b36e23e9321dd6b9d334ef9",
+    urls = ["https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/4.27.0-RC3/protobuf-java-4.27.0-RC3.jar"],
+)
diff --git a/examples/WORKSPACE.bazel b/examples/WORKSPACE.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/WORKSPACE.bazel
diff --git a/examples/go/BUILD b/examples/go/BUILD
index 5777ee9..db2b107 100644
--- a/examples/go/BUILD
+++ b/examples/go/BUILD
@@ -3,5 +3,5 @@
 go_test(
     name = "foo_proto_test",
     srcs = ["foo_proto_test.go"],
-    deps = ["//examples:foo_go_proto"],
+    deps = ["//:foo_go_proto"],
 )
diff --git a/examples/java/BUILD b/examples/java/BUILD
index 43adca8..fe35ad5 100644
--- a/examples/java/BUILD
+++ b/examples/java/BUILD
@@ -3,7 +3,7 @@
     srcs = ["Main.java"],
     main_class = "Main",
     deps = [
-        "//examples:foo_java_proto",
+        "//:foo_java_proto",
         "@protobuf-java//jar",
     ],
 )
diff --git a/examples/lang_toolchains/BUILD b/examples/lang_toolchains/BUILD
deleted file mode 100644
index d72db69..0000000
--- a/examples/lang_toolchains/BUILD
+++ /dev/null
@@ -1,25 +0,0 @@
-load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain")
-load("@rules_uv//uv:pip.bzl", "pip_compile")
-
-pip_compile(
-    name = "generate_requirements_txt",
-    requirements_in = "requirements.in",
-    requirements_txt = "requirements.txt",
-)
-
-# Configure protoc to have the right arguments for generating Python stubs.
-proto_lang_toolchain(
-    name = "protoc_py_toolchain",
-    command_line = "--python_out=%s",
-    progress_message = "Generating Python proto_library %{label}",
-    runtime = "@pypi//protobuf",
-    toolchain_type = "@rules_python//python/proto:toolchain_type",
-)
-
-proto_lang_toolchain(
-    name = "protoc_java_toolchain",
-    command_line = "--java_out=%s",
-    progress_message = "Generating Java proto_library %{label}",
-    runtime = "@protobuf-java//jar",
-    toolchain_type = "@rules_java//java/proto:toolchain_type",
-)
diff --git a/examples/lang_toolchains/requirements.in b/examples/lang_toolchains/requirements.in
deleted file mode 100644
index ec5c8b1..0000000
--- a/examples/lang_toolchains/requirements.in
+++ /dev/null
@@ -1 +0,0 @@
-protobuf==5.27.3
diff --git a/examples/lang_toolchains/requirements.txt b/examples/lang_toolchains/requirements.txt
deleted file mode 100644
index a7ba71e..0000000
--- a/examples/lang_toolchains/requirements.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file was autogenerated by uv via the following command:
-#    bazel run @@//examples/lang_toolchains:generate_requirements_txt
---index-url https://pypi.org/simple
-
-protobuf==5.27.3 \
-    --hash=sha256:043853dcb55cc262bf2e116215ad43fa0859caab79bb0b2d31b708f128ece035 \
-    --hash=sha256:16ddf3f8c6c41e1e803da7abea17b1793a97ef079a912e42351eabb19b2cffe7 \
-    --hash=sha256:68248c60d53f6168f565a8c76dc58ba4fa2ade31c2d1ebdae6d80f969cdc2d4f \
-    --hash=sha256:82460903e640f2b7e34ee81a947fdaad89de796d324bcbc38ff5430bcdead82c \
-    --hash=sha256:8572c6533e544ebf6899c360e91d6bcbbee2549251643d32c52cf8a5de295ba5 \
-    --hash=sha256:a55c48f2a2092d8e213bd143474df33a6ae751b781dd1d1f4d953c128a415b25 \
-    --hash=sha256:af7c0b7cfbbb649ad26132e53faa348580f844d9ca46fd3ec7ca48a1ea5db8a1 \
-    --hash=sha256:b8a994fb3d1c11156e7d1e427186662b64694a62b55936b2b9348f0a7c6625ce \
-    --hash=sha256:c2a105c24f08b1e53d6c7ffe69cb09d0031512f0b72f812dd4005b8112dbe91e \
-    --hash=sha256:c84eee2c71ed83704f1afbf1a85c3171eab0fd1ade3b399b3fad0884cbcca8bf \
-    --hash=sha256:dcb307cd4ef8fec0cf52cb9105a03d06fbb5275ce6d84a6ae33bc6cf84e0a07b
-    # via -r examples/lang_toolchains/requirements.in
diff --git a/examples/python/BUILD b/examples/python/BUILD
index 89d9d95..a55aab0 100644
--- a/examples/python/BUILD
+++ b/examples/python/BUILD
@@ -1,5 +1,5 @@
 py_test(
     name = "message_test",
     srcs = ["message_test.py"],
-    deps = ["//examples:foo_py_proto"],
+    deps = ["//:foo_py_proto"],
 )
diff --git a/examples/python/message_test.py b/examples/python/message_test.py
index 431efa2..0ea0782 100644
--- a/examples/python/message_test.py
+++ b/examples/python/message_test.py
@@ -1,7 +1,7 @@
 import sys
 import unittest
 
-from examples import foo_pb2
+from _main import foo_pb2
 
 class TestCase(unittest.TestCase):
     def test_message(self):
diff --git a/examples/tools/BUILD.bazel b/examples/tools/BUILD.bazel
new file mode 100644
index 0000000..2a4a2f4
--- /dev/null
+++ b/examples/tools/BUILD.bazel
@@ -0,0 +1,18 @@
+load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS")
+load("@rules_uv//uv:pip.bzl", "pip_compile")
+
+pip_compile(
+    name = "generate_requirements_txt",
+    requirements_in = "requirements.in",
+    requirements_txt = "requirements.txt",
+)
+
+# Don't allow rules_go to compile the Go SDK with cgo enabled, as that
+# would cause a dependency on a functional C++ toolchain.
+# This value is referenced in the .bazelrc
+platform(
+    name = "no_cgo_host_platform",
+    constraint_values = HOST_CONSTRAINTS + [
+        "@rules_go//go/toolchain:cgo_off",
+    ],
+)
diff --git a/examples/tools/requirements.in b/examples/tools/requirements.in
new file mode 100644
index 0000000..07c7637
--- /dev/null
+++ b/examples/tools/requirements.in
@@ -0,0 +1 @@
+protobuf==5.28.0
diff --git a/examples/tools/requirements.txt b/examples/tools/requirements.txt
new file mode 100644
index 0000000..acd4713
--- /dev/null
+++ b/examples/tools/requirements.txt
@@ -0,0 +1,17 @@
+# This file was autogenerated by uv via the following command:
+#    bazel run @@//tools:generate_requirements_txt
+--index-url https://pypi.org/simple
+
+protobuf==5.28.0 \
+    --hash=sha256:018db9056b9d75eb93d12a9d35120f97a84d9a919bcab11ed56ad2d399d6e8dd \
+    --hash=sha256:510ed78cd0980f6d3218099e874714cdf0d8a95582e7b059b06cabad855ed0a0 \
+    --hash=sha256:532627e8fdd825cf8767a2d2b94d77e874d5ddb0adefb04b237f7cc296748681 \
+    --hash=sha256:6206afcb2d90181ae8722798dcb56dc76675ab67458ac24c0dd7d75d632ac9bd \
+    --hash=sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0 \
+    --hash=sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6 \
+    --hash=sha256:853db610214e77ee817ecf0514e0d1d052dff7f63a0c157aa6eabae98db8a8de \
+    --hash=sha256:d001a73c8bc2bf5b5c1360d59dd7573744e163b3607fa92788b7f3d5fefbd9a5 \
+    --hash=sha256:dde74af0fa774fa98892209992295adbfb91da3fa98c8f67a88afe8f5a349add \
+    --hash=sha256:dde9fcaa24e7a9654f4baf2a55250b13a5ea701493d904c54069776b99a8216b \
+    --hash=sha256:eef7a8a2f4318e2cb2dee8666d26e58eaf437c14788f3a2911d0c3da40405ae8
+    # via -r tools/requirements.in
diff --git a/examples/tools/toolchains/BUILD.bazel b/examples/tools/toolchains/BUILD.bazel
new file mode 100644
index 0000000..1febe31
--- /dev/null
+++ b/examples/tools/toolchains/BUILD.bazel
@@ -0,0 +1,55 @@
+"""Define a non-functional cc toolchain.
+
+To fail-fast in cases where we are forced to compile third-party C++ code,
+define a cc toolchain that doesn't work, by using 'false' as the compiler.
+See https://bazel.build/tutorials/ccp-toolchain-config
+"""
+
+load("defs.bzl", "cc_toolchain_config")
+load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain")
+
+# Configure protoc to have the right arguments for generating Python stubs.
+# NB: the protobuf team intends to remove --python_out and instead use a protoc plugin for Python stub emit.
+proto_lang_toolchain(
+    name = "protoc_py_toolchain",
+    command_line = "--python_out=%s",
+    progress_message = "Generating Python proto_library %{label}",
+    runtime = "@pypi//protobuf",
+    toolchain_type = "@rules_python//python/proto:toolchain_type",
+)
+
+# Same as above, but for Java
+proto_lang_toolchain(
+    name = "protoc_java_toolchain",
+    command_line = "--java_out=%s",
+    progress_message = "Generating Java proto_library %{label}",
+    runtime = "@protobuf-java//jar",
+    toolchain_type = "@rules_java//java/proto:toolchain_type",
+)
+
+################
+# Setup a non-functional C++ toolchain, so we're assured that no C++ compilation
+# will be expected for engineers working in our repo.
+# That's the critical guarantee of toolchains_protoc
+filegroup(name = "empty")
+
+cc_toolchain_config(name = "noop_toolchain_config")
+
+cc_toolchain(
+    name = "noop_toolchain",
+    all_files = ":empty",
+    compiler_files = ":empty",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 0,
+    toolchain_config = ":noop_toolchain_config",
+    toolchain_identifier = "noop-toolchain",
+)
+
+toolchain(
+    name = "cc_toolchain",
+    toolchain = ":noop_toolchain",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
diff --git a/tools/toolchains/defs.bzl b/examples/tools/toolchains/defs.bzl
similarity index 100%
rename from tools/toolchains/defs.bzl
rename to examples/tools/toolchains/defs.bzl
diff --git a/tools/toolchains/BUILD.bazel b/tools/toolchains/BUILD.bazel
deleted file mode 100644
index eecadd0..0000000
--- a/tools/toolchains/BUILD.bazel
+++ /dev/null
@@ -1,31 +0,0 @@
-"""Define a non-functional cc toolchain.
-
-To fail-fast in cases where we are forced to compile third-party C++ code,
-define a cc toolchain that doesn't work, by using 'false' as the compiler.
-See https://bazel.build/tutorials/ccp-toolchain-config
-"""
-
-load("defs.bzl", "cc_toolchain_config")
-
-filegroup(name = "empty")
-
-cc_toolchain_config(name = "noop_toolchain_config")
-
-cc_toolchain(
-    name = "noop_toolchain",
-    all_files = ":empty",
-    compiler_files = ":empty",
-    dwp_files = ":empty",
-    linker_files = ":empty",
-    objcopy_files = ":empty",
-    strip_files = ":empty",
-    supports_param_files = 0,
-    toolchain_config = ":noop_toolchain_config",
-    toolchain_identifier = "noop-toolchain",
-)
-
-toolchain(
-    name = "cc_toolchain",
-    toolchain = ":noop_toolchain",
-    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
-)