{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://abdess.github.io/retrobios/api/v1/schemas/install-manifest.schema.json", "title": "RetroBIOS installer manifest", "type": "object", "additionalProperties": false, "required": [ "manifest_version", "source", "regions", "platform", "display_name", "version", "generated", "base_destination", "detect", "standalone_copies", "total_files", "total_size", "total_omitted", "omitted_files", "files" ], "properties": { "manifest_version": { "const": 2 }, "source": { "enum": [ "full", "platform", "truth" ] }, "regions": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }, "target": { "type": "string", "minLength": 1, "description": "Hardware target this manifest was filtered for, absent when unfiltered" }, "categorized": { "description": "Every game data file carries category: game_data. Without it the list records no category, and the installer refuses --no-game-data.", "const": true }, "no_game_data": { "description": "Built without game data, absent when the game data is listed", "const": true }, "platform": { "type": "string", "minLength": 1, "description": "Registry key of the platform (batocera)." }, "display_name": { "type": "string", "minLength": 1, "description": "Name the site shows for the platform." }, "version": { "type": "string", "description": "Version of the platform's own list this manifest was built from." }, "generated": { "type": "string", "format": "date-time", "description": "When the manifest was written." }, "base_destination": { "type": "string", "description": "The BIOS folder entries are written below, as the platform names it. Empty when entries start one level higher (RetroDECK)." }, "detect": { "type": "array", "items": { "type": "object" } }, "standalone_copies": { "type": "array", "items": { "type": "object" } }, "total_files": { "type": "integer", "minimum": 0, "description": "Number of entries in files." }, "total_size": { "type": "integer", "minimum": 0, "description": "Bytes of the files in files." }, "pack_files": { "description": "Files the platform's pack holds once extracted: this list, the data directories and the pack's own documents.", "type": "integer", "minimum": 0 }, "pack_size": { "description": "Bytes those files occupy once extracted.", "type": "integer", "minimum": 0 }, "total_omitted": { "type": "integer", "minimum": 0, "description": "Number of entries in omitted_files." }, "core_names": { "description": "Each core a file names, with the other names it goes by upstream (the buildbot's mednafen_psx for beetle_psx).", "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } }, "system_cores": { "description": "Each platform system with the cores whose presence keeps it. A system absent here is kept whatever cores are available.", "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } }, "system_titles": { "description": "Each system id with the name a person reads for it, the one the site prints (Sony PlayStation). A system the site cannot name is absent.", "type": "object", "additionalProperties": { "type": "string", "minLength": 1 } }, "system_names": { "description": "Each platform system with the names the platform's own file gives it (native_system), which the installer accepts for --system.", "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } }, "omitted_files": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "dest", "name", "system", "required", "reason", "cores" ], "properties": { "dest": { "type": "string", "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$" }, "name": { "type": "string", "minLength": 1 }, "system": { "type": "string" }, "required": { "type": "boolean" }, "reason": { "enum": [ "hash_mismatch", "not_found", "external", "user_provided", "no_platform_slug", "below_platform_folder", "no_save_directory", "no_core_folder", "no_save_system" ] }, "category": { "description": "game_data: a game's own data, not firmware. Absent on firmware.", "const": "game_data" }, "held": { "description": "The pack builder holds this file and the installer cannot download it. Region narrowing counts it held, as the builder does, so it displaces the same fallback.", "const": true }, "cores": { "oneOf": [ { "type": "null" }, { "type": "array", "items": { "type": "string" }, "uniqueItems": true } ] }, "regions": { "description": "The regions the emulator code selects the file for. Absent when it never competes.", "type": "array", "items": { "type": "string", "enum": [ "argentina", "asia", "asia-ntsc", "asia-pal", "australia", "brazil", "canada", "china", "denmark", "europe", "finland", "france", "germany", "greece", "hong-kong", "india", "italy", "japan", "latin-america", "mexico", "netherlands", "new-zealand", "north-america", "norway", "oceania", "poland", "portugal", "russia", "singapore", "south-korea", "spain", "sweden", "taiwan", "uk", "world" ] }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_groups": { "description": "Groups the file competes in as a core extra, whatever systems are chosen.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_system_groups": { "description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "systems": { "description": "Every platform system that declares the file, for the installer's --system.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "priority": { "description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.", "type": "integer" }, "declared_in": { "description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.", "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "alternatives": { "description": "Cores claiming this destination behind the platform's own declaration, in the order the pack builder tries them. A narrowing that drops every declaring system takes the first whose cores remain.", "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "cores" ], "properties": { "cores": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } } } }, "root": { "description": "save: dest is relative to the save directory the frontend hands the core (RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY), not to the BIOS directory. Absent for a file of the BIOS tree.", "const": "save" }, "core_folder": { "description": "The core's library_name, the folder a frontend sorting saves by core (RetroArch's sort_savefiles_enable) inserts between its save directory and dest. Only with root: save. Absent on a save entry when the core reads the same place sorted or not.", "type": "string", "minLength": 1, "pattern": "^[^/\\\\]+$" } } }, "description": "Files the pack needs and the repository cannot serve, with the reason." }, "files": { "type": "array", "items": { "$ref": "#/$defs/file" }, "description": "Every file the installer fetches, one entry per destination." }, "case_variants": { "description": "Files the folded list serves under another case, installed only where the target directory keeps case.", "type": "array", "items": { "$ref": "#/$defs/file" } }, "data_directories": { "description": "Data trees the pack carries, rebuilt by the installer from their source archive. Each file is kept only when its sha1 matches.", "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "ref", "dest", "url", "type", "systems", "files" ], "properties": { "ref": { "type": "string" }, "dest": { "type": "string", "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).*$" }, "url": { "type": "string", "pattern": "^https://" }, "type": { "enum": [ "zip", "tarball" ] }, "strip_components": { "type": "integer", "minimum": 0 }, "source_path": { "type": "string" }, "exclude": { "type": "array", "items": { "type": "string" } }, "systems": { "type": "array", "items": { "type": "string" } }, "files": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": false, "required": [ "sha1", "size" ], "properties": { "sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "size": { "type": "integer", "minimum": 0 } } } } } } }, "save_directory": { "description": "Where the platform keeps the save directory its frontend hands a core, present when an entry carries root: save. folder is the pack folder holding those files and the save directory's default place beside the BIOS directory, and by_core says the frontend appends each core's library_name (core_folder).", "type": "object", "additionalProperties": false, "required": [ "folder", "by_core" ], "properties": { "folder": { "type": "string", "pattern": "^[^/\\\\.][^/\\\\]*(/[^/\\\\.][^/\\\\]*)*$" }, "by_core": { "type": "boolean" }, "by_system": { "description": "true when the platform's launcher hands each core / at each launch (Batocera, RetroBat). Each dest then starts with that system's folder, and no frontend config read at install time changes it.", "const": true } } } }, "$defs": { "file": { "type": "object", "additionalProperties": false, "required": [ "dest", "sha1", "sha256", "size", "repo_path", "cores" ], "properties": { "dest": { "type": "string", "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$", "description": "Path below base_destination, or below the save directory when root is save." }, "sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$", "description": "SHA1 of the copy the repository serves. The installer checks it after download." }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "SHA256 of the same copy." }, "size": { "type": "integer", "minimum": 0, "description": "Bytes of the same copy." }, "repo_path": { "type": "string", "description": "Path in the repository. Fetched from https://raw.githubusercontent.com/Abdess/retrobios//, ref being main unless RETROBIOS_REF names a tag." }, "cores": { "oneOf": [ { "type": "null" }, { "type": "array", "items": { "type": "string" }, "uniqueItems": true } ], "description": "Profiles whose core brings the file into the pack. Null for a file the platform's own list declares." }, "storage": { "const": "release", "description": "release when the file is a large-files release asset." }, "release_asset": { "type": "string", "pattern": "^[^/\\\\]+$", "description": "Asset of the large-files release, fetched from https://github.com/Abdess/retrobios/releases/download/large-files/ instead of repo_path." }, "systems": { "description": "Every platform system that declares the file, for the installer's --system.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "regions": { "description": "The regions the emulator code selects the file for. Absent when it never competes.", "type": "array", "items": { "type": "string", "enum": [ "argentina", "asia", "asia-ntsc", "asia-pal", "australia", "brazil", "canada", "china", "denmark", "europe", "finland", "france", "germany", "greece", "hong-kong", "india", "italy", "japan", "latin-america", "mexico", "netherlands", "new-zealand", "north-america", "norway", "oceania", "poland", "portugal", "russia", "singapore", "south-korea", "spain", "sweden", "taiwan", "uk", "world" ] }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_groups": { "description": "Groups the file competes in as a core extra, whatever systems are chosen.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_system_groups": { "description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "priority": { "description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.", "type": "integer" }, "alternatives": { "description": "Copies other cores read at this destination when they disagree on its content, in the order the pack builder tries them. A narrowing that drops the entry's cores takes the first whose cores remain.", "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "sha1", "sha256", "size", "repo_path", "cores" ], "properties": { "sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "size": { "type": "integer", "minimum": 0 }, "repo_path": { "type": "string" }, "storage": { "const": "release" }, "release_asset": { "type": "string", "pattern": "^[^/\\\\]+$" }, "cores": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "executable": { "type": "boolean" } } } }, "slot_choices": { "description": "On a platform file a core's own source contradicts while the frontend only checks the path: the copy each core's presence puts there, in the order the pack builder settles the slot. A narrowing serves the first whose cores remain. One naming only cores, or none remaining, leaves `declared_choices`.", "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "cores" ], "properties": { "sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "size": { "type": "integer", "minimum": 0 }, "repo_path": { "type": "string" }, "storage": { "const": "release" }, "release_asset": { "type": "string", "pattern": "^[^/\\\\]+$" }, "cores": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "executable": { "type": "boolean" } } } }, "declared_choices": { "description": "The platform's own answer at the destination by the declaring systems that remain, in the order the pack builder takes the declarations. A narrowing serves the first whose systems remain.", "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": [ "sha1", "sha256", "size", "repo_path", "systems" ], "properties": { "sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "size": { "type": "integer", "minimum": 0 }, "repo_path": { "type": "string" }, "storage": { "const": "release" }, "release_asset": { "type": "string", "pattern": "^[^/\\\\]+$" }, "executable": { "type": "boolean" }, "systems": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1, "uniqueItems": true } } } }, "category": { "description": "game_data: a game's own data, not firmware. Absent on firmware. The installer's --no-game-data leaves these out, as a pack built with --no-game-data does.", "const": "game_data" }, "executable": { "description": "The repository keeps the file executable, and the installer gives it the execute bits the umask allows.", "type": "boolean" }, "declared_in": { "description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.", "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, "absent_claims": { "description": "Cores that want this destination and have nothing held, after the cores served here: a narrowing that keeps none of those takes the first named one as a file left out, as a pack built for it lists it.", "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": [ "name", "system", "required", "reason", "cores" ], "properties": { "name": { "type": "string", "minLength": 1 }, "system": { "type": "string" }, "required": { "type": "boolean" }, "reason": { "enum": [ "hash_mismatch", "not_found", "external", "user_provided", "no_platform_slug", "below_platform_folder" ] }, "cores": { "oneOf": [ { "type": "null" }, { "type": "array", "items": { "type": "string" }, "uniqueItems": true } ] }, "regions": { "description": "The regions the emulator code selects the file for. Absent when it never competes.", "type": "array", "items": { "type": "string", "enum": [ "argentina", "asia", "asia-ntsc", "asia-pal", "australia", "brazil", "canada", "china", "denmark", "europe", "finland", "france", "germany", "greece", "hong-kong", "india", "italy", "japan", "latin-america", "mexico", "netherlands", "new-zealand", "north-america", "norway", "oceania", "poland", "portugal", "russia", "singapore", "south-korea", "spain", "sweden", "taiwan", "uk", "world" ] }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_groups": { "description": "Groups the file competes in as a core extra, whatever systems are chosen.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "region_system_groups": { "description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "systems": { "description": "Every platform system that declares the file, for the installer's --system.", "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "minItems": 1, "maxItems": 1000, "uniqueItems": true }, "priority": { "description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.", "type": "integer" }, "declared_in": { "description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.", "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } } } }, "root": { "description": "save: dest is relative to the save directory the frontend hands the core (RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY), not to the BIOS directory. Absent for a file of the BIOS tree.", "const": "save" }, "core_folder": { "description": "The core's library_name, the folder a frontend sorting saves by core (RetroArch's sort_savefiles_enable) inserts between its save directory and dest. Only with root: save. Absent on a save entry when the core reads the same place sorted or not.", "type": "string", "minLength": 1, "pattern": "^[^/\\\\]+$" } }, "oneOf": [ { "required": [ "release_asset" ] }, { "properties": { "repo_path": { "type": "string", "pattern": "^bios/" } }, "not": { "required": [ "release_asset" ] } } ] } }, "description": "What a platform's pack installs, one file per entry, as install.py reads it. The platform's list says what the setup checks, this list says what the pack writes: the list's files plus every file the setup's cores load." }