A collection of working example plugins for Artifact Keeper. Each plugin implements a custom format handler using the WASM Component Model and the artifact-keeper:format@1.0.0 WIT contract.
Use these as starting points for building your own plugins. Fork, change the format key, and implement your logic.
| Plugin | Format Key | What it demonstrates |
|---|---|---|
| Unity | unity |
Gzip magic byte validation, path-based version extraction, JSON index |
| RPM | rpm |
Binary format validation (RPM lead magic), right-to-left filename parsing, structured metadata |
| PyPI | pypi |
PEP 427 wheel parsing, PEP 503 name normalization, HTML + JSON index generation |
- Rust (stable)
- The
wasm32-wasip2target (installed automatically viarust-toolchain.toml)
git clone https://github.com/artifact-keeper/artifact-keeper-example-plugin.git
cd artifact-keeper-example-plugin
# Build all plugins
cargo build --release
# Build a specific plugin
cargo build --release -p rpm-format-plugin
# Output: target/wasm32-wasip2/release/<plugin_name>.wasmUnit tests run on the host target (not WASM):
# All plugins
cargo test --target $(rustc -vV | grep host | awk '{print $2}') --workspace
# Single plugin
cargo test --target $(rustc -vV | grep host | awk '{print $2}') -p pypi-format-plugincurl -X POST https://your-registry/api/v1/plugins/install/git \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://github.com/artifact-keeper/artifact-keeper-example-plugin.git",
"ref": "v0.1.0"
}'Download a plugin ZIP from the Releases page, then:
curl -X POST https://your-registry/api/v1/plugins/install/zip \
-H "Authorization: Bearer $TOKEN" \
-F "file=@rpm-format-plugin-v0.1.0.zip"curl -X POST https://your-registry/api/v1/plugins/install/local \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"path": "/path/to/artifact-keeper-example-plugin"}'- Copy one of the example plugins as a starting point (the Unity plugin is the simplest)
- Update
plugin.tomlwith your format key, extensions, and description - Implement the four functions in
src/lib.rs:format_key()-- return your unique format identifierparse_metadata()-- extract metadata from uploaded artifactsvalidate()-- reject invalid artifacts before storagegenerate_index()-- create repository index files (or returnNone)
- The WIT contract in
wit/format-plugin.witdefines the interface -- don't modify it - Push a tag to trigger the release workflow
.
├── Cargo.toml # Workspace root
├── .cargo/config.toml # Default WASM target (wasm32-wasip2)
├── rust-toolchain.toml # Rust stable + WASM target
├── wit/format-plugin.wit # Shared WIT contract
├── plugins/
│ ├── unity-format/ # Unity .unitypackage handler
│ │ ├── Cargo.toml
│ │ ├── plugin.toml
│ │ └── src/lib.rs
│ ├── rpm-format/ # RPM package handler
│ │ ├── Cargo.toml
│ │ ├── plugin.toml
│ │ └── src/lib.rs
│ └── pypi-format/ # Python wheel/sdist handler
│ ├── Cargo.toml
│ ├── plugin.toml
│ └── src/lib.rs
└── .github/workflows/
├── ci.yml # Lint + test + build on push/PR
└── release.yml # Build + package + GitHub Release on tag
Plugins implement the artifact-keeper:format@1.0.0 interface:
interface handler {
record metadata {
path: string,
version: option<string>,
content-type: string,
size-bytes: u64,
checksum-sha256: option<string>,
}
format-key: func() -> string;
parse-metadata: func(path: string, data: list<u8>) -> result<metadata, string>;
validate: func(path: string, data: list<u8>) -> result<_, string>;
generate-index: func(artifacts: list<metadata>) -> result<option<list<tuple<string, list<u8>>>>, string>;
}MIT