Skip to content

Repository files navigation

AltGen icon

AltGen

Python versionsPyPI versionMIT license

Generate AltStoreapps.json source files from GitHub Releases IPA assets.

Static app metadata (name, bundle identifier, icon and screenshot URLs, descriptions…) comes from a TOML config; everything dynamic (version, build version, release date, download URL, file size, release notes) is read live from the GitHub Releases API.

GitHub Releases API ──┐
├──► altgen ──► apps.json
app config TOML ──────┘

Install

pip install altgen
altgen --version

Requires Python ≥ 3.10.

Usage

One TOML config = one app = one apps.json:

altgen -c piliplus.toml # writes apps.json next to the config
altgen -c piliplus.toml -o out/piliplus.json # override output path

Or skip the config file entirely for a quick single-app source (any CLI flag overrides its TOML counterpart):

altgen --repo owner/App --app-name App --bundle-id com.owner.app -o apps.json

Hosting many sources is just many configs — loop over them or use a CI matrix, one altgen -c <config> per app.

Merge sources

Combine several apps.json files into one source (e.g. host many apps under a single source while keeping one config per app):

altgen merge a.json b.json -o merged.json
altgen merge -c merge.toml a.json b.json # root values + output from TOML
altgen merge --name MySource --tint-color "#00AEEF" a.json b.json
  • apps are taken from the inputs and sorted by name (case-insensitive); news entries from all inputs (root news plus each app's news) are combined and sorted newest-first.
  • Root values (name, subtitle, description, icon_url, website, tint_color) come from the CLI flags or the config's [source] table — same rules as build mode, and --name (or [source] name) is required.
  • Merge configs only support [source] and [output] tables; build-mode tables ([github], [app], …) are rejected.
  • A duplicate bundleIdentifier or duplicate news identifier across inputs is an error (exit 2).

See examples/merge.toml for a full merge config.

GitHub token

Unauthenticated requests are limited to 60/hour; a token raises that to 5,000/hour. Precedence: --token > GITHUB_TOKEN env var > [github] token.

TOML schema

Only [github] repo, [app] name, and [app] bundle_identifier are required. Keys are snake_case in TOML and become the AltStore camelCase JSON keys (bundle_identifierbundleIdentifier, icon_urliconURL, min_os_versionminOSVersion, …). Unknown keys are rejected with an error.

See examples/piliplus.toml for a full example.

[github]
repo = "owner/App"# REQUIRED: GitHub repo with releasestoken = ""# optional (see above)
[source] # the source this apps.json describesname = "App"# defaults to the repo namesubtitle = ""description = ""icon_url = ""# omitted from JSON when unsetwebsite = ""tint_color = "#00AEEF"# must be #RRGGBB
[app] # the app inside the sourcename = "App"# REQUIREDbundle_identifier = "com.x.y"# REQUIREDdeveloper_name = ""# defaults to the repo owner (CLI mode)subtitle = ""description = ""# fallback when a release body is emptyicon_url = ""# falls back to [source].icon_urlscreenshots = ["https://…"]
tint_color = ""# falls back to [source].tint_colormin_os_version = "14.0"# omitted from versions when unset
[versions]
strip_v_prefix = true# tag "v1.2.3" → version "1.2.3"include_prereleases = false# drafts are always skippedasset_pattern = "\\.ipa$"# regex, case-insensitive search on asset namebuild_version_pattern = "\\+(\\d+)\\.ipa$"# group 1 = buildVersion; no match → key omitted# version_pattern = "…" # optional: extract version with this regex instead of the tag# (for projects whose tags lack a version); no match → tag-derived version# version_source = "release" # where version_pattern runs: "release" (default, release name) or "filename" (IPA asset name)max_versions = 1# default: newest version only; 0 = all versions
[news]
enabled = truetitle_template = "{name} {version} - {date}"# default; placeholders: {name} {version} {tag} {date} (e.g. 07 Aug 2026)caption_template = ""# optional; default: "{name} {version} is available."image_url = ""# optional; omitted from JSON when unset# news appID = [app] bundle_identifiermax_entries = 0# 0 = unlimited; caps after sorting; news already limited to releases kept by max_versions
[output]
path = "apps.json"# resolved against THIS file's directory

Behavior notes

  • Versions are sorted newest-first by (date, version); one version entry per matching release asset. A release with several IPAs produces several entries — sharing one version by default, or one version each when version_source = "filename".
  • The version is the release tag by default (strip_v_prefix strips a leading v). For projects whose tags carry no version (e.g. youproextra-ipa2), set version_pattern to extract it from the release name or IPA filename instead; on no match the version falls back to the tag-derived value.
  • By default only the newest version is emitted (max_versions = 1); set max_versions = 0 (or --max-versions 0) to include all versions.
  • News follows the same convention: one news entry per release, kept only when that release still has a version entry after the max_versions cap. Matching is by release, not by version string, so several releases that resolve to the same version (e.g. a date-bearing tag like release-v1.2.3-2026-08-21 vs ...-2026-08-14) each get their own news entry only while their version entry survives the cap. [news] max_entries can further cap the list.
  • News entries follow the AltStore spec: appID first (the app's bundle_identifier), a full ISO date timestamp, identifier derived from the release tag (release-<tag>), and an optional imageURL; title_template / caption_template support {name}, {version}, {tag}, {date} placeholders.
  • A release with no matching asset contributes nothing — not even a news entry. One news entry is emitted per release that has assets.
  • Empty output (no releases, only drafts, …) is a valid source: altgen warns on stderr and exits 0.

CLI

altgen [-c PATH] [--repo OWNER/REPO] [--token TOKEN]
[--name] [--subtitle] [--description] [--icon-url] [--website] [--tint-color]
[--app-name] [--bundle-id] [--developer-name] [--app-subtitle]
[--app-description] [--app-icon-url] [--app-tint-color] [--min-os-version]
[--screenshots URL …] [--include-prereleases] [--max-versions N]
[-o PATH] [-q] [-v] [--version]
altgen merge APPS_JSON… [-c PATH] [--name] [--subtitle] [--description]
[--icon-url] [--website] [--tint-color] [-o PATH] [-q]
  • Without -c, --repo, --app-name, and --bundle-id are required (build mode).
  • --max-versions N caps the output after sorting (newest first); it defaults to 1 (latest version only) and 0 means all versions.
  • CLI flags override TOML values; -o resolves against the current directory while [output] path resolves against the config file's directory (so a config next to its sources works from any CWD).
  • altgen merge combines apps.json files; see Merge sources.
  • -v logs skipped releases (draft / prerelease / no matching assets) to stderr; -q silences the success message.
  • Exit codes: 0 success, 1 GitHub, IO, or write error, 2 usage or configuration error.

Development

pip install -e ".[dev]"
pytest # fully offline — fixtures captured from the GitHub API

About

Generate AltStore apps.json source files from GitHub Releases IPA assets.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages