DSH Game Store 中文

DSH Game Store spec

Version 1. 中文

The Game Store is a plugin for DeepSeek Harness (DSH), published as dsh-game-store. This spec covers six things: what a game package looks like, what the store does, how games are listed and taken down, how community features such as message boards live on GitHub, how the Workshop (extensions for games) works, and how the store protects players.

To get started right away, read Publish your game.

1. Terms

TermMeaning
Game packageAn npm package that holds every file of one game
Game manifestgame.json in the package: name, summary, entry, pictures and so on
Catalogcatalog/games/ in the dsh-game-store repository, one small file per game
Catalog entryOne file in the catalog; it points at one exact version of one game package
ChecksumThe sha512-… value npm computes for each version; it changes when one byte changes
StoreThe dsh-game-store plugin installed in DSH

2. The game package

One game is one npm package. The recommended name is dsh-game-<name>. It is also a DSH plugin, so DSH's plugin manager can install, update and remove it.

A game is a local web game: HTML, JavaScript, pictures and sounds that play when the entry page opens.

2.1 Layout

dsh-game-<name>/
├── package.json        npm manifest
├── game.json           game manifest
├── cordis.patch.yml    the standard file, copied unchanged
├── LICENSE             license
├── game/               the game; the entry is in here
│   └── index.html
├── store/              what the store shows
│   ├── icon.png        icon
│   ├── cover.png       cover
│   ├── shot-1.png      screenshot
│   ├── trailer.mp4     video (optional)
│   ├── about.en.md     description (English)
│   └── about.zh.md     description (Chinese)
└── manual/             manual (optional)
    └── index.html

The store opens files from three folders only: game/, manual/ and store/.

2.2 package.json

{
  "name": "dsh-game-my-game",
  "version": "0.1.0",
  "license": "MIT",
  "repository": { "type": "git", "url": "git+https://github.com/you/dsh-game-my-game.git" },
  "icon": "./store/icon.png",
  "files": ["game", "store", "game.json", "cordis.patch.yml", "README.md", "LICENSE"],
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } },
  "dshGame": "./game.json"
}

Required:

Not allowed:

2.3 cordis.patch.yml

Every game package ships the same file, unchanged:

# dsh-game-store spec 1: a game adds no plugin rows.
[]

It tells DSH that the package adds no plugin code to DSH.

2.4 The game manifest game.json

{
  "spec": 1,
  "id": "my-game",
  "name": { "en": "My Game", "zh": "我的游戏" },
  "tagline": { "en": "A short line under the name.", "zh": "名字下面的一句话。" },
  "summary": { "en": "One sentence about the game.", "zh": "一句话介绍。" },
  "author": { "name": "Your Name", "url": "https://github.com/you" },
  "entry": "game/index.html",
  "icon": "store/icon.png",
  "cover": "store/cover.png",
  "screenshots": [
    { "src": "store/shot-1.png", "caption": { "en": "In play", "zh": "游戏画面" } }
  ],
  "about": { "en": "store/about.en.md", "zh": "store/about.zh.md" },
  "manual": { "en": "manual/index.html" },
  "languages": ["en", "zh-CN"],
  "controls": ["keyboard", "mouse", "touch"],
  "players": { "min": 1, "max": 1 },
  "content": { "rating": "everyone" }
}
FieldRequiredMeaning
specyesAlways 1
idyesThe game's name in the store: lowercase letters, digits and hyphens, at most 40 characters. Fixed once listed
nameyesThe game's name, at most 40 characters
taglinenoA tagline, at most 80 characters
summaryyesOne sentence, at most 80 characters
author.nameyesThe author
author.urlnoThe author's page, starting with https://
entryyesThe entry page, an HTML file in game/
iconyesIcon: square, at least 128×128, at most 256 KB
coveryesCover: 16:9, at least 1280×720, at most 2 MB
screenshotsyes1 to 8 screenshots, each at least 960×540 and at most 2 MB; caption is optional
videosnoUp to 3 videos in store/, MP4 or WebM, at most 40 MB each: [{ "src": "store/trailer.mp4", "poster": "store/trailer.jpg", "caption": { "en": "Trailer" } }]. poster and caption are optional
aboutyesThe description: one Markdown file per language, at most 64 KB each
manualnoThe manual: one HTML file in manual/ per language
languagesyesLanguages the game itself supports, such as ["en", "zh-CN", "ja"]
controlsyesAny of keyboard, mouse, touch, gamepad
playersyes{ "min": 1, "max": 4 }
content.ratingyeseveryone, teen (13 and up) or mature (18 and up)
workshopnoPresent when the game takes extensions; see section 8
content.notessometimesContent notes, at most 200 characters. Required for teen and mature: say what the content is

The version and the license are in package.json; the manifest does not repeat them.

Text in several languages: name, tagline, summary, caption and content.notes are a string, or one text per language: { "en": "…", "zh": "…", "ja": "…" }. Language ids are lowercase and en is required. The store shows the text for DSH's interface language and falls back to English.

Pictures: PNG, JPEG or WebP.

2.5 The description

Every game package carries its own description, and the store shows it as it is. It has three parts:

2.6 Entry and how a game runs

When a player clicks Play, the store opens a local address for the game (http://127.0.0.1:<port>/) and shows the page entry names. The game fills the whole DSH window and the window goes full screen.

What a game must do:

2.7 Size

At most 300 MB unpacked.

3. What the store does

FeatureWhat happens
Browse the catalogThe first screen shows the newest game: cover, name, summary and an Install button. All games follow
Game pageEvery game has its own page: videos, cover and screenshots, description, message board, version, author, license, size, languages, controls, players, content rating, npm package, source repository and checksum
InstallOne click installs the version registered in the catalog
PlayThe game fills the window and goes full screen. Moving the pointer to the top edge shows a small strip: Restart, Full screen, Quit game
ManualWhen the package has one, the game page shows a Manual button
UpdateWhen the catalog has a newer version, the button reads "Update to x.y.z"
UninstallRemoves the game's files and keeps the saves
WorkshopA section of the game page: browse, install, switch on and off, and uninstall the game's extensions; see section 8
My GamesLists the installed games
Play in the browserEvery game page on dsh-game-store.com has "Play in the browser", which needs no DSH. The game runs on its own subdomain <id>.play.dsh-game-store.com, from the same files as the package

The store reads the catalog once a day from https://dsh-game-store.com/catalog.json. When it cannot be reached, the last saved copy is used; when there is none, the copy shipped inside the plugin.

A game package installed by hand (dsh plugin add …) also shows under My Games, with a note: it is not in the catalog and the store has not checked it.

4. Listing a game: through GitHub

The catalog is catalog/games/ in the dsh-game-store repository, one file <id>.json per game:

{
  "id": "my-game",
  "package": "dsh-game-my-game",
  "version": "0.1.0",
  "integrity": "sha512-…",
  "repository": "https://github.com/you/dsh-game-my-game",
  "addedAt": "2026-11-13"
}
FieldMeaning
idThe same as the file name and the id in the game manifest
packageThe npm package name
versionOne exact version
integrityThat version's checksum: npm view <package>@<version> dist.integrity
repositoryThe game's GitHub repository
addedAtThe day it was listed
status, reasonFilled in by maintainers when a game is taken down; see section 6

A new game and an update go the same way:

  1. The developer publishes the game package to npm.
  2. The developer opens a pull request against dsh-game-store that adds or changes the file of their game.
  3. CI checks it (section 5.1).
  4. It is merged. A pull request that changes only its author's own entry, comes from the GitHub account that owns the game's repository, and passes every check merges by itself (section 5.3). Anything else waits for a maintainer's review (section 5.2).
  5. The site is rebuilt and the catalog with it. Players' stores see the change within a day, or at once with "Refresh catalog".

Every version goes through a pull request. The catalog names one exact version and its checksum, and the store installs only that. A new version on npm changes nothing for players until the catalog changes.

Why it is built this way:

5. Review criteria

5.1 Automatic checks

CI does the following for every entry. All of it must pass before a merge:

  1. The entry is well formed, and no other entry has the same id or package.
  2. npm has that version, with the checksum the entry names.
  3. The package is downloaded (downloaded only; nothing in it is run) and compared with section 2 point by point: the required and forbidden parts of package.json, the standard cordis.patch.yml, every manifest field, the entry file, the format, dimensions and size of pictures, the English description, a license file, total size, no symbolic links, no programs or script files (.exe, .sh, .node and the like).
  4. The package is installed into an empty folder with install scripts switched off, to confirm it installs and brings in no other package.

When game files load something from the internet, CI warns: the store blocks those requests, so the game would be missing things for players.

Developers run the same checks on their own computer: npx dsh-game-store check <folder or package@version>.

5.2 Content review

Before or after the merge, a maintainer (or an automatic patrol a maintainer set up) installs the game, plays it, and confirms:

For an update, the review looks at what changed.

5.3 Automatic merge

A pull request merges by itself, with nobody waiting, when all of this holds:

  1. It changes only entry files in the catalog (.json under catalog/games/ or catalog/workshop/), at most 3.
  2. The repository of every entry belongs to the GitHub account that opened the pull request. For an existing entry, the previous owner must be that account too. So nobody else can change your entry.
  3. An existing entry keeps its id and package, and its version only goes up.
  4. It does not touch status or reason (takedowns are done by maintainers) and deletes no entry.
  5. Every automatic check of section 5.1 passes.

A game merged this way then goes through content review. If a problem is found, it is delisted or blocked under section 6.

Touching any file outside the catalog means a maintainer looks before the merge.

6. Takedown rules

Maintainers take a game down by changing its catalog entry, through a pull request, so there is a record. There are two levels:

StatusWhenFor players
delistedThe author asks; the author cannot be reached and the game no longer runs; a rights holder has a reasonable complaint; the description does not match the game and the author does not fix itThe game no longer shows in the store and cannot be installed or updated. Installed copies still run, and the game page shows the reason
blockedMalicious behaviour is found: trying to send data out, getting around the limits, attacking the player's computerThe store refuses to start it; the game page shows the reason and asks the player to uninstall

The entry becomes:

{ "…": "…", "status": "delisted", "reason": "Taken down at the author's request" }

7. Community: everything lives on GitHub

The store has no server of its own. The site is static pages, the catalog is files in a repository, and game packages are on npm. Content from players works the same way: the account is a GitHub account, and the content is kept in GitHub repositories.

7.1 Game pages

Every game has its own page: https://dsh-game-store.com/games/<id>/ on the site, and one click on the game in the store. All of it comes from the game package: videos, screenshots, description, manual and the facts. To change the page, a developer publishes a new version.

7.2 Message boards

7.3 Planned (not built yet)

These follow the same approach. They are written down to fix the direction, and will be added to the spec when they exist.

8. The Workshop

Everything is a plugin. The store is a DSH plugin, a game is a plugin, and an extension made for a game is a plugin too. All of them are npm packages, all are registered in the same catalog, and the store installs and removes all of them. An extension can be a map, a commander, a language pack, a skin, a balance change; which kinds exist is up to each game.

8.1 How a game says it takes extensions

A game adds workshop to its manifest game.json:

"workshop": {
  "types": ["map", "language", "commander", "balance"],
  "mount": "game/mods",
  "list": { "path": "game/mods/mods.js", "template": "window.AWModList = {{ids}};" },
  "guide": { "en": "How to write an extension: game/mods/README.md" }
}
FieldMeaning
typesThe kinds of extensions the game accepts. The game picks the names: lowercase letters, digits, hyphens
mountThe folder of the game where extensions appear; it must be inside game/
listOptional. A list file the store writes for the game: path is where (inside mount), and {{ids}} in template becomes the ids of the enabled extensions, such as ["a","b"], in load order
guideOptional. One sentence telling extension authors where to read more

A game without this section takes no extensions.

8.2 The platform only hands extensions to the game

What an extension contains and how the game reads it is each game's own business. The platform fixes only the handover:

The store serves these files directly at the game's local address and copies nothing into the game package. The game package stays exactly as it was installed, and its checksum keeps matching.

What a game must do: when one extension fails, skip it and keep running. The game checks what extensions contain, and tells the player inside the game which extensions are active, which were skipped, and why.

8.3 The extension package

An extension is an npm package. The recommended name is dsh-game-<game id>-<name>.

dsh-game-tidemark-sample-map/
├── package.json
├── extension.json      extension manifest
├── cordis.patch.yml    the same standard file as in a game package
├── LICENSE
└── mod/                the files handed to the game
    └── mod.js

package.json follows the rules of a game package (section 2.2) with one difference: "dshGameExtension": "./extension.json" takes the place of "dshGame": "./game.json".

The extension manifest extension.json:

{
  "spec": 1,
  "id": "sample-map",
  "game": "tidemark",
  "gameVersion": "1.x",
  "types": ["map"],
  "name": { "en": "Sample Map: Three Fords", "zh": "示例地图:三岔河" },
  "summary": { "en": "A small map for two factions.", "zh": "一张两方小地图。" },
  "author": { "name": "Your Name" },
  "files": "mod"
}
FieldRequiredMeaning
specyesAlways 1
idyesThe extension's name, unique within one game. This is the id the game sees
gameyesThe id of the game it extends
gameVersionyesThe game versions it works with; see below
typesyesWhat it adds; each must be a type the game accepts
nameyesName, at most 40 characters
summaryyesOne sentence, at most 120 characters
author.nameyesThe author
filesyesThe name of the folder handed to the game

How to write gameVersion:

ValueMeaning
"1.0"Game 1.0.x
"1.x"Every version starting with 1
"*"Every version
["1.x", "2.0"]Any one of the listed

It is compared with the game package's version (version in package.json).

An extension package is at most 50 MB unpacked.

8.4 Listing an extension

By pull request, like a game. The file is catalog/workshop/<game id>/<extension id>.json:

{
  "id": "sample-map",
  "game": "tidemark",
  "package": "dsh-game-tidemark-sample-map",
  "version": "1.0.0",
  "integrity": "sha512-…",
  "repository": "https://github.com/you/dsh-game-tidemark-sample-map",
  "addedAt": "2026-11-13"
}

CI runs the same checks as for a game, plus two: the game is in the catalog and takes extensions, and the extension's types are ones the game accepts. When the versions an extension asks for do not include the game version in the catalog, CI warns.

The review criteria and takedown rules are those of sections 5 and 6. Making an extension for someone else's game needs no permission from the game's author; a game author who sees a problem with an extension opens an issue.

8.5 In the store

For every game that takes extensions, the game page has a Workshop section:

ActionWhat happens
BrowseLists the game's extensions in the catalog: name, types, summary, author, version, game versions
InstallInstall the game first, then the extension. It is switched on once installed
Switch on, switch offAn extension that is off stays on the computer and is not handed to the game
ReorderWith several extensions installed, one can be moved earlier or later
Update"Update to x.y.z" shows when the catalog has a newer version
UninstallRemoves the extension's files. Uninstalling a game removes its extensions too

Changes take effect the next time the game starts.

8.6 Load order and conflicts

8.7 After a game update

Each time a game starts, the store compares every extension's gameVersion with the installed game version:

A game author who changes the extension interface raises the game's major or minor version, so old extensions are stopped automatically and never load with errors.

8.8 Playing on the site

Games on the site are the game package as it is, with no extensions. Extensions work in the store inside DSH.

9. Safety

Installing someone else's game means running someone else's code on your computer. The store sets the limits below. Some things it cannot do; those are written here as well.

9.1 What the store does

What gets installed

Where a game runs

Extensions

What players can see

Message boards

9.2 What the store cannot do

10. Versions

This is version 1 of the spec; a game manifest says "spec": 1. An incompatible change will be version 2, and the store will accept both for a time so developers can move.

To discuss the spec, open an issue in the dsh-game-store repository.