CI/CD and Packaging
Relevant source files
The following files were used as context for generating this wiki page:
Crisp utilizes a structured CI/CD pipeline and automated packaging system designed to deliver a native macOS application alongside experimental machine learning models. The system is built around three distinct release channels—Stable, Nightly, and Dev—each with its own identity, bundle ID, and update cadence. The packaging process ensures that the application is self-contained by bundling a Python-based cleaning engine and necessary binaries like FFmpeg and Whisper-CLI.
The automation strategy relies on GitHub Actions for release management, specialized shell scripts for local and CI builds, and a Python-based publishing flow for Hugging Face-hosted ML models. Promotion from experimental stages to stable release is strictly gated by automated verification scripts to ensure that red builds never reach the end-user.
Sources: CLAUDE.md:37-67, apps/desktop/build.sh:5-24
Build Channels and Versioning
Crisp is organized into three parallel channels. This separation allows for simultaneous testing of development features, nightly integrations, and stable releases without interference between installations.
| Channel | Application Name | Bundle Identifier | Update Feed | Icon Color |
|---|---|---|---|---|
| Stable | Crisp | com.syntaxlabtechnology.crisp | GitHub (Main) | Blue |
| Nightly | Crisp Nightly | com.syntaxlabtechnology.crisp.nightly | GitHub (Nightly Tag) | Amber |
| Dev | Crisp Dev | com.syntaxlabtechnology.crisp.dev | Disabled (Local only) | Purple |
Sources: CLAUDE.md:83-93, apps/desktop/build.sh:9-25
Version Calculation Logic
Version strings are derived from the git commit count to ensure they are monotonic and never go backwards, which is critical for the Sparkle-based update system.
- Stable Version: Formatted as
0.<total commit count on main>. - Nightly Version: Orders by the CI
CrispBuildNumberwith a cosmetic0.<count>-nightlystring. - Build Metadata: For non-stable builds, the branch and short SHA are injected into
Info.plistasCrispBuildInfo.
Sources: CLAUDE.md:78-81, apps/desktop/build.sh:71-92
Application Build Pipeline
The build.sh script orchestrates the entire compilation and packaging flow for the macOS application. It targets the arm64 architecture exclusively for Apple Silicon Macs.
The Build Workflow
The diagram below illustrates the sequence of operations performed during a standard build:
This flow describes the internal stages of building the Crisp desktop application, from compilation to final code signing.
Sources: apps/desktop/build.sh:27-190, apps/desktop/Scripts/vendor.sh:5-15
Engine Vendoring and Bundling
Crisp includes a "cleaning engine" that must be self-contained within the .app bundle. The vendor.sh script downloads and verifies pinned versions of external tools.
- FFmpeg/FFprobe: Downloaded as pre-built binaries.
- Python: A stripped-down
python-build-standaloneruntime. - Whisper-CLI: Built from source using
cmakeduring the vendoring process. - Crisp Helpers: Swift-built tools like
crisp-fillerandcrisp-embedare moved intoResources/engine/bin.
Sources: apps/desktop/build.sh:50-68, apps/desktop/Scripts/vendor.sh:22-85
Release and Promotion Workflow
The transition of code from development to stable release is managed by two primary GitHub Actions workflows and a promotion script.
Promotion Mechanism
Promotion from nightly to main is automated via .github/scripts/promote.sh. It avoids standard Git merge conflicts by setting the main branch's tree to exactly match the nightly branch's tree, resulting in a single squash commit per release on main.
Sequence of events during the automated weekly promotion of the Nightly branch to Main.
Sources: CLAUDE.md:46-61
Model Publishing and HF Integration
Machine Learning models (specifically the Wren filler detection model) follow a parallel release flow hosted on Hugging Face (HF).
HF Model Channels
Model channels mirror the app channels to prevent unverified models from reaching stable users.
- Staging: Models are published to the
nightlybranch of the HF repository. - Stable: Models are promoted to the
mainbranch once tested. - Versioning: Model versions are determined by the HF repository commit count (
0.0.N).
Sources: research/filler_classifier/publish_hf.py:9-30, research/NOTES.md:214-230
Model Packaging Structure
Published models include a manifest that the Crisp app polls for updates.
| File | Description |
|---|---|
<Name>.mlmodel | The Core ML model file used by the macOS app. |
<Name>.pt | Raw PyTorch weights for research transparency. |
<Name>.config.json | Manifest containing version, SHA256, and tuning parameters. |
README.md | The generated Model Card. |
Sources: research/filler_classifier/publish_hf.py:108-124, research/NOTES.md:144-150
Code Signing and Security
Crisp uses an "inside-out" signing strategy. Every Mach-O executable bundled within the app (including the Python binary and FFmpeg) is signed before the final app bundle is sealed.
- Ad-hoc Signing: Default behavior (
-) for local builds. - Developer ID: Required for notarization; adds hardened runtime and timestamps via
CODESIGN_IDENTITY. - Bundle Structure: Mach-Os are located in
Contents/MacOSandContents/Resources/engine/bin.
Sources: apps/desktop/build.sh:170-189
Conclusion
The CI/CD and packaging system in Crisp ensures a reproducible environment for a complex application that bridges Swift, Python, and C++ (Whisper). By utilizing separate channels and automated promotion, the project maintains a high bar for stability while allowing rapid iteration on ML models and desktop features.
Sources: CLAUDE.md:78-100, research/NOTES.md:214-220