-
Notifications
You must be signed in to change notification settings - Fork 0
CLI Reference
patchforge build \
--source-dir game_v1.0/ \
--target-dir game_v1.1/ \
--output-dir dist/ \
--app-name "My Game" \
--version 1.1 \
--engine hdiffpatch \
--compression set6_lzma2 \
--arch x64Output: dist/MyGame_1.1_patch_x64.exe
Use --patch-exe-name to override the output filename stem:
patchforge build ... --patch-exe-name "MyGame_Update_Nov2025"
# → dist/MyGame_Update_Nov2025_x64.exe| Flag | Default | Description |
|---|---|---|
--project FILE |
— | Load settings from a .xpm project file (CLI flags override) |
--source-dir DIR |
— | Original (old) game folder |
--target-dir DIR |
— | Patched (new) game folder |
--output-dir DIR |
. |
Directory for the output .exe
|
--app-name NAME |
— | Application name shown in the patcher UI |
--app-note TEXT |
— | Short subtitle shown next to the app name |
--version VER |
— | Version string (e.g. 1.1) |
--description TEXT |
— | Optional description shown in the patcher |
--copyright TEXT |
— | Copyright notice shown in the patcher window |
--contact TEXT |
— | Contact email or URL shown in the patcher window |
--company-info TEXT |
— | Publisher / company name shown in the patcher window |
--window-title TEXT |
— | Title bar text of the patcher window (defaults to app name) |
--patch-exe-name STEM |
— | Output exe filename stem (default: auto from app name + version) |
--patch-exe-version VER |
— | Informational version string for the patch exe (e.g. 1.0.0.0) |
--engine ENGINE |
hdiffpatch |
hdiffpatch | jojodiff
|
--compression PRESET |
engine default | Compression preset key (see Engines-and-Presets) |
--threads N |
1 |
Worker threads for patch generation |
--quality LEVEL |
max |
HDiffPatch compressor quality: fast / normal / max
|
--verify METHOD |
crc32c |
crc32c | md5 | filesize
|
--find-method METHOD |
manual |
manual | registry | ini
|
--registry-key KEY |
— | Windows registry key path |
--registry-value VALUE |
InstallPath |
Registry value name |
--ini-path FILE |
— | Path to INI file |
--ini-section SECTION |
— | INI section name |
--ini-key KEY |
— | INI key name |
--arch ARCH |
x64 |
x64 | x86
|
--icon-path FILE |
— |
.ico file to embed as the patcher's icon |
--backdrop FILE |
— | Background image for the patcher window (PNG/JPEG/BMP) |
--extra-args ARGS |
— | Extra CLI arguments passed verbatim to the diff engine |
--delete-extra-files |
on | Delete game files absent from the target version |
--no-delete-extra-files |
— | Keep game files absent from the target version |
--preserve-timestamps |
off | Preserve original file timestamps when applying the patch |
--run-on-startup CMD |
— | Shell command to run when the patcher window first opens |
--run-before CMD |
— | Shell command to run immediately before patching starts |
--run-after CMD |
— | Shell command to run after patching succeeds |
--run-on-finish CMD |
— | Shell command to run when the patcher window closes (always, not just on success) |
--extra-file SRC[:DEST] |
— | Bundle an extra file into the patch exe; optional :DEST sets the relative install path (repeatable) |
--backup-at MODE |
same_folder |
disabled | same_folder | custom
|
--backup-path DIR |
— | Backup directory (used when --backup-at custom) |
--save-project FILE |
— | Save resolved settings to a .xpm after building |
--check |
off | Validate inputs and resolved settings, then exit without invoking the engine |
--quiet / -q
|
off | Suppress progress output (errors still go to stderr); mutually exclusive with --verbose
|
--verbose / -v
|
off | Verbose output (reserved for future debug logging); mutually exclusive with --quiet
|
--json |
off | Emit a single JSON result object on stdout (implies --quiet for progress) |
patchforge new-project --output patch.xpm --app-name "My Game" --engine hdiffpatch
patchforge show-project patch.xpmpatchforge repack \
--game-dir game/ \
--output-dir dist/ \
--app-name "My Game" \
--codec lzma \
--compression max \
--threads 8 \
--arch x64Output: dist/MyGame_1.0_installer_x64.exe
With optional components:
patchforge repack --game-dir game/ --app-name "My Game" \
--component '{"label":"High-res textures","folder":"hires/","default_checked":false,"group":""}' \
--component '{"label":"English voices","folder":"voices_en/","default_checked":true,"group":"voices"}' \
--component '{"label":"Japanese voices","folder":"voices_jp/","default_checked":false,"group":"voices"}'Load a .xpr project file and override individual fields:
patchforge repack --project installer.xpr --threads 16 --output-dir dist/Each --component is a JSON object:
| Key | Type | Description |
|---|---|---|
label |
string | Display name shown in the installer |
folder |
string | Path to the folder of files for this component |
default_checked |
bool | Whether the component is selected by default |
group |
string | Empty = standalone checkbox; shared name = mutually exclusive radio-button group |
requires |
int[] | 1-based indices of components that must be selected for this one to be enabled |
shortcut_target |
string | Overrides the main shortcut target when this component is selected |
sac_warning |
bool | Show an antivirus / Smart App Control warning when this component is selected |
external |
bool | Store this component's compressed stream in a separate .bin sidecar file; components in the same group share one sidecar |
| Flag | Default | Description |
|---|---|---|
--project FILE |
— | Load settings from a .xpr project file (flags override) |
--game-dir DIR |
— | Game directory to compress |
--output-dir DIR |
. |
Directory for the output .exe
|
--app-name NAME |
— | Application name shown in the installer |
--app-note TEXT |
— | Short subtitle shown next to the app name |
--version VER |
— | Version string (e.g. 1.0) |
--description TEXT |
— | Description shown in the installer |
--copyright TEXT |
— | Copyright notice |
--contact TEXT |
— | Contact email or URL |
--company-info TEXT |
— | Publisher / company name |
--window-title TEXT |
— | Installer title bar text (defaults to app name) |
--installer-exe-name STEM |
— | Output exe filename stem (default: auto) |
--installer-exe-version VER |
— | Informational version string for the exe |
--codec CODEC |
lzma |
lzma | zstd
|
--compression QUALITY |
max |
LZMA: fast | normal | max — Zstd: fast | normal | max | ultra
|
--threads N |
1 |
Compression threads (auto-populated from CPU count in GUI) |
--arch ARCH |
x64 |
x64 | x86
|
--icon-path FILE |
— |
.ico file to embed as the installer's icon |
--backdrop FILE |
— | Background image (PNG/JPEG/BMP); displayed at 616:353 aspect ratio |
--install-registry-key KEY |
— | Registry key written to HKCU after install |
--run-after CMD |
— | Shell command to run after successful install |
--detect-running EXE |
— | Warn if this process is running before install |
--close-delay N |
0 |
Seconds before auto-closing after success (0 = stay open) |
--required-free-space GB |
0 |
Warn if disk space is below this threshold in GB (0 = disabled) |
--no-verify-crc32 |
— | Skip CRC32 integrity check after installation (default: enabled) |
--shortcut-target REL_PATH |
— | Relative path to the exe for shortcuts (e.g. Bin\Game.exe) |
--shortcut-name NAME |
— | Shortcut display name (default: app name) |
--shortcut-desktop / --no-shortcut-desktop
|
off | Create a Desktop shortcut |
--shortcut-startmenu / --no-shortcut-startmenu
|
on | Create a Start Menu shortcut |
--component JSON |
— | Add an optional component (repeatable; see above) |
--no-uninstaller |
— | Omit the uninstaller and Add/Remove Programs registration |
--split-bin |
auto | Force the base game archive into a base_game.bin sidecar even below the 3.5 GB auto-split threshold |
--max-part-size-mb MB |
0 |
Split base_game.bin into .001, .002, ... parts of this size in MB (0 = no split) |
--save-project FILE |
— | Save resolved settings to a .xpr after building |
--check |
off | Validate inputs and resolved settings, then exit without invoking the engine |
--quiet / -q
|
off | Suppress progress output (errors still go to stderr); mutually exclusive with --verbose
|
--verbose / -v
|
off | Verbose output (reserved for future debug logging); mutually exclusive with --quiet
|
--json |
off | Emit a single JSON result object on stdout (implies --quiet for progress) |
patchforge new-repack-project --output installer.xpr --app-name "My Game" --compression max
patchforge show-repack-project installer.xprThe CLI uses distinct exit codes so scripts can branch on outcome class:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Generic / unspecified runtime error |
2 |
Argparse usage error (unknown flag, missing required value, mutually-exclusive group conflict, etc.) |
3 |
Input error: missing file/dir, malformed project file, malformed --component JSON, or any failure validating user-supplied data |
4 |
Build error: engine ran but produced an error or non-zero output |
# Validate without building
if patchforge build --project app.xpm --check --quiet; then
echo "settings ok"
fi
# Capture resolved settings as JSON
patchforge build --project app.xpm --check --json | jq .
# {"success": true, "checked": true, "app_name": "My Game", ...}
# Run a build and post-process the result
result=$(patchforge build --project app.xpm --json)
output=$(echo "$result" | jq -r .output_path)
echo "Built: $output"In --json mode the CLI emits exactly one JSON object on stdout, and the exit code still reflects success/failure (so scripts can choose to branch on either the JSON success field or the exit code).
argcomplete provides bash/zsh/fish completion for subcommands and --engine / --codec choice lists. Install it once and register the completer in your shell rc file:
pip install argcomplete
eval "$(register-python-argcomplete patchforge)"PatchForge's CLI is wired up to use argcomplete if it's available; if it isn't installed, the autocomplete call is a silent no-op and nothing else changes.
Steam-side download / poll / upload pipeline. Requires the optional archive extra (pip install patchforge[archive]). See Archive-Mode for the full reference; the most-used subcommands are summarised here.
patchforge archive login # one-shot QR / password
patchforge archive download --project mygame.xarchive # single pass over project apps
patchforge archive download --project mygame.xarchive \
--restart-delay 1800 # poll every 30 min
patchforge archive depot --app 4048390 --depot 4048391 \
--manifest 5520155637093182018 # historical-build pull
patchforge archive show-app 730 # raw product-info for one appid
patchforge archive new-project --output mygame.xarchive
patchforge archive add-app mygame.xarchive 730
patchforge archive add-app mygame.xarchive 4048390 --branch beta --platform linux
patchforge archive remove-app mygame.xarchive 730
patchforge archive show-project mygame.xarchive| Subcommand | Purpose |
|---|---|
archive login |
QR code or password login. Saves a refresh token to archive_credentials.json; subsequent commands reuse it. |
archive logout |
Clear the saved refresh token (web API key + bot tokens are preserved). |
archive show-app APPID... |
Print raw product-info for one or more app IDs (depots, branches, build IDs, DLC). |
archive download |
The main workhorse — single-pass over --app-ids or polling driver over a --project of apps. |
archive depot |
DepotDownloader-style historical pull of a single (--app, --depot, --manifest) triple. |
archive new-project |
Create a fresh .xarchive JSON project. |
archive add-app PROJECT APPID [--branch NAME] [--platform {windows,linux,macos}] [--crack {off,gse,coldclient,all}] |
Append an app to an existing .xarchive. Duplicate app_id → exit 3. --crack sets a per-app override; off skips crack for this app even when the project default enables one. |
archive remove-app PROJECT APPID |
Drop an app from an existing .xarchive. Missing app_id → exit 3. Other state (manifest_history etc.) is preserved. |
archive show-project FILE |
Pretty-print a .xarchive to stdout (with manifest_history summary). |
See Archive-Mode for every flag, the project-file schema, and the BBCode template format.