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
- Bump
manifest.jsonversion when shipping installers (keep CHANGELOG in sync). - Add a
## X.Y.Z — YYYY-MM-DDsection toCHANGELOG.md. - Commit + merge to
main. - 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
- Deploy Pages (
website/) so Changelog + Downloads match the tag. - Sync the public mirror so
sparklang-dev/sparklangmatches 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.