Skip to content

Repository files navigation

Proto WASM Plugins

Linux macOS Windows License: MIT GitHub downloads

A collection of proto WASM plugins for managing CLI tools. Requires proto >= 0.57 / moon v2.

Plugins

Tool Description Plugin Latest
Gitleaks Secret scanner for git repos gitleaks_tool release
jq JSON processor jq_tool release
just Command runner just_tool release
lefthook Git hook manager lefthook_tool release
Maestro Mobile & web UI testing (requires Java) maestro_tool release
ripwire Code map and change checker for coding agents (macOS/Linux only) ripwire_tool release
sfw Socket Firewall Free, a network security proxy for package managers sfw_tool release
V V compiler; weekly tags without a release build from source on opt-in (macOS/Linux only, see V) v_tool release
yq YAML/JSON/XML processor yq_tool release

Usage

Add the plugin to your .prototools:

[plugins]
gitleaks = "github://muuvmuuv/proto-plugins/gitleaks_tool"
jq = "github://muuvmuuv/proto-plugins/jq_tool"
just = "github://muuvmuuv/proto-plugins/just_tool"
lefthook = "github://muuvmuuv/proto-plugins/lefthook_tool"
maestro = "github://muuvmuuv/proto-plugins/maestro_tool"
ripwire = "github://muuvmuuv/proto-plugins/ripwire_tool"
sfw = "github://muuvmuuv/proto-plugins/sfw_tool"
v = "github://muuvmuuv/proto-plugins/v_tool"
yq = "github://muuvmuuv/proto-plugins/yq_tool"

Then install:

proto install gitleaks
proto install just
proto install lefthook

Direct download links

The github:// locator requires proto to query the GitHub API to resolve plugin versions. In CI environments without authentication, this can fail due to rate limiting (60 requests/hour for unauthenticated requests).

To avoid this, you can reference the WASM files directly by URL:

[plugins]
gitleaks = "https://github.com/muuvmuuv/proto-plugins/releases/download/gitleaks_tool-v0.3.1/gitleaks_tool.wasm"
jq = "https://github.com/muuvmuuv/proto-plugins/releases/download/jq_tool-v0.3.1/jq_tool.wasm"
just = "https://github.com/muuvmuuv/proto-plugins/releases/download/just_tool-v0.3.1/just_tool.wasm"
lefthook = "https://github.com/muuvmuuv/proto-plugins/releases/download/lefthook_tool-v0.2.1/lefthook_tool.wasm"
maestro = "https://github.com/muuvmuuv/proto-plugins/releases/download/maestro_tool-v0.2.1/maestro_tool.wasm"
ripwire = "https://github.com/muuvmuuv/proto-plugins/releases/download/ripwire_tool-v0.1.1/ripwire_tool.wasm"
sfw = "https://github.com/muuvmuuv/proto-plugins/releases/download/sfw_tool-v0.2.1/sfw_tool.wasm"
v = "https://github.com/muuvmuuv/proto-plugins/releases/download/v_tool-v0.1.2/v_tool.wasm"
yq = "https://github.com/muuvmuuv/proto-plugins/releases/download/yq_tool-v0.4.1/yq_tool.wasm"

This downloads the WASM file directly without any GitHub API calls for plugin resolution. Note that you will need to update the URLs manually when upgrading plugin versions.

Tip

If you prefer the github:// locator, set the GITHUB_TOKEN environment variable in CI to get 5,000 requests/hour instead of 60. This also benefits the plugins themselves, which call the GitHub API to resolve tool versions.

V

V's release tags (0.5.2, and 0.5 for a minor release) and its weekly tags both install. proto versions must be semantic, so weekly.2026.41 is an alias of version 2026.41.0, and latest is the newest release, never a weekly tag:

v = "weekly.2026.41"

[plugins]
v = "github://muuvmuuv/proto-plugins/v_tool"

[tools.v]
build-from-source = true

[env]
V_MACOS_V3_NO_FALLBACK = "1"

A tag with a GitHub release installs its archive. A tag without one can only be built from source, which runs the plugin's build script with the host's tools, so it fails unless [tools.v] sets build-from-source = true. With it, the tag builds in about 90 seconds into V's own Git checkout at the tag. That tree is bootstrapped from the vlang/vc snapshot of the newest v commit the tag contains, and V's make local=1 builds it with the system cc. The build needs git, make, cc and ar, and downloads only the two repositories, no tcc. So that plain (non -prod) builds link without tcc's bundle, the plugin builds its Boehm GC archive from V's bundled sources. The resulting v lacks the FastC backend (-b fastc), which needs tcc's libtcc.a.

Recent weekly tags compile with V3, V's new compiler. When the C that V3 generates fails to compile, V silently compiles again with V 0.5.2, which it downloads from GitHub when it is missing, so a build "on the weekly" can be a 0.5.2 build. V_MACOS_V3_NO_FALLBACK=1, despite its name on every OS, turns that retry off, and a failed V3 build then fails. The v shim sets it, and the [env] entry above extends it to proto run and shells using proto activate. Calling ~/.proto/bin/v directly bypasses both, so export it there yourself. At weekly.2026.41, V3 still rejects or miscompiles some code that 0.5.2 builds, and on Linux it cannot link any program with cc, as its unused-code pruning drops array__get, so installing that tag fails there.

The lockfile checksum of a source build is the SHA-256 of the line <v commit> <vc commit>, so a moved tag or a different bootstrap fails the next install. It is never the hash of a download. The release lookup uses the GitHub API; set GITHUB_TOKEN in CI to avoid its limit of 60 requests an hour. Musl and Windows are not supported.

Development

Prerequisites

  • Rust (toolchain is pinned in rust-toolchain.toml)
  • proto

Setup

Clone the repo and run:

just setup

This will:

  1. Install the Rust toolchain and wasm32-wasip1 target (via rust-toolchain.toml)
  2. Build all WASM plugins in release mode (needed for .prototools to resolve local file:// plugins; rerun just build-release to try a plugin change in your shell)
  3. Install pinned tool versions via proto use
  4. Install lefthook git hooks

Commands

Command Description
just setup Initial project setup
just build Build all WASM plugins
just test Build and run all tests
just test-tool <name> Test a single plugin (e.g. just test-tool jq)
just check Type-check without building
just fmt Format code
just lint Run clippy lints

Git hooks

Lefthook is configured to run automatically:

  • pre-commit: just lint (clippy)
  • pre-push: just check (fast compile check)

Tests are not hooked. They download ~900MB of real release artifacts per run — maestro.zip is 300MB and two tests fetch it independently — so they run in CI on every push and pull request instead.

Testing

Every plugin has integration tests that verify version resolution, archive download, checksum verification, and tool installation. Run them with:

just test

Tests compile the plugin to WASM first, then execute it inside a sandboxed proto environment that downloads real release artifacts. All tests run in CI on every push and pull request.

Checksum verification

Most plugins verify download integrity using SHA-256 checksums. Some tools require special handling:

  • jq, just, gitleaks, lefthook, maestro -- standard sha256sum.txt format, handled natively by proto
  • ripwire -- one standard <asset>.sha256 file per release asset, handled natively by proto
  • yq -- publishes a non-standard multi-hash checksums file (30+ algorithms per line); the plugin fetches and parses it during download to extract the SHA-256 hash
  • sfw -- upstream publishes no checksum file, so the plugin relies on HTTPS to github.com for integrity
  • v -- no checksum file either; the plugin verifies each release archive against the SHA-256 digest GitHub publishes for it in the Releases API. Archives uploaded before GitHub computed digests (V 0.4.x and older) have none, so proto hashes the download into its lockfile instead. Source builds are checked by Git's object hashes and pinned in the lockfile, see V

Adding a new plugin

  1. Create a new crate: mkdir -p tools/<name>/src
  2. Add Cargo.toml (use an existing plugin as a template)
  3. Implement the required plugin functions in src/lib.rs:
    • register_tool -- plugin metadata
    • load_versions -- fetch available versions (usually via load_git_tags)
    • download_prebuilt -- download URL, archive name, and checksum URL
    • locate_executables -- path to the executable within the install directory
  4. Add tests using the generate_download_install_tests! and generate_resolve_versions_tests! macros
  5. Add an entry to .prototools for local development
  6. Run just test-tool <name> to verify

Release

Tag the crate you want to release and push:

git tag <name>_tool-v<version>
git push origin main <name>_tool-v<version>

The GitHub Actions workflow will build the WASM binary, optimize it, and create a release with the .wasm asset attached.

Important

Push at most three tags per git push. GitHub creates no push events at all when more than three tags arrive at once, so git push --tags after a workspace-wide bump lands every tag on the remote and builds nothing. The failure is silent: no workflow run, no release, no error. Recovering means deleting the remote tags and re-pushing in batches, because re-pushing a tag the remote already has is a no-op that fires no event either.

FAQ

Tests fail with MissingToolExecutable

The file that locate_executables declares as the executable must actually exist in the install dir after install. If the upstream release asset is a platform-suffixed binary (e.g. yq_darwin_arm64), you have two options:

  1. Preferred: if the project also publishes a raw single-file binary, download that instead of the archive and name it after the tool. proto's non-archive install path automatically copies it to <install_dir>/<tool>. (This is what yq_tool does.)
  2. Implement the unpack_archive hook to extract the archive and rename the binary yourself.

Do not rely on the PDK's post_install hook for this — as of proto_core 0.55/0.56 it is declared but never invoked by the core.

which <tool> resolves to ~/.proto/shims/<tool> and complex args break

proto activate adds a tool's install dir to PATH only when the dir contains a file whose name matches the tool id. If the extracted binary has a platform-suffix (e.g. yq_darwin_arm64), activate skips the install dir and invocations fall through to ~/.proto/shims/<tool>. The proto-shim binary in proto ≤ 0.56.x routes commands via bash -c <flattened-string>, which mangles shell-special characters like ( ), |, |=, ' in arguments:

bash: -c: line 0: syntax error near unexpected token `('

Fix it on the plugin side by making the install dir contain a tool-named file (see the MissingToolExecutable answer above). Do not try to work around it in user code.

After changing download_prebuilt, installs fail with mismatched_checksum

proto persists the download URL and checksum for each installed version in ~/.proto/tools/<tool>/manifest.json (the "lockfile"). Upgrading a plugin that changes the URL or checksum format does not invalidate this file, so the next install compares the fresh download against a stale expected hash. Users need to proto uninstall <tool> <ver> followed by proto install <tool> <ver> once per installed version.

Installs fail with missing field ... after a proto upgrade

proto sends plugin function input as JSON that the PDK deserializes into structs, so removing or adding a required context field is a breaking change on both sides. A plugin built against a PDK older than the running proto fails with missing field <name> (proto 0.60 dropped tool_dir, which older PDKs require); a plugin built against a newer PDK than the running proto fails the same way in reverse (proto 0.55 predates working_dir). Either way the message names the field, not the version mismatch.

The fix is always to bump proto_pdk, proto_pdk_api, and proto_pdk_test_utils in the workspace Cargo.toml, rebuild, and re-release every plugin — they share the PDK, so they break together. Keep minimum_proto_version in register_tool honest with the oldest proto the current PDK still talks to.

Tests fail with assertion failed: shim.path.exists()

Proto needs to find the proto-shim binary to create shims. If you installed proto via Homebrew, the shim binary is in /opt/homebrew/bin/ instead of ~/.proto/bin/. The justfile handles this automatically via PROTO_LOOKUP_DIR. Always run tests through just test instead of cargo test directly.

Tests fail with UnknownAlgorithm for checksums

Proto's built-in checksum parser only supports standard sha256sum / sha512sum formats (<hash> <filename>) and detects the algorithm from the file extension or hash length. If a tool publishes checksums in a non-standard format, you need to fetch and parse them yourself in download_prebuilt and provide the hash via the checksum field instead of checksum_url.

License

MIT

Releases

Packages

Contributors

Languages