A pack holds one league on one day. A repository wraps your packs up so the game can list them, install them and see when a newer one comes out. It's the same folder whether it's zipped, on GitHub or on your own server.
roster-repository.json the front page: who made it, and its sets
pond/ a folder for each set, named for its id
roster-set.json the set's updates, by date
2026-10-01/
roster-pack.json the pack as it was on October 1
2026-10-05/
roster-pack.json and on October 5
changes.md what changed since the update before
A repository can hold any number of sets. Each is a league that installs on its own, like your league, or the same teams with house rules. Each set has any number of updates, one per date.
roster-repository.json
The front page. It names the repository and lists its sets.
{
"format": "bladeybiscuit.roster-repository",
"formatVersion": 1,
"name": "Example rosters",
"description": "The example from the Blades & Biscuits custom rosters guide",
"maintainer": "Blades & Biscuits",
"homepage": "https://bladesandbiscuits.hockey/rosters/",
"sets": [
{
"id": "pond",
"name": "The Pond League",
"league": "POND",
"description": "Two made-up teams, for trying custom rosters out",
"index": "pond/roster-set.json",
"latest": "2026-10-05"
}
]
}
| Field | What it does | |
|---|---|---|
format |
Required | Always "bladeybiscuit.roster-repository". |
formatVersion |
1. |
|
name |
The repository's name in the Rosters menu (default “Rosters”). | |
maintainer |
Who keeps it. Shown as “Kept by”. | |
description, homepage |
About it. | |
sets |
The sets in it. |
Each set in sets:
| Field | What it does | |
|---|---|---|
id |
Required | A short name for the set, unique in the repository, like "pond". Name its folder the same. |
index |
Required | Where its roster-set.json is, relative to this file: "pond/roster-set.json". |
name |
Its name in the menus (default: its id). |
|
league |
The league's letters, as in its packs. | |
description |
A line about it, shown while it's highlighted. | |
latest |
The date of its newest update. It's a hint: the game reads the set's own file for the real list. |
roster-set.json
One set's updates. Each update is one pack.
{
"format": "bladeybiscuit.roster-set",
"formatVersion": 1,
"id": "pond",
"name": "The Pond League",
"league": "POND",
"description": "Two made-up teams, for trying custom rosters out",
"updates": [
{
"date": "2026-10-05",
"season": "2026-27",
"file": "2026-10-05/roster-pack.json",
"sha256": "ecfdbfe1f9b447036dc8d354c969dfa3505cf2aea43384db3562b48a62f9aa84",
"size": 25482,
"teams": 2,
"players": 40,
"notes": "Trades (1) · Lines · Ratings",
"changes": "2026-10-05/changes.md"
},
{
"date": "2026-10-01",
"season": "2026-27",
"file": "2026-10-01/roster-pack.json",
"sha256": "c4c1ae45a6952ccd005afc178c788ae1afe6d4be5e380132933bd5218d03053a",
"size": 25482,
"teams": 2,
"players": 40,
"notes": "The first rosters of the season"
}
]
}
| Field | What it does | |
|---|---|---|
format |
Required | Always "bladeybiscuit.roster-set". |
formatVersion |
1. |
|
id, name, league, description |
As in the repository's list. | |
updates |
Every update, in any order. The game sorts them newest first. |
Each update:
| Field | What it does | |
|---|---|---|
date |
Required | The day its rosters are as of, as yyyy-MM-dd. The game shows it as “Oct 5, 2026”. One update per date. |
file |
Required | The pack, relative to this file. |
sha256 |
Recommended | The pack's checksum. If the download doesn't match it, the game doesn't install it. |
season |
Shown next to the date. | |
size |
The pack's size in bytes. | |
teams, players |
How many of each. The game shows these when you pick an update, so fill them in. | |
notes |
A line about what's new, shown when you pick an update. | |
changes |
A longer write-up, as a Markdown file beside the pack, for anyone browsing the repository. The game doesn't show it yet. |
The checker works out sha256, size, teams and players for a pack and
writes the whole update for you.
Updates and history
- Add a new update for each change. Make a new dated folder with the new pack, and add it to
updates. Keep the old ones: people can go back to any date, like the rosters from the start of the season. - Keep
latestin step. Change the set'slatestinroster-repository.jsonto the new date too. - People see it as an update. When they check the repository, the game reads each set's
roster-set.json, and if there's a newer date than the one they installed, it says “Update available”. - One date per set is installed at a time. Installing another date replaces it. A game in progress keeps the rosters it started with.
- Fixing a mistake? You can replace a pack and update its
sha256andsize, but anyone who already installed that date won't be told. A new date is better.
Checksums
A SHA-256 checksum is a 64-character fingerprint of a file. Change one letter in the pack and it's
completely different. The game works out the fingerprint of every pack it downloads and compares
it with sha256, so a half-uploaded or out-of-date file never gets installed.
The checker gives you a pack's checksum. Or, from a terminal:
| On | Run |
|---|---|
| Mac | shasum -a 256 roster-pack.json |
| Windows (PowerShell) | (Get-FileHash roster-pack.json).Hash |
| Linux | sha256sum roster-pack.json |
Capitals or not, either works. Leave sha256 out and the game skips the check. That's handy while
you're trying things out, but put it back before you share.
Paths
index, file and changes are paths relative to the file they're in. So the repository
works the same zipped, on a web server or on your computer. The game is strict about them, so a
repository can never point outside itself:
- Forward slashes between folders:
pond/2026-10-05/roster-pack.json. - Letters, digits,
.,_and-only, with each name starting with a letter or digit. No spaces, no.., and no names starting with a dot. - At most 8 names long (the folders and the file) and 200 characters.
- No names Windows reserves, like
conoraux.
A set index with a bad path is refused as a whole, so the checker is worth running after any change.
Zipped repositories
A repository zips up as it is. Settings ▸ Rosters ▸ Import a zip unpacks it and installs the newest update of every set in it.
roster-repository.jsongoes at the top of the zip, or inside one folder, which is what you get when you zip a folder. GitHub's “Download ZIP” works too.- Only
.json,.md,.txtand.csvfiles, and.pngand.jpgpictures, are taken. Anything else in the zip is skipped, and so is the junk Macs and Windows leave behind (__MACOSX,.DS_Store,Thumbs.db). - The game refuses a zip with an unsafe path in it, two files whose names differ only in capitals, more than 20,000 files, a file over 32 MB, or more than 1 GB in all.
A pack the game downloads can be up to 64 MB. A whole league is usually under 1 MB. Its pictures are downloaded and checked with it.