horizon_mods::index (feature index): index.json's types and rules (unique ids, https URLs, plain file names, hex SHA-256, minisign keys and signatures, a modpack's mods present in the index), open-ended kinds (mod, modpack, resourcepack, shader; unknown kinds kept, not offered), revocations, and check_file: size, hash, revocation, signature and the file's own manifest against its entry. horizon_mods::modpack reads .hpack files: horizon-modpack.toml and an allow-list of overrides. docs/api/mod-index.md documents both, with a sample index the tests read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.3 KiB
The registry index and .hpack
Horizon's registry lists what is made for Horizon and reviewed: mods (.hmod), modpacks (.hpack), resource packs
and, once their format exists, Horizon shader packs. Submissions are pull requests in
ludovic111/horizon-mods; merging one publishes it. The launcher and the
website read one file, index.json, which that repository's CI builds. The Rust types and every check below are
horizon_mods::index and horizon_mods::modpack (feature index); the sample is
crates/horizon-mods/tests/index/index-v1.json, read by the tests with the files it lists.
Level: preview (stability.md). Schema 1.
index.json
{
"schema": 1,
"generated": "2026-10-24T18:00:00Z",
"projects": [{
"id": "coords_hud", "kind": "mod", "name": "Coordinates HUD", "summary": "One line.",
"description": "Markdown.", "authors": ["Horizon"], "owners": ["ludovic111"],
"license": "MIT", "source": "https://github.com/...", "icon": "https://...png", "key": "RWT...",
"versions": [{
"version": "0.1.0", "published": "2026-10-24", "changelog": "",
"api": "0.1", "side": "client", "capabilities": ["game-read", "hud", "chat"], "game": "26.3",
"file": { "name": "coords_hud-0.1.0.hmod", "url": "https://github.com/ludovic111/horizon-mods/releases/download/...",
"size": 438, "sha256": "e113...", "signature": "untrusted comment: ...\n...\ntrusted comment: ...\n...\n" }
}]
}],
"revoked": [{ "id": "bad_mod", "sha256": "1111...", "reason": "Sent chat messages it didn't declare.", "date": "2026-10-24" }]
}
| Field | Meaning |
|---|---|
schema |
1. A reader refuses a higher number with "update Horizon" rather than misread it. |
projects[].id |
[a-z0-9_]{1,64}, unique; a mod's is its manifest's id. |
kind |
mod, modpack, resourcepack, shader (Horizon's own shader packs, not Iris or OptiFine packs). Other kinds (data packs, worlds, themes) may come without a new schema: a reader keeps a kind it doesn't know and doesn't offer it. |
summary, description |
One line for lists; Markdown for the project's page. |
owners |
GitHub logins allowed to publish updates. |
license, source |
An SPDX expression and an https:// address of the source code: both required. |
icon |
https://, optional. |
key |
The author's minisign public key. When set, every version must be signed with it; an update signed with another key is refused. Absent: the project is unsigned and the launcher says so. |
versions |
Newest first, at least one. |
api |
A mod's API line (its manifest's api); a modpack's manifest format (1). |
side, capabilities |
A mod's, read from its manifest by CI, never typed by hand. |
game |
The Minecraft version it is for. |
requires |
A modpack's mods: { id, version, sha256 }, each a version in this index with that hash. |
file |
A plain name with the kind's extension (.hmod, .hpack, .zip), an https:// URL, the size (at most 64 MiB), the lowercase hex SHA-256, and the .minisig text when the project has a key. |
revoked |
Files taken down: one file by sha256, or every version of id without it. The launcher refuses to install them and turns installed copies off with the reason. |
Readers ignore fields they don't know, so an optional field can be added to schema 1. Renaming or removing a field, or changing what one means, makes schema 2.
Before a file is installed
index::check_file runs on the downloaded file, before it reaches the game folder:
- Its size and SHA-256 are the ones the entry lists, and it isn't revoked.
- With a project key: its signature verifies with that key (minisign's prehashed and legacy signatures both).
- What the file says matches the entry: a mod's
horizon-mod.toml(id, version, API, side, capabilities) and its content's fence (mods.md); a modpack's manifest (id, version, format, game, mods); a resource pack'spack.mcmeta. - A kind this build can't install is refused with "this Horizon can't install a … yet".
The game still checks a mod's component imports against its capabilities when it starts it, as for any mod.
.hpack
A zip holding horizon-modpack.toml and, optionally, overrides/. The mods are not inside: the launcher downloads
each from the index and checks it as above.
format = 1
id = "cozy" # [a-z0-9_]{1,64}: the profile's folder
name = "Cozy"
version = "1.0.0"
description = "Coordinates and a calm render distance."
authors = ["Horizon"]
game = "26.3"
[[mods]]
id = "coords_hud"
version = "0.1.0"
sha256 = "e1135345692f6dd8fd4c51920151944b82333e17049c9bb7d756f27b8deefc53"
on = true # optional, default true: turned on in the profile's horizon-mods.txt
Unknown keys are refused. overrides/ may hold only options.txt, horizon-graphics.txt, horizon-extras.txt,
resourcepacks/<name>.zip and horizon-mods/.horizon-mod-data/<a listed mod>/... (a mod's own saved settings,
capability storage), each at most 64 MiB and 256 MiB in all; anything else refuses the pack. The launcher copies
them into the profile's game folder.
Changelog
- Schema 1 (2026-10-24): kinds
mod,modpack,resourcepack,shader;.hpackformat 1.