Compatibility rules

Package metadata says what a tool claims to support. Compatibility rules record what is known to work — and they take priority when jrt picks a runtime.

Local rules

A rule says: for this package, in this version range, use this runtime. --versions uses the ecosystem’s own range syntax (semver for npm, PEP 440 for PyPI, …).

shell
jrt compat set pypi:black --runtime python@3.13 --versions ">=26,<27"
jrt compat set npm:@wonderwhy-er/desktop-commander --runtime node@22 --versions ">=0.2.0 <0.3.0"
jrt compat list
jrt compat remove pypi:black

Rules apply the next time a tool is added, updated or run; jrt why <alias> shows when one was used.

Precedence

  1. Local rules from jrt compat set — always win.
  2. Signed bundles from publishers you trust.
  3. Rules built into jrt.

Sharing rules with signed bundles

Instead of every developer running compat set, a team or publisher can sign a bundle of rules once and distribute it.

Publisher

shell
jrt compat keygen my-team                        # writes JRT_HOME/keys/my-team.jrt-key, prints the public key
jrt compat sign --key <key-file> --sequence 1 --rules rules.json \
  --publisher "My Team" --expires-in 90d --out compat-bundle.json

rules.json has the same shape as the local compatibility.json. Without --rules, your current local rules are signed. Every new bundle must use a higher --sequence than the last. Keep the key file private.

rules.json
{
  "rules": [
    {
      "ecosystem": "npm",
      "package": "left-pad",
      "package_constraint": ">=1.0.0",
      "runtime": "node",
      "runtime_version": "22"
    }
  ]
}

Consumers

shell
jrt compat trust add my-team <public-key>
jrt compat update compat-bundle.json             # or an https:// URL
jrt compat list                                  # local rules, then each signed layer
jrt compat trust list
jrt compat trust remove my-team                  # also removes that publisher's rules

Security properties

  • ed25519 signatures over the exact payload bytes; bundles from untrusted keys or with modified payloads are rejected.
  • Rollback and replay protection: a bundle is only installed if its sequence is newer than the one already installed for that key.
  • Expired bundles and bundles issued in the future are rejected; an installed layer that expires keeps working but jrt doctor flags it.
  • Every rule is validated before signing and again after verification.
  • Only https:// URLs are fetched, bundles are capped at 4 MiB, and JRT_OFFLINE blocks fetching.