Experimental Plugins
These CLI plugins are functional but new. They're registered by default in every game-ci binary -
no --plugin flag needed, and nothing extra to install - but expect rough edges, and verify against
a test target (a test repo, a test itch.io channel) before pointing any of them at something real.
Deploy to a GitHub Release
@game-ci/github-release-deploy attaches a built output to a GitHub Release.
GITHUB_TOKEN=... game-ci deploy github-release ./build --repo owner/repo --tag v1.2.3
buildPath may be a single file (uploaded as-is, optionally renamed via --assetName) or a
directory - every top-level file inside it is uploaded as a separate asset, named after itself.
Re-running against the same tag is idempotent: an existing release for that tag is reused, and an
asset that already exists on it is replaced rather than failing.
| Option | Description |
|---|---|
--repo | owner/repo. Defaults to $GITHUB_REPOSITORY. |
--tag | Release tag. Required. |
--releaseNotes | Release body/description. |
--draft | Create the release as a draft. |
--prerelease | Mark the release as a prerelease. |
--assetName | Override the uploaded asset's file name (single-file buildPath only). |
--targetCommitish | Commit/branch to create the tag from, if it doesn't already exist. |
GitLab Release support isn't included in this first version.
Deploy to itch.io
@game-ci/itch-deploy wraps itch.io's official butler push CLI.
BUTLER_API_KEY=... game-ci deploy itch ./build --user myuser --game mygame --channel windows
Requires butler already installed and on PATH (or pass --butlerPath explicitly - recommended
for CI determinism). This plugin doesn't install butler for you.
| Option | Description |
|---|---|
--user | itch.io username or organization. Required. |
--game | itch.io game slug. Required. |
--channel | Channel to push to, e.g. windows, linux, web. Required. |
--butlerPath | Explicit path to the butler executable. |
--userVersion | Custom version string shown in itch.io's build history. |
--ignore | Comma-separated glob patterns excluded from the push. |
Publish a Steam Workshop item
@game-ci/steam-workshop uploads a Workshop item (a mod, map, or asset pack) via SteamCMD's
workshop_build_item.vdf path - distinct from @game-ci/steam-deploy's full-game upload.
STEAM_USERNAME=... STEAM_PASSWORD=... game-ci deploy steam-workshop ./my-mod --appId 480 --title "My Mod"
Omit --publishedFileId to publish a new item; pass it to update an existing one.
Sign and notarize a build
@game-ci/code-signing signs (and, on macOS, notarizes and staples) a built player.
APPLE_ID=... APPLE_TEAM_ID=... APPLE_APP_SPECIFIC_PASSWORD=... game-ci \
sign ./build/Game.app --platform macos --identity "Developer ID Application: Studio Name (TEAM123)"
Windows signing goes through signtool sign instead, via --platform windows and either
--certificatePath or --certificateThumbprint.
Pseudo-localization QA
@game-ci/pseudo-localization injects pseudo-loc strings pre-translation, to catch UI
overflow/truncation and missing-localization bugs before real translation work starts.
game-ci pseudo-localize ./Localization
Reads a flat key→string localization table - <projectPath>/<sourceLocale>.json or .csv - and
writes the pseudo-localized result to <projectPath>/<outputLocale>.<same format>. Engine-specific
structured formats (e.g. Unity's binary StringTable assets) aren't supported yet.
Bevy engine support
@game-ci/bevy detects a Bevy project - a real bevy dependency in
Cargo.toml, not just any Cargo project - and builds/tests it via cargo build
--release/cargo test --release. Detection is automatic; point build/test at the project like
you would for any other engine:
game-ci build ./my-game
game-ci test ./my-game
--target is only needed for cross-compilation (e.g. --target x86_64-pc-windows-gnu to build a
Windows binary from a Linux runner) - omit it to build for the runner's own host toolchain, which is
what most CI jobs want.
Detection isn't specific to Bevy - build/test inspect the project directory for every engine
this way. If you need to skip that (e.g. a project whose structure confuses auto-detection, or you
just want to be explicit), pass --engine=bevy to force it:
game-ci build ./my-game --engine=bevy
| Option | Applies to | Description |
|---|---|---|
--target | build, test | Rust target triple. Builds for the host toolchain when omitted. |
--features | build, test | Comma-separated cargo features to enable. |
--locked | build, test | Fail instead of updating Cargo.lock. Default true. |
--debug | build | Build in debug mode instead of --release. Default false. |
--outputPath | build | Directory to copy the built binary into. |
Cross-compilation via --target assumes the target's toolchain and any required linkers are
already installed (e.g. via rustup target add, or a cross-based custom Docker image) - this
plugin doesn't set that up for you. Doesn't yet resolve workspace-inherited dependencies
(bevy.workspace = true) for detection - a known gap for workspace-structured projects.
Planned plugins
These are registered as structural drafts only - the command shape exists, but no domain logic is written yet, and invoking them throws. Not usable today; listed here so the roadmap is visible.
| Plugin | What it will do |
|---|---|
@game-ci/anti-cheat | Wrap a build with an anti-cheat SDK's own packaging step. |
@game-ci/dedicated-server-provisioning | Provision/deploy a built dedicated server to hosting infrastructure. |
@game-ci/dev-tunnel | Expose a local dev build through a public tunnel for remote playtesting. |
@game-ci/gamemaker | Build a GameMaker project via Igor (needs a real licensed GameMaker install to verify against). |
@game-ci/renpy | Build a Ren'Py visual novel project. |
@game-ci/rpg-maker | Build an RPG Maker project (no official CLI exists yet to verify a real invocation shape against). |
@game-ci/save-data-compat | Validate save-data compatibility across engine/build versions. |
@game-ci/screen-capture | Capture gameplay footage/screenshots during an automated test run (GPU-required). |
Interested in one of these? Open an issue on game-ci/cli - the plugin interface is stable, so implementing the domain logic for any of these is a scoped, self-contained contribution.