Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The noyalib ecosystem

This document does two things. It describes what the ecosystem is today, and it states — with numbers anyone can reproduce — how good it actually is. The second part is the harder one, and the reason scripts/ecosystem-scorecard.sh exists.

Why a harness instead of a claim

A rating is worth something only if it can be shown to be wrong. Most “production-ready / battle-tested / enterprise-grade” language in this corner of the industry cannot be, because nothing is attached to it. So every number below is produced by a command, and the command is printed next to the number.

Three rules govern the harness:

  1. Falsifiable. Each metric names the exact command and the exact threshold. “Docs are good” is not a metric. “rustdoc emits 0 warnings under -D warnings” is — run it and see.
  2. No credit for unmeasured work. A probe that cannot run scores N/A and is removed from the denominator. It never scores 0, and it never silently scores 1. The report states what fraction of the rubric actually executed, because a perfect score over a third of the rubric is not a perfect score.
  3. Reproducible. The header records rustc/cargo versions, host triple, each repo’s commit SHA, and whether the worktree was dirty.

Run it:

scripts/ecosystem-scorecard.sh                  # local probes
scripts/ecosystem-scorecard.sh --network        # + crates.io, GitHub, OpenSSF
scripts/ecosystem-scorecard.sh --deep           # + all-features build probes
scripts/ecosystem-scorecard.sh --with-coverage  # + cargo-llvm-cov
scripts/ecosystem-scorecard.sh --json out.json

CI runs the same harness weekly and on every change to it or to this page (.github/workflows/ecosystem-scorecard.yml), against fresh checkouts of all six repos; the workflow fails below the 0.90 floor, and the JSON report is attached to the run.

It exits non-zero below SCORE_FLOOR (default 0.90), so the rating can be a CI gate rather than a boast.

What it deliberately does not measure

  • Adoption. Downloads are recorded as context below, not scored. Popularity is not quality, and scoring it would let the rating drift with marketing rather than engineering.
  • Benchmark numbers. The harness checks that docs/BENCHMARKS.md discloses host, toolchain and repro command — the things that make a speed claim falsifiable — but does not re-run criterion. Timing a laptop under variable load and calling the delta a score would be measurement theatre.
  • Code review. OpenSSF scores this 0 across every repo in the family, correctly: these are single-maintainer repos with squash merges. That is a real limitation and is left visible rather than excluded.

The competitive landscape, 2026

YAML tooling is not one market. It is five, and each has a different incumbent in a different language.

SurfaceIncumbentLanguagenoyalib’s answer
Libraryserde_yaml (archived 2024)Rustnoyalib
CLI query / transformyqGonothing
Style linteryamllintPythonnothing
Language serveryaml-language-server (Red Hat)TypeScriptnoyalib-lsp
Agent tooling (MCP)no incumbent—noyalib-mcp
Browser / JSyaml (eemeli), js-yamlJavaScriptnoyalib-wasm

The Rust library tier alone has fragmented since serde_yaml was archived. Recent-download counts from the crates.io API:

CrateRecent downloadsStatus
serde_yaml87.1Marchived upstream
yaml-rust213.9Mmaintained, no serde layer
serde_yml6.4Mdescription begins “DEPRECATED”
serde_yaml_ng5.0Mmaintained fork
serde-saphyr3.6Mmaintained, newer
serde_norway2.7Mmaintained fork
noyalib0.247Mmaintained

The honest reading: noyalib is roughly 0.3% of the deprecated incumbent and 6.8% of serde-saphyr. On measured capability it leads; on measured reach it does not. The constraint is distribution, not engineering — which is exactly where the gaps below sit.

For a feature-by-feature comparison of the Rust libraries — and instructions for verifying any row of it yourself — see COMPARISON.md. This document is about the suite, not the library.

The structural advantage is that noyalib is the only one of these that spans all five surfaces from a single core. yq, yamllint and yaml-language-server are three unrelated codebases in three languages with three different YAML parsers and three different sets of edge-case behaviour. A team that adopts them gets three answers to “is this document valid?”.

Measured gaps

Every row below was produced by a filesystem or API probe on 2026-08-20, not by judgement.

Capability the suite cannot express today

MissingEvidenceIncumbent
Query / transform toolnoya-cli declares exactly two [[bin]]: noyafmt, noyavalidateyq
Style linternoyavalidate is schema validation; no line-length, key-duplication, indentation or quote-consistency rulesyamllint

Both are surfacing work, not engine work. The lossless CST already tracks every span these rules need, and already backs remove/set.

Distribution

MissingEvidence
GitHub Actionno action.yml in any of the five repos
Hosted pre-commit hookno .pre-commit-hooks.yaml in noya-cli — docs/pre-commit.md documents only repo: local, which needs noyafmt already installed
VS Code extensionno editors/vscode in noyalib-lsp — the server exists but nobody can install it from the marketplace
Homebrew formulashipped: homebrew-tap/Formula/noya-cli.rb, with Scoop and AUR (noyalib-bin) beside it
CLI container imageshipped: noya-cli/pkg/docker/Dockerfile publishes ghcr.io/sebastienrousseau/noya-cli from its release workflow (first image with v0.0.34); the core’s dead monorepo-era Dockerfile is gone
Python bindingsno bindings/python
Native Node bindingswasm only; no napi

Supply-chain posture

OpenSSF Scorecard, scans taken the same day at the current HEAD of each repo:

RepoScore
noyalib8.0
noya-cli6.5
noyalib-lsp6.5
noyalib-mcp6.4
noyalib-wasm6.4

The satellite deficit is concentrated in four checks:

  • Fuzzing 10 -> 0. No satellite has a fuzz/ directory. Worth about a point each and cheap to fix.
  • CII-Best-Practices 5 -> 0. The badge is registered for the core only.
  • Contributors 3 -> 0, Signed-Releases 3 -> 1.

Code-Review is 0 on all five, including the core — single-maintainer squash merges. Honest, and not something a script can fix.

The credibility gap

Three crates in the same portfolio still depend on YAML libraries their own authors have marked dead:

RepoDependencyUpstream status
libmakeserde_yml 0.0.13crates.io description begins “DEPRECATED”
nucleusflowserde_yml 0.0.13same
wiseroneserde_yaml 0.9.31archived
metadata-gennoyalib and yaml-rust2half-migrated

Already migrated: frontmatter-gen, html-generator, static-site-generator, and the five satellites.

Shipping a YAML library while three of your own crates depend on an archived one is the most falsifiable credibility claim in the set, and the cheapest to close.

Proposed additions

Ranked by measured gap times incumbent strength.

Tier 1 — capability

  1. noyaq (new bin in noya-cli) — query and in-place transform with a yq-compatible expression subset.
  2. noyalint (new bin in noya-cli) — yamllint’s rule set over the CST.
  3. noyalib-rules (new crate) — the rule engine behind noyalint, reused by the LSP for diagnostics and by the MCP server as an agent-facing lint tool, so three surfaces do not re-implement the same checks.

Tier 2 — distribution

  1. First-party GitHub Action. CI is where YAML tooling is actually consumed; this is the highest-leverage single artefact on the list.
  2. .pre-commit-hooks.yaml — one file, unlocks the entire pre-commit user base.
  3. VS Code extension wrapping noyalib-lsp.
  4. Homebrew tap (shipped, with Scoop and AUR) and a CLI container image.

Tier 3 — reach beyond Rust

  1. noyalib-py (PyO3) — the linting and round-trip audience is Python-native.
  2. noyalib-node (napi-rs) — native throughput where WASM loses.

Tier 4 — cheap credibility

  1. Fuzz targets in each satellite.
  2. OpenSSF Best Practices badge for the five satellites.
  3. Migrate libmake, nucleusflow, wiserone; finish metadata-gen.

Rating

Rating: A- (92.5% weighted) — 134 executed probes, 12 scored N/A.

Measured 2026-10-15T20:47:55Z on aarch64-apple-darwin, rustc 1.99.0 (b940084d7 2026-09-28). Rubric executed: 92%.

RepoMetricMeasuredScoreProbe
noyalibtests6635 passed / 0 failed1.00cargo test --workspace --locked
noyalibclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noyalibrustfmtclean1.00cargo fmt --all --check
noyalibunsafe_forbidden2/2 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noyalibmsrv_declared1.89.01.00grep rust-version Cargo.toml
noyalibrustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noyalibmissing_docs_lint2/2 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noyalibreadme_examplescompile1.00scripts/check-readme-examples.sh
noyalibbench_methodology3/3 disclosed (host, toolchain, command)1.00grep host/toolchain/repro-command in docs/BENCHMARKS.md
noyalibaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noyalibdeny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noyalibvet_auditedpass1.00cargo vet --locked
noyalibreuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noyalibdependency_closure12 unique runtime crates1.00cargo tree -e normal --prefix none --no-dedupe | sort -u (library budget 60; propagates to consumers)
noyalibactions_sha_pinned160/160 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noyalibfuzz_targets18 libFuzzer targets1.00find fuzz/fuzz_targets -name '*.rs' (floor 2)
noyalibline_coveragenot runn/apass --with-coverage to measure
noyalibrelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noyalibrelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noyalibrelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noyalibdependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noyalib/dependabot/alerts?state=open
noyalibci_main_greenfailure0.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noyalibcrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noyalib .max_stable_version
noyalibopenssf_scorecard8.3/100.83api.securityscorecards.dev/projects/github.com/sebastienrousseau/noyalib .score
noya-clitests122 passed / 0 failed1.00cargo test --workspace --locked
noya-cliclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noya-clirustfmtclean1.00cargo fmt --all --check
noya-cliunsafe_forbidden1/1 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noya-climsrv_declared1.89.01.00grep rust-version Cargo.toml
noya-clirustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noya-climissing_docs_lint1/1 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noya-clireadme_examplescompile1.00scripts/check-readme-examples.sh
noya-clibench_methodology1/3 disclosed (host, toolchain, command)0.33grep host/toolchain/repro-command in docs/BENCHMARKS.md
noya-cliaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noya-clideny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noya-clivet_auditedpass1.00cargo vet --locked
noya-clireuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noya-clidependency_closure105 unique runtime crates (leaf, not scored)n/acargo tree -e normal --prefix none --no-dedupe | sort -u — recorded, not scored: a leaf binary's tree is not inherited
noya-cliactions_sha_pinned77/77 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noya-clifuzz_targets2 libFuzzer targets1.00find fuzz/fuzz_targets -name '*.rs' (floor 2)
noya-cliline_coveragenot runn/apass --with-coverage to measure
noya-clirelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noya-clirelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noya-clirelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noya-clidependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noya-cli/dependabot/alerts?state=open
noya-clici_main_greensuccess1.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noya-clicrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noya-cli .max_stable_version
noya-cliopenssf_scorecard8.4/100.84api.securityscorecards.dev/projects/github.com/sebastienrousseau/noya-cli .score
noyalib-lsptests75 passed / 0 failed1.00cargo test --workspace --locked
noyalib-lspclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noyalib-lsprustfmtclean1.00cargo fmt --all --check
noyalib-lspunsafe_forbidden2/2 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noyalib-lspmsrv_declared1.89.01.00grep rust-version Cargo.toml
noyalib-lsprustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noyalib-lspmissing_docs_lint2/2 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noyalib-lspreadme_examplescompile1.00scripts/check-readme-examples.sh
noyalib-lspbench_methodology1/3 disclosed (host, toolchain, command)0.33grep host/toolchain/repro-command in docs/BENCHMARKS.md
noyalib-lspaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noyalib-lspdeny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noyalib-lspvet_auditedpass1.00cargo vet --locked
noyalib-lspreuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noyalib-lspdependency_closure71 unique runtime crates (leaf, not scored)n/acargo tree -e normal --prefix none --no-dedupe | sort -u — recorded, not scored: a leaf binary's tree is not inherited
noyalib-lspactions_sha_pinned62/62 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noyalib-lspfuzz_targets2 libFuzzer targets1.00find fuzz/fuzz_targets -name '*.rs' (floor 2)
noyalib-lspline_coveragenot runn/apass --with-coverage to measure
noyalib-lsprelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noyalib-lsprelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noyalib-lsprelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noyalib-lspdependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noyalib-lsp/dependabot/alerts?state=open
noyalib-lspci_main_greensuccess1.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noyalib-lspcrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noyalib-lsp .max_stable_version
noyalib-lspopenssf_scorecard8.4/100.84api.securityscorecards.dev/projects/github.com/sebastienrousseau/noyalib-lsp .score
noyalib-mcptests124 passed / 0 failed1.00cargo test --workspace --locked
noyalib-mcpclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noyalib-mcprustfmtclean1.00cargo fmt --all --check
noyalib-mcpunsafe_forbidden2/2 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noyalib-mcpmsrv_declared1.89.01.00grep rust-version Cargo.toml
noyalib-mcprustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noyalib-mcpmissing_docs_lint2/2 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noyalib-mcpreadme_examplescompile1.00scripts/check-readme-examples.sh
noyalib-mcpbench_methodology1/3 disclosed (host, toolchain, command)0.33grep host/toolchain/repro-command in docs/BENCHMARKS.md
noyalib-mcpaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noyalib-mcpdeny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noyalib-mcpvet_auditedpass1.00cargo vet --locked
noyalib-mcpreuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noyalib-mcpdependency_closure134 unique runtime crates (leaf, not scored)n/acargo tree -e normal --prefix none --no-dedupe | sort -u — recorded, not scored: a leaf binary's tree is not inherited
noyalib-mcpactions_sha_pinned74/74 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noyalib-mcpfuzz_targets1 libFuzzer targets0.50find fuzz/fuzz_targets -name '*.rs' (floor 2)
noyalib-mcpline_coveragenot runn/apass --with-coverage to measure
noyalib-mcprelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noyalib-mcprelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noyalib-mcprelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noyalib-mcpdependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noyalib-mcp/dependabot/alerts?state=open
noyalib-mcpci_main_greensuccess1.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noyalib-mcpcrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noyalib-mcp .max_stable_version
noyalib-mcpopenssf_scorecard8.4/100.84api.securityscorecards.dev/projects/github.com/sebastienrousseau/noyalib-mcp .score
noyalib-wasmtests57 passed / 0 failed1.00cargo test --workspace --locked
noyalib-wasmclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noyalib-wasmrustfmtclean1.00cargo fmt --all --check
noyalib-wasmunsafe_forbidden1/1 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noyalib-wasmmsrv_declared1.89.01.00grep rust-version Cargo.toml
noyalib-wasmrustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noyalib-wasmmissing_docs_lint1/1 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noyalib-wasmreadme_examplescompile1.00scripts/check-readme-examples.sh
noyalib-wasmbench_methodology0/3 disclosed (host, toolchain, command)0.00grep host/toolchain/repro-command in docs/BENCHMARKS.md
noyalib-wasmaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noyalib-wasmdeny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noyalib-wasmvet_auditedpass1.00cargo vet --locked
noyalib-wasmreuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noyalib-wasmdependency_closure33 unique runtime crates (leaf, not scored)n/acargo tree -e normal --prefix none --no-dedupe | sort -u — recorded, not scored: a leaf binary's tree is not inherited
noyalib-wasmactions_sha_pinned65/65 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noyalib-wasmfuzz_targets2 libFuzzer targets1.00find fuzz/fuzz_targets -name '*.rs' (floor 2)
noyalib-wasmline_coveragenot runn/apass --with-coverage to measure
noyalib-wasmrelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noyalib-wasmrelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noyalib-wasmrelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noyalib-wasmdependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noyalib-wasm/dependabot/alerts?state=open
noyalib-wasmci_main_greensuccess1.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noyalib-wasmcrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noyalib-wasm .max_stable_version
noyalib-wasmopenssf_scorecard8.4/100.84api.securityscorecards.dev/projects/github.com/sebastienrousseau/noyalib-wasm .score
noyalib-serde-yamltests6 passed / 0 failed1.00cargo test --workspace --locked
noyalib-serde-yamlclippy0 diagnostics (rc=0)1.00cargo clippy --workspace --all-targets --locked -- -D warnings
noyalib-serde-yamlrustfmtclean1.00cargo fmt --all --check
noyalib-serde-yamlunsafe_forbidden1/1 crate roots1.00grep -l 'forbid(unsafe_code)' on every lib.rs/main.rs
noyalib-serde-yamlmsrv_declared1.89.01.00grep rust-version Cargo.toml
noyalib-serde-yamlrustdoc_strict0 warnings1.00RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps --all-features (matches CI + docs.rs)
noyalib-serde-yamlmissing_docs_lint1/1 roots deny missing_docs1.00grep for deny/warn(missing_docs) in crate roots
noyalib-serde-yamlreadme_examplescompile1.00scripts/check-readme-examples.sh
noyalib-serde-yamlbench_methodology1/3 disclosed (host, toolchain, command)0.33grep host/toolchain/repro-command in docs/BENCHMARKS.md
noyalib-serde-yamlaudit_vulnerabilities0 advisories1.00cargo-audit audit --json | .vulnerabilities.count
noyalib-serde-yamldeny_checkpass1.00cargo deny check (advisories, bans, licenses, sources)
noyalib-serde-yamlvet_auditedpass1.00cargo vet --locked
noyalib-serde-yamlreuse_compliancecompliant1.00reuse lint (REUSE 3.3)
noyalib-serde-yamldependency_closure10 unique runtime crates (leaf, not scored)n/acargo tree -e normal --prefix none --no-dedupe | sort -u — recorded, not scored: a leaf binary's tree is not inherited
noyalib-serde-yamlactions_sha_pinned52/52 external uses pinned1.00grep 'uses:.*@<40-hex>' .github/workflows
noyalib-serde-yamlfuzz_targets2 libFuzzer targets1.00find fuzz/fuzz_targets -name '*.rs' (floor 2)
noyalib-serde-yamlline_coveragenot runn/apass --with-coverage to measure
noyalib-serde-yamlrelease_gpg_signed3 .asc assets1.00gh release view --json assets | grep '\.asc$'
noyalib-serde-yamlrelease_sigstore3 .bundle assets1.00gh release view --json assets | grep '\.bundle$'
noyalib-serde-yamlrelease_sbom6 sbom assets1.00gh release view --json assets | grep -i sbom
noyalib-serde-yamldependabot_open0 open alerts1.00gh api /repos/sebastienrousseau/noyalib-serde-yaml/dependabot/alerts?state=open
noyalib-serde-yamlci_main_greensuccess1.00gh run list --branch main --workflow CI --status completed --limit 1 --json conclusion
noyalib-serde-yamlcrates_io_currenttree 0.0.58 / crates.io 0.0.570.00crates.io/api/v1/crates/noyalib-serde-yaml .max_stable_version
noyalib-serde-yamlopenssf_scorecard7.3/100.73api.securityscorecards.dev/projects/github.com/sebastienrousseau/noyalib-serde-yaml .score
ecosystemversion_lockstepcore 0.0.58 not tagged yetn/agit tag -l v0.0.58 in noyalib (pending release; satellites pin only published versions)
ecosystemhost_coverage6/6 hosts present1.00directory presence for noyalib noya-cli noyalib-lsp noyalib-mcp noyalib-wasm noyalib-serde-yaml

Generated by scripts/ecosystem-scorecard.sh v1.0.0. Regenerate rather than edit.

How to disagree with this rating

Pick the row you doubt and run its probe. If the number differs, the harness is wrong and should be fixed — open an issue with the command output. That is the entire contract.

Two caveats the harness prints about itself and this document repeats, because a score that hides its own limits is a marketing number:

  • Rubric coverage. The percentage of probes that actually executed is reported alongside the score. Network and coverage probes are opt-in; with them off, a large slice of the rubric is N/A, and the headline is correspondingly less meaningful.
  • Worktree state. The header records whether each repo was dirty. A score measured against uncommitted changes describes those changes, not the published artefact.

Known weaknesses of the harness itself

  • A timed-out probe used to score 0, asserting a failure it had not observed. The run recorded above shows noyalib · tests · timeout after 3600s · 0.00, which dragged correctness to 83.3%. That is an artefact of the ceiling firing on a cold target dir, not a test failure: the same suite run directly on the same commit passed 5739 / 0, and spec_conformance in this very run reports 406/406. It also contradicted rule 2 above — an unmeasured probe is supposed to score N/A and never 0. Fixed: a timeout now records N/A, which keeps it visible (N/A rows print, and they lower the reported rubric coverage) without claiming a failure that did not happen. The next regeneration will show N/A here rather than a false ✗.

  • It measures the presence of fuzz targets, not fuzzing effort. Two targets that have never found anything score the same as two that have.

  • dependency_closure used one flat budget of 60 for every repo. That is why noya-cli scored 0 at 130 crates. The obvious fix — a per-repo budget — turned out to be the wrong one: any number picked now would be a number picked so the current value clears it. The rule that survived scrutiny is about propagation. A library’s dependencies are inherited by every downstream consumer, so their size is a cost imposed on other people and belongs in the score; noyalib sits at 12. A leaf binary’s are not inherited, and 130 of noya-cli’s crates are miette’s fancy renderer giving noyavalidate source excerpts and carets — which for a validator is the job, not bloat. Leaves are therefore recorded and not scored: the count stays in the table and the JSON, so a leaf that doubles its tree is obvious, but it is not judged against a line nobody can defend.

  • Code-Review cannot be fixed by any script, and no probe pretends otherwise.

  • Test pass ratio is scored, but not test quality. A suite of 4,000 trivial assertions scores the same as 4,000 sharp ones. Coverage (--with-coverage) partly compensates and is off by default because it is slow.

Family layout

Every repository in the family carries the same skeleton, enforced per push by the Family layout contract step of shared-docs-lint.yml — a repo that drops one of these files fails its own CI:

FileRole
README.mdidentity, install, quick start, the four documentation links
CHANGELOG.mdKeep-a-Changelog, one heading per lockstep release
SECURITY.mdprivate reporting channel
CONTRIBUTING.mdfamily process (satellites point at the core’s)
DEVELOPMENT.mddeveloper entry point (satellites point at the core’s)
REUSE.tomlmachine-readable licensing for headerless files
CODE_OF_CONDUCT.md, GOVERNANCE.md, SUPPORT.mdcommunity files; satellites point at the core’s governance model
AGENTS.mdthe invariants an AI-assisted contributor must respect (lockstep, signing, CI green)
CITATION.cffone citation record per crate, at the crate’s version
.pre-commit-config.yaml, .devcontainer/pre-commit hooks; a container that boots to a working make
docs/documentation root (never doc/), with ARCHITECTURE.md and an mdBook (book.toml, SUMMARY.md) deployed to Pages
scripts/verify-release-versions.shthe version gate, run before every tag
fuzz/corpus/seeda seed corpus replayed by CI on every push
.editorconfig, .markdownlint.yaml, .codespellrcshared editor + docs-lint configs

Satellites additionally carry supply-chain/; the core additionally carries the shared-*.yml workflows the family consumes by SHA and the manual for the library itself. Until 2026-09-05 the citation record, AGENTS.md, and the devcontainer lived in the core only; every satellite now carries its own, so the contract lists them.

Where the family is published

Cratecrates.ionpmghcr.io
noyalibnoyalib
noya-clinoya-clisebastienrousseau/noya-cli (from v0.0.34)
noyalib-lspnoyalib-lsp
noyalib-mcpnoyalib-mcp@sebastienrousseau/noyalib-mcpsebastienrousseau/noyalib-mcp
noyalib-wasmnoyalib-wasm@sebastienrousseau/noyalib-wasm
noyalib-serde-yamlnoyalib-serde-yaml

All six crates release in lockstep at the identical =0.0.X; the npm packages and container images carry the same version. Homebrew, Scoop, and AUR carry noya-cli (see its pkg/). A repository’s GitHub Packages sidebar counts only GitHub-hosted registries, so it is not the map; this table is.