Versions and releases
For maintainers: version identity, packaging and publication.
Synoec is a technical alpha. The development version is in the root
package.json. A release ships a Mac .dmg and a Windows .exe installer,
each with its .sha256; that is all a release publishes. The
changelog lists every release, the
source-only tags and the asset-only tags (memory-coreai-v1 and the NInfer
runtime mirror that Local AI setup downloads). Project
status describes tested behavior and known limits. A version bump, source tag, signed
package and published release are separate steps, and each needs its own
authorization.
To run Synoec today, use Getting started and the desktop build guide.
Choose the version
Section titled “Choose the version”Bump only when cutting a release, by compatibility and behavior, not changed-line counts (rules in TESTING.md).
| Command | Use |
|---|---|
bun run release:suggest |
Suggest an increment from commit messages since the last tag |
bun run release:version patch|minor|major|X.Y.Z[-beta.N] |
A fix release, a feature release, a breaking change, or an exact version, with a pre-release suffix below 1.0 if wanted |
The command rewrites the root and app manifests, packages/shared/src/product-version.ts
and bun.lock. It does not build, commit, tag, push or publish. Between bumps
every build carries its build number and commit, so About and
synoec --version identify the exact build.
Tag a source milestone
Section titled “Tag a source milestone”Only when a milestone is authorized: commit the reviewed tree, then annotate and push the exact version together.
git tag -a vX.Y.Z -m "Synoec X.Y.Z source milestone"git push --atomic origin HEAD refs/tags/vX.Y.ZA tag does not imply packaging or publication.
Package
Section titled “Package”bun run release:packageThis packages the CLI, builds the portable Electron app, assembles it and
packages the Mac app. It requires a macOS host, the pinned Bun, a clean
committed tree and an assembled app whose version matches package.json.
Outputs go to the ignored release/cli/ and release/desktop/ directories
with checksums and manifests. Inspect the actual archive contents and
installation on each platform you claim.
The Windows installer is packaged on a Windows host (or any host with NSIS) after the same build and assembly:
bun run desktop:package:windowsIt writes release/desktop/synoec-windows-vX.Y.Z-x64.exe with .sha256 and
.manifest.json. It needs NSIS 3 makensis on PATH or in MAKENSIS, the
pinned Bun, a clean committed tree and an assembled Windows app of the current
version. The manual Desktop Windows acceptance and installer workflow does
all of this and keeps the installer as a two-day artifact once acceptance
passes. The installer is per user (no administrator prompt) and its
uninstaller keeps user data; After copying the app
it sets up Git for Windows (reusing one already installed, otherwise the
pinned official PortableGit), then it shows a found Ollama (with an option to start it with Synoec), offers
Bonsai 2 on Synoec’s Local AI service on a supported NVIDIA card, with an
unticked Image generation box and its extra download on an 11 GB card, sums
up and downloads the runtime and model; the app connects Ollama and starts Bonsai at
first launch. The installer’s
first page chooses Upgrade (keeps everything), Install fresh (removes
the app’s data, keeps the downloaded local AI) or Remove (everything,
models included). Silent installs take /S /MODE=install|upgrade|remove /OLLAMA=1 /OLLAMASTART=1 /BONSAI=1 /BONSAIIMAGE=1. The app’s Update control runs
/S /NCRC /MODE=upgrade /UPDATE=<process id>, which waits for that app to exit,
replaces the files and reopens Synoec, skipping the Git, probe and Bonsai steps.
Upgrading by hand does not offer a Bonsai 2 that is already on the computer;
it offers only image generation, when that is not there yet.
Release workflow
Section titled “Release workflow”The Release workflow (.github/workflows/release.yml) builds and publishes a
release without switching machines. It runs only when a v* tag is pushed, or
when started by hand for a tag that is already pushed; ordinary pushes never run
it.
bun run release:version …, add the changelog entry, commit.git tag -a vX.Y.Z[-beta.N] -m "Synoec X.Y.Z[-beta.N]"andgit push --atomic origin HEAD refs/tags/vX.Y.Z[-beta.N].- The workflow checks the tag matches
package.json, builds and packages the Windows installer onwindows-latestand the Mac.dmgonmacos-26, uploads both with their.sha256to a draft, then publishes it as Latest with notes that state the signing limits.
If the release already exists (a rerun, or a download added later), the
workflow replaces this version’s downloads on it and keeps its notes. A manual
run can skip the Mac job (mac: false), or build another branch or commit to
diagnose a build (source), which is never published.
Both jobs fetch the pinned assets a fresh checkout lacks
(context-embedding:fetch, rea:fetch). The Mac job also runs
memory-coreai:fetch: the MiniLM archive (memory-coreai-v1) and the prebuilt
Core AI helper (memory-coreai-helper-v1), which needs the macOS 27 SDK that
hosted runners lack. The build refuses the helper unless its manifest matches
the current CoreAIMemory.swift; after changing that file, build the helper
(memory-coreai:build), publish it as the next memory-coreai-helper-vN
asset-only pre-release and update core-ai-helper-release.json. A test fails
until the pin matches the source.
The Mac job signs with the persistent Apple Development identity from two
repository secrets, MAC_SIGNING_CERTIFICATE_P12 (the base64 of the exported
.p12) and MAC_SIGNING_CERTIFICATE_PASSWORD; without them it stops, since
ad-hoc signing is not allowed. Adding them is the owner’s step. A failed run
leaves no published release; rerun it by hand for the same tag.
Signing and notarization
Section titled “Signing and notarization”The Mac package is certificate signed with the persistent local identity and
not notarized; its manifest records notarized: false and the DMG says so.
There is no Developer ID notarization lane yet. The Windows installer is
not code signed; its manifest records signing: "unsigned" and SmartScreen
warns on first run. Identity selection and the
macOS privacy-permission caveats are in desktop signing.
Publish
Section titled “Publish”bun run release:publish creates a draft GitHub release for the version tag,
which must already be pushed (gh release create --verify-tag), with only this
version’s user downloads: the Mac .dmg (required) and the Windows .exe
(when present in release/desktop/), each with its .sha256. It refuses a Mac
manifest for another bundle identifier and any download whose bytes no longer
match its manifest and checksum. It does not require notarization, since no
notarization lane exists; it prints a note for the unnotarized Mac package and
for each unsigned download, and the release text must say so. The CLI tarball, Mac .zip and manifests are not
uploaded. After review, publish the draft as Latest by hand. Publish only when
a release is explicitly authorized; a testing distribution must state its real
signing and platform limits.
Optional model assets (such as the Core AI memory archive) are versioned and published separately with pinned descriptors. Never replace bytes behind an existing pin.
Verification
Section titled “Verification”Use TESTING.md for proportionate checks. A release candidate
needs its release gate plus platform and install evidence; a commit or tag does
not. The Release workflow runs on a v* tag or a manual
dispatch only; the older push-triggered workflows stay disabled under
.github/workflows-disabled/.
Limits
Section titled “Limits”- The Windows installer is unsigned. Install and uninstall on a clean machine are checked by hand through the acceptance workflow, not by an automated gate.
- Mac packages are not notarized, so macOS Gatekeeper may block them when downloaded.
- The app reads its GitHub releases with a built-in read-only key
(
apps/desktop/assets/release-access.json, staged asruntime/release-access.json), shortly after it opens and every six hours; Settings → General → Check for Updates does so on demand. It asks for the repository’s latest release, which GitHub never resolves to a draft or prerelease, so the NInfer mirror is skipped. A release whosevX.Y.Zis above the app’s version puts an Update control above the Profile on the left rail. It downloads the release’s installer to the app’s data folder and runs it. On Windows that shows no pages: the app shuts down normally, the files are replaced and Synoec reopens. If the app stays open while quitting, because the person chose to keep editing unsaved drafts, the update does not run. On a Mac the disk image opens. With no published release it finds nothing; trust its reported status, not an endpoint you cannot reach.
Related
Section titled “Related”- Licensing — notices that must ship with artifacts
- Changelog
- Desktop signing
Decisions behind this page: 0132, 0196, 0240, 0244, 0286 — see the decisions index.