Auto-Update & CI
Kalam uses Tauri v2's built-in updater (tauri-plugin-updater) for automatic updates.
Architecture
GitHub Releases latest.json → updater plugin → useUpdateChecker hook → UpdateBanner component
The latest.json is auto-generated by tauri-apps/tauri-action@v0 during CI (via includeUpdaterJson: true) and uploaded as a release asset — no manual manifest management needed.
Signing Keys (One-Time Setup)
Generate an Ed25519 keypair for update verification:
npm run tauri signer generate -- -w $HOME\.tauri\kalam.key
Creates:
$HOME\.tauri\kalam.key— PRIVATE KEY. Store in GitHub Secrets. Never commit.$HOME\.tauri\kalam.key.pub— PUBLIC KEY. Embedded intauri.conf.jsonplugins.updater.pubkey.
Building with Signing (Local)
$env:TAURI_SIGNING_PRIVATE_KEY = "C:\Users\You\.tauri\kalam.key"
$env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD = "your-password"
npm run tauri build -- --bundles msi
.env files do NOT work — you must use real environment variables.
GitHub Secrets Needed
| Secret | Value |
|---|---|
TAURI_SIGNING_PRIVATE_KEY | Base64-encoded content of kalam.key (use [Convert]::ToBase64String(...)) — avoids YAML newline mangling |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD | Password chosen during key generation |
GITHUB_TOKEN | Auto-provided by GitHub Actions |
CI Signing Fix (Important)
Problem: GitHub YAML strips newlines when expanding ${{ secrets.X }} directly in the env: block. The PEM key gets truncated to just the first line.
Fix: Store the key as base64, decode to a temp file in a workflow step:
- name: Decode signing key
shell: pwsh
run: |
$bytes = [Convert]::FromBase64String("${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}")
$path = Join-Path $env:RUNNER_TEMP "kalam.key"
[IO.File]::WriteAllBytes($path, $bytes)
echo "TAURI_SIGNING_PRIVATE_KEY=$path" >> $env:GITHUB_ENV
Also add these fallbacks for a known Tauri bug:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
Testing the Update UI Locally
- Create a
latest.jsonand serve it locally:python -m http.server 8765 - Temporarily change the endpoint in
tauri.conf.jsontohttp://localhost:8765/latest.json - Bump the version in
latest.jsonabove the localtauri.conf.jsonversion - Run
npm run tauri dev— the UpdateBanner should appear
HTTP is only allowed in dev mode. Release builds require HTTPS.
Release Workflow
Triggers: workflow_dispatch (manual version input) or push tag v*.
Steps:
- Extract version from tag / manual input
- Write version into
tauri.conf.json - Decode base64 signing key to temp file
- Rust dependency cache (
Swatinem/rust-cache@v2) — cuts compile from ~20 min to ~2-3 min - Single
tauri-actionstep — builds, creates draft GitHub Release, uploads MSI +.sig, generateslatest.json
Release Process
- Update version in
app/src-tauri/tauri.conf.jsonandapp/package.json - Commit:
git commit -m "v0.2.0" - Tag and push:
git tag v0.2.0 && git push origin v0.2.0 - GitHub Actions handles the rest
- Manually publish the draft on GitHub Releases page
Common Pitfalls
| Issue | Cause / Fix |
|---|---|
No .sig files | TAURI_SIGNING_PRIVATE_KEY not set during build, or createUpdaterArtifacts missing |
| Signature rejected | Public key in config doesn't match the private key used to sign |
| Update not detected | Endpoint must match https://github.com/Comp-Tech-Guy/Kalam/releases/latest/download/latest.json |
| Lost private key | All existing installs permanently unable to receive updates. Store in password manager + GitHub secrets. |
| Private repo | The endpoint URL is unauthenticated — make repo public or host latest.json elsewhere |
| CI "Missing comment in secret key" | Key newlines lost in YAML env: block. Use base64+temp file workaround. |
Tauri Configuration
{
"bundle": { "createUpdaterArtifacts": true },
"plugins": {
"updater": {
"active": true,
"endpoints": ["https://github.com/Comp-Tech-Guy/Kalam/releases/latest/download/latest.json"],
"dialog": false,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEZFM0FGNkNBM0QzRTg3NkUKUldSdWh6NDl5dlk2L3BmanBHRGNLa3I2N2tKQUUvam1TWWZiYitOUllBVzFSWmVGL2QrRE93b2QK"
}
}
}