Skip to content

Release

Pre-release checklist

Run these locally before tagging anything — the CI pipeline (.github/workflows/ci.yml) currently only enforces the lockfile, so tests/lint/build are on you to verify:

bash
npx vitest run
npm run lint
npm run build

Then confirm the lockfile is actually in sync (see the rule below):

bash
npm ci

If npm ci fails, package-lock.json is out of sync with package.json — fix that before tagging, not after (see why below).

The lockfile rule (non-negotiable)

package-lock.json is regenerated only via npm install — never hand-edited. Release tags (v*) must point at a commit whose lockfile is in sync with package.json.

This is enforced by .github/workflows/ci.yml, which runs npm ci (Node 22) on every push/PR to main. It exists because the v0.1.2 release once failed: the tag pointed at a commit with a hand-edited, out-of-sync lockfile, npm ci requires exact sync, and the fix landed on main after the tag had already been cut — so the tag never saw it. Only tag a commit that's already on main and already green on this check.

Cutting a release

  1. Bump the version in both places (they should match):
    • src-tauri/tauri.conf.json"version"
    • package.json"version" (if you version it there too)
  2. Commit the version bump:
    bash
    git add src-tauri/tauri.conf.json package.json package-lock.json
    git commit -m "chore: bump version to v0.1.x"
    git push
  3. Wait for main's CI (lockfile check) to pass on that commit.
  4. Tag and push the tag:
    bash
    git tag v0.1.x
    git push --tags
  5. .github/workflows/release.yml picks up the v* tag: runs on a Windows runner with Node 22, npm ci, then tauri-action, which builds a signed NSIS installer plus latest.json and publishes a GitHub Release titled "Kairo <tag>". Signing uses the TAURI_SIGNING_PRIVATE_KEY secret, matched against the public key embedded in src-tauri/tauri.conf.json.
  6. The in-app updater (src/features/settings/lib/updater.ts) picks up the new release automatically — it polls https://github.com/SeiynJie/Kairo/releases/latest/download/latest.json, which the release workflow just published to.

After a release

  • Sanity-check the GitHub Release page: installer asset + latest.json both present.
  • Optionally install the new version locally and use Settings -> Updates -> Check for updates (Settings & Updates) on the previous version to confirm the update prompt actually appears and installs cleanly.

Why "Check for updates" currently errors

The in-app updater fetches https://github.com/SeiynJie/Kairo/releases/latest/download/latest.json (see step 6 above), and that URL must be publicly reachable — the Tauri updater plugin's fetch is unauthenticated. With the repo currently private, GitHub returns a 404 for that URL, so check() throws and the user sees an error toast. Right now there are also zero published releases, which is the immediate cause even if the repo were public.

To make updates actually deliver, do one of:

  • (a) Make the repo (or at minimum its Releases) public, and cut a release per "Cutting a release" above, or
  • (b) Host latest.json plus the signed installer assets at a public URL of your own and point plugins.updater.endpoints in src-tauri/tauri.conf.json at that URL instead of the GitHub Releases URL.