We welcome contributions to the rules_wasm_component project! This document provides guidelines for contributing.
- Bazel 7.0+ with bzlmod support
- Rust 1.75+ with WASM targets
The Nix flake below provides all of these pinned — see the next section.
A Nix flake pins the host environment Bazel runs inside — Bazel itself
(via .bazelversion), a C/C++ compiler, git, python, and a host Rust
toolchain. The WebAssembly toolchains are still fetched hermetically by
Bazel; Nix only guarantees an identical environment around it.
nix develop # enter the dev shell with everything pinned
bazel build //... # WASM toolchains download automaticallyflake.lock pins the exact dependency revisions, so every developer, CI
runner, and qualification environment gets an identical toolchain. The Nix
CI workflow verifies that bazel build succeeds inside the dev shell.
# Clone the repository
git clone https://github.com/pulseengine/rules_wasm_component.git
cd rules_wasm_component
# Install Rust and WASM targets
rustup target add wasm32-wasip2 wasm32-wasip1 wasm32-unknown-unknown
# Verify setup - all tools downloaded automatically by Bazel
bazel build //...
bazel test //...Note: All WASM tools (
wasm-tools,wac-cli,wit-bindgen-cli, etc.) are now downloaded automatically by Bazel for truly hermetic builds. No manual installation required!
- Starlark: Follow Starlark style guide
- Documentation: All public rules must have comprehensive docstrings
- Examples: Add examples for new features
- Tests: Include tests for new functionality
# Format all files
bazel run //:buildifier
# Check formatting
bazel run //:buildifier -- --mode=check# Run all tests
bazel test //...
# Test specific area
bazel test //wit/...
bazel test //rust/...
bazel test //wac/...
# Integration tests
bazel test //examples/...git checkout -b feature/my-new-feature- Add rule implementation in appropriate directory
- Update providers if needed for new data
- Add BUILD.bazel files for new packages
- Write comprehensive documentation
# Example test structure
my_feature/
├── BUILD.bazel # Test targets
├── my_feature.bzl # Implementation
├── my_feature_test.bzl # Unit tests
└── test_data/ # Test fixtures# Add example usage
examples/my_feature/
├── BUILD.bazel
├── src/
└── README.md- Rule reference in
docs/rules.md - Migration guide if changing existing APIs
- README.md for major features
# Good: Clear field documentation
MyInfo = provider(
doc = "Information about my feature",
fields = {
"my_field": "Description of what this field contains",
"my_list": "List of items with specific purpose",
},
)
# Bad: Unclear or missing documentation
MyInfo = provider(fields = {"stuff": "some stuff"})def _my_rule_impl(ctx):
"""Implementation with clear documentation"""
# Validate inputs
if not ctx.files.srcs:
fail("srcs cannot be empty")
# Get toolchain
toolchain = ctx.toolchains["@rules_wasm_component//toolchains:my_toolchain_type"]
# Declare outputs
output = ctx.actions.declare_file(ctx.label.name + ".out")
# Run action
ctx.actions.run(
executable = toolchain.my_tool,
arguments = [args],
inputs = inputs,
outputs = [output],
mnemonic = "MyAction",
progress_message = "Processing %s" % ctx.label,
)
return [DefaultInfo(files = depset([output]))]
my_rule = rule(
implementation = _my_rule_impl,
attrs = {
"srcs": attr.label_list(
allow_files = [".my_ext"],
mandatory = True,
doc = "Source files to process",
),
},
toolchains = ["@rules_wasm_component//toolchains:my_toolchain_type"],
doc = """
Processes my files into output format.
This rule takes source files and processes them using my_tool.
Example:
my_rule(
name = "process_files",
srcs = ["file1.my_ext", "file2.my_ext"],
)
""",
)# Good: Clear error messages
if not ctx.files.srcs:
fail("my_rule requires at least one source file in 'srcs'")
if ctx.attr.profile not in ["debug", "release"]:
fail("profile must be 'debug' or 'release', got: %s" % ctx.attr.profile)
# Bad: Unclear errors
fail("invalid input")
fail("error")# my_rule_test.bzl
load("@bazel_skylib//lib:unittest.bzl", "unittest")
load(":my_rule.bzl", "my_rule")
def _my_rule_test_impl(ctx):
env = unittest.begin(ctx)
# Test successful case
# ... test implementation
return unittest.end(env)
my_rule_test = unittest.make(_my_rule_test_impl)
def my_rule_test_suite():
unittest.suite(
"my_rule_tests",
my_rule_test,
)# BUILD.bazel
load(":my_rule.bzl", "my_rule")
my_rule(
name = "test_basic",
srcs = ["test_input.txt"],
)
sh_test(
name = "integration_test",
srcs = ["integration_test.sh"],
data = [":test_basic"],
)my_rule = rule(
# ... implementation
doc = """
One-line summary of what the rule does.
Longer description explaining the purpose, behavior,
and any important details about the rule.
Example:
my_rule(
name = "example",
srcs = ["file.txt"],
options = ["--verbose"],
)
Args:
name: Target name
srcs: Source files to process
options: Additional command-line options
""",
)- All public rules must have comprehensive docstrings
- Attributes must be documented with clear descriptions
- Examples should show realistic usage patterns
- Cross-references to related rules and providers
- Fork the repository
- Create feature branch from
main - Implement changes following guidelines
- Add tests for new functionality
- Update documentation as needed
- Submit pull request with clear description
- ✅ All tests pass
- ✅ Code is formatted (buildifier)
- ✅ Documentation is updated
- ✅ Examples work correctly
- ✅ No breaking changes (or clearly documented)
- Automated checks must pass
- Code review by maintainers
- Address feedback and update PR
- Final approval and merge
- Semantic versioning:
MAJOR.MINOR.PATCH - Breaking changes: Increment MAJOR
- New features: Increment MINOR
- Bug fixes: Increment PATCH
- Update version in
MODULE.bazel - Update
CHANGELOG.md - Tag release:
git tag v1.2.3 - Update documentation
- Announce release
Tool binaries (wasm-tools, wit-bindgen, wac, wasmtime, wasi-sdk, nodejs, tinygo,
wkg, and the PulseEngine tools loom / wsc / file-ops-component) are pinned by
SHA256 in checksums/tools/*.json. The Bazel toolchains resolve each tool's
version and download URL from that JSON registry — there is no separate
version pin in MODULE.bazel for registry-managed tools, so the registry's
latest_version field is the pin.
Do not hand-edit checksums. Use the checksum_updater, which downloads each
platform asset, computes and verifies the SHA256, and writes the registry block:
cd tools/checksum_updater
cargo build --release
BIN=./target/release/checksum_updater
# See what would change for every tool, without writing (recommended first step)
$BIN update-all --dry-run
# Update one or more specific tools
$BIN update --tools wsc,wit-bindgen --dry-run # preview
$BIN update --tools wsc # apply
# Re-download and verify the SHAs already recorded (no version change)
$BIN validate --all
# Higher GitHub rate limits
GITHUB_TOKEN=$(gh auth token) $BIN update-all --dry-runEach tool is registered in tools/checksum_updater/src/tool_config.rs with a
UrlPattern matching its release-asset layout:
StandardTarball/SingleBinary— per-OS archives or bare binaries with a single extension across platforms.PerPlatformAsset— per-OS assets with mixed extensions (e.g. bare unix binaries vs.exe/.zipon Windows). Used by wasmtime, wit-bindgen, and wsc.UniversalWasm— a single platform-independent.wasmasset (loom ≤0.3.0, file-ops-component). Pair withVersionFilter::AssetExistswhen newer releases stop shipping the expected asset, so the updater holds at the last good version instead of failing.
To add a tool, add an entry to ToolConfig::new() (the default-config fallback
guesses bytecodealliance/<tool>, which is rarely right for PulseEngine tools).
Signing-path tools. wsc (
pulseengine/sigil) is the signing toolchain. Bumping it changes how components are signed — run a signing build/test and get a maintainer review before merging a wsc version bump, even though the updater can produce the registry change mechanically.
- Issues: GitHub issues for bugs and feature requests
- Discussions: GitHub discussions for questions
- Email: maintainers@rules-wasm-component.dev
- Toolchain not found: Ensure WASM tools are installed
- Build failures: Check Rust and Bazel versions
- Test failures: Run
bazel cleanand retry
rules_wasm_component/
├── BUILD.bazel # Root build file
├── MODULE.bazel # Bazel module definition
├── README.md # Project overview
├── CONTRIBUTING.md # This file
├── wit/ # WIT-related rules
├── rust/ # Rust WASM component rules
├── wac/ # WAC composition rules
├── wasm/ # General WASM utilities
├── toolchains/ # Toolchain definitions
├── providers/ # Provider definitions
├── common/ # Common utilities
├── examples/ # Usage examples
├── docs/ # Documentation
└── .github/ # CI/CD workflows
Thank you for contributing to rules_wasm_component! 🎉