SparkLang release process

Version source

  • Runtime / installer kit version: website/downloads/manifest.json"version"
  • User-facing notes: CHANGELOG.md (mirrored at /CHANGELOG.html)
  • CLI: ./spark --version

Cutting a release

  1. Bump manifest.json version when shipping installers (keep CHANGELOG in sync).
  2. Add a ## X.Y.Z — YYYY-MM-DD section to CHANGELOG.md.
  3. Commit + merge to main.
  4. Tag and publish a GitHub Release from that commit:
git tag -a vX.Y.Z -m "SparkLang X.Y.Z"
        git push origin vX.Y.Z
        gh release create vX.Y.Z --title "SparkLang X.Y.Z" --notes-file - <<'EOF'
        See CHANGELOG.md for X.Y.Z.
        Installers: https://sparklang.dev/downloads.html
        EOF
        
  1. Deploy Pages (website/) so Changelog + Downloads match the tag.
  2. Sync the public mirror so sparklang-dev/sparklang matches the tagged tree.

Public mirror sync

Development happens in the private repo. The public repo sparklang-dev/sparklang is a generated mirror with its own history: each sync adds one normal commit, so every push fast-forwards. There is no force-push and no history rewrite.

scripts/sync-public-mirror.sh --check   # stage + scrub + gate, no writes
        scripts/sync-public-mirror.sh           # also commit in the mirror clone
        scripts/sync-public-mirror.sh --push    # also push to sparklang-dev
        

Defaults: source ref origin/main, mirror clone $HOME/workspaces/sparklang-public, branch main. Override with --ref / --public-dir or SPARK_MIRROR_REF / SPARK_PUBLIC_DIR. Merges and pushes take /tmp/spark-bc-merge.lock.

Rules are data, not code, and live next to the script:

File Purpose
scripts/public-mirror/exclude.txt Paths never mirrored (private reports, host-specific agent rules)
scripts/public-mirror/scrub.sed Text substitutions (repo slug, MIT copyright holder)
scripts/public-mirror/forbid.txt Patterns that must have zero matches
scripts/public-mirror/overrides/ Public variants of files that need different content

forbid.txt is a hard gate: it runs on the staged tree before any commit or push, and any match aborts the sync. Add a pattern there whenever you add an exclusion or substitution, so an accidental un-exclude fails loudly instead of shipping.

To verify a push without credentials:

curl -sI https://github.com/sparklang-dev/sparklang | head -1   # 200
        git clone --depth 1 https://github.com/sparklang-dev/sparklang.git /tmp/pubverify
        grep -rIlE --exclude-dir=.git 'PATTERN' /tmp/pubverify | wc -l   # 0
        

Maintainer

Public source: GitHub org sparklang-dev / https://github.com/sparklang-dev/sparklang — no private store or personal ops data on the public site. Private development remains Michael20251/sparklang.

CLI names: spark / ./spark-bootstrap remain the UX entrypoints. Product name in docs/site is SparkLang.

Notes

  • Do not invent token/cost numbers in release notes.
  • Dry-run remains the default story; live gateway is optional.