EncoreDocs
Modding

Unofficial mod repositories

Host mods for Encore with a static JSON repository

Encore installs mods from BeatMods by default. An unofficial repository is a static JSON file that anyone can host

They're opt-in and disabled until the user reviews the repository and accepts the risk. ScoreSaber can still block individual repositories through its repository policy

How it works

The format is loosely based on VRChat Creator Companion repositories. Read their much better docs here to get an idea.

Each package lists its versions and each version points to a downloadable archive

  • The archive and every installed file need a hash. Encore checks both and uses the file hashes to recognise the installed mod later
  • Files can only land under Plugins/ or Libs/. A repository can't replace the mod loader or write into the game root

We'll probably want to create some kind of cool GitHub action to automate repository generation from releases or something, not quite sure yet.

Listing format

Serve the JSON file over HTTPS. Encore appends /index.json when the URL doesn't end in .json and converts GitHub blob URLs to raw URLs

Cool thing to add to your README if you wanna, some people may make dedicated encore repo... repos or some people may just do what I did and stick it in their mods existing repo the choice really is yours to make

[Add to Encore](encore://add-source?url=https://raw.githubusercontent.com/example/encore-repo/main/index.json)

<sub>[What's Encore?](https://encore.scoresaber.com)</sub>

This opens a preview in Encore. The user still has to accept the risk and select Add repository

The schema:

{
  "schemaVersion": 1,
  "id": "com.example.encore-repo",
  "name": "Example Mods",
  "owner": "Example Maintainer",
  "contactUrl": "https://github.com/example/encore-repo/issues",
  "infoUrl": "https://github.com/example/encore-repo",
  "packages": [
    {
      "id": "com.example.coolmod",
      "identity": "beatmods:256",
      "name": "Cool Mod",
      "summary": "Does something cool",
      "description": "# Cool Mod\n\nMarkdown shown in the mod details.\n\n![Screenshot](https://raw.githubusercontent.com/example/encore-repo/main/cool-mod.png)",
      "iconUrl": "https://raw.githubusercontent.com/example/encore-repo/main/cool-mod-icon.png",
      "category": "gameplay",
      "author": "Example Maintainer",
      "sourceUrl": "https://github.com/example/cool-mod",
      "issuesUrl": "https://github.com/example/cool-mod/issues",
      "versions": [
        {
          "version": "1.2.3",
          "gameVersions": ["1.37.0"],
          "platforms": ["universalpc"],
          "downloadUrl": "https://github.com/example/cool-mod/releases/download/1.2.3/CoolMod.zip",
          "fileSizeBytes": 51234,
          "hash": { "algorithm": "sha256", "value": "<64 hex characters>" },
          "dependencies": ["beatmods:1"],
          "files": [
            {
              "path": "Plugins/CoolMod.dll",
              "hash": { "algorithm": "sha256", "value": "<64 hex characters>" }
            }
          ]
        }
      ]
    }
  ]
}

Rools:

  • schemaVersion must be 1
  • A listing needs id, name, owner and packages. Encore already has the URL it fetched, so the document doesn't repeat it
  • A package needs id, name and at least one version
  • identity is optional and must be a BeatMods mod ID written as beatmods:<mod id>
  • A version needs version, an HTTPS downloadUrl, hash and at least one file with its own hash
  • Use sha256 for new repositories. md5 is accepted for existing mod metadata
  • An empty or missing gameVersions or platforms list matches every install. Otherwise the version has to include the current game version and steampc, oculuspc or universalpc
  • Every file path is normalised like an archive entry and must stay under Plugins/ or Libs/
  • description is optional Markdown. Encore strips raw HTML and anything other than HTTPS links and images
  • Optional URLs are only opened or loaded when they're plain HTTPS addresses without credentials or a custom port
  • A malformed version or package is dropped. A malformed listing is refused

Package IDs only need to be unique inside their repository. Dependencies refer to another package ID from that repository. Use beatmods:<mod id> to depend on a mod from BeatMods, such as beatmods:1 for BSIPA. The mod ID is the number in its BeatMods page URL

Keep older compatible versions in the listing. Encore uses their file hashes to recognise an installed version and offer the latest matching update under the same repository package ID

Repository policy

ScoreSaber publishes the repository policy at https://encore.scoresaber.com/policy/mod-repositories.json

We'll make this policy editable by trusted figures in the community soon

Hopefully in a not so half assed way where it requires making a commit 🙃

{
  "schemaVersion": 1,
  "version": 7,
  "updatedAt": "2026-07-20T10:00:00.000Z",
  "expiresAt": "2027-07-20T10:00:00.000Z",
  "transparencyUrl": "https://github.com/ScoreSaber/encore",
  "entries": [
    {
      "reason": "malware",
      "addedAt": "2026-07-01T00:00:00.000Z",
      "id": "com.example.bad-repo",
      "host": "bad.example",
      "listingUrl": "https://bad.example/index.json",
      "detailsUrl": "https://github.com/ScoreSaber/encore/issues/1"
    }
  ]
}

Encore caches the policy in the user data folder and won't replace it with an older version

  • A current policy is required to add or enable an unofficial repository
  • An expired policy leaves already enabled repositories available but shows that the policy is stale
  • With no cached policy, every unofficial repository is unavailable
  • A denylisted repository is disabled and can't contribute mods. Denylisted download hosts are blocked too

Encore doesn't come with a bundled denylist. Until the policy endpoint answers, unofficial repositories stay unavailable

Reporting

Once I make the button for it, it'll probably open https://github.com/ScoreSaber/encore/issues/new?labels=mod-repository for now. Proper moderation endpoint's are planned.

On this page