# Halkyon Train's Linux app as a Snap (decided 3 Nov 2026, ADR 0030, D62), built in LXD # by the release tool (`dart run tool/release.dart train`) as Todo's is: snapcraft # builds one recipe a folder, from its snap/snapcraft.yaml, so the tool builds this one in a clone of the repository at the release's # tag with this folder in place of the clone's snap/ (`SnapRelease.projectPath`), but # for snap/local/, which the recipes share. By hand, the same: in such a clone, # `snapcraft pack`. # # It builds what is committed (the source is the clone's HEAD, the tag), never a # working tree with its build caches, and always for train.halkyon.eu. Flutter is # pinned like the local and CI one (FLUTTER_VERSION in .forgejo/workflows/ci.yaml), # spelled out as in Learn's recipe, which says why. name: halkyon-train title: Halkyon Train base: core24 adopt-info: halkyon-train # the version, from the app's pubspec.yaml summary: Your workouts, routes and training plans, sealed and synced description: | Halkyon Train on the desktop: your runs, walks, hikes, rides and rows with their maps, splits, heart rate and power, the routes you plan on the map, turn by turn, your strength plans with the equipment at each place and the plates to load, and the statistics of your weeks and months. Recording, the Polar Loop and Health Connect are the phone's (Halkyon Train for Android); what the phone records shows here, synced. Everything is sealed on your device with your account's keys before it reaches the instance, which can't read it. You sign in with SimpleLogin, by Proton, or with an email address, a password and an authenticator app. It connects to train.halkyon.eu, the project's instance, or to any other: everything an instance needs is in the repository, to run your own. The app is AGPL-3.0 and the server SSPL-1.0, so all of its code is public. Questions and reports: support@halkyon.app license: AGPL-3.0-or-later source-code: https://code.halkyon.app/halkyon-days/halkyon # The project's, not an instance's: the app works with any instance. website: https://halkyon.app/train # No contact or issues, as Learn's (its recipe says why): the address is in the # description. # The app's icon with rounded corners, made by the repository's tool/app_icons.py; also # the desktop file's. icon: snap/gui/halkyon-train.png grade: stable confinement: strict platforms: amd64: apps: halkyon-train: command: bin/halkyone_train_flutter # How the session is kept: see snap/local/secret-backend (Learn's, kept in the # clone). command-chain: [bin/secret-backend] # GTK, WebKitGTK (the sign-in's page) and libsecret come from the GNOME runtime; # files (GPX, TCX and FIT in and out) and the browser go through the desktop's # portals. extensions: [gnome] plugs: - network # SimpleLogin's sign-in comes back on a loopback address the app listens on. - network-bind # Never connected by itself; whoever connects it by hand gets the keyring. - password-manager-service # As Learn's: the sync's connection ended at once when the network goes; # not connected until the Store grants it. - network-manager-observe parts: flutter: plugin: nil source: https://github.com/flutter/flutter.git source-tag: '3.47.8' source-depth: 1 build-packages: - clang - cmake - curl - git - libgtk-3-dev - lld - llvm-18 - ninja-build - pkg-config - unzip - xz-utils - zip override-build: | mkdir -p "$CRAFT_PART_INSTALL/usr/libexec" "$CRAFT_PART_INSTALL/usr/bin" cp -r "$CRAFT_PART_SRC" "$CRAFT_PART_INSTALL/usr/libexec/flutter" ln -s ../libexec/flutter/bin/flutter "$CRAFT_PART_INSTALL/usr/bin/flutter" ln -s ../libexec/flutter/bin/dart "$CRAFT_PART_INSTALL/usr/bin/dart" "$CRAFT_PART_INSTALL/usr/bin/flutter" --disable-analytics "$CRAFT_PART_INSTALL/usr/bin/flutter" precache --linux # Needed to build, not in the Snap. override-prime: '' halkyon-train: after: [flutter] plugin: nil source: . source-type: git # sodium's build hook compiles libsodium with its configure script and make # (ADR 0017), with the Flutter part's clang. build-packages: - make override-build: | set -eu export PATH="$CRAFT_STAGE/usr/bin:$PATH" cd apps/train/halkyone_train_flutter craftctl set version="$(sed -n 's/^version: *\([^+]*\).*/\1/p' pubspec.yaml)" flutter pub get --enforce-lockfile flutter build linux --release \ --dart-define=SERVER_URL=https://train.halkyon.eu/ mkdir -p "$CRAFT_PART_INSTALL/bin" cp -r build/linux/x64/release/bundle/. "$CRAFT_PART_INSTALL/bin/" secret-backend: plugin: dump source: snap/local organize: secret-backend: bin/secret-backend # As Learn's: every file the GNOME runtime or the base has at the same path # goes, so that nothing staged hides the runtime's own (Learn's recipe says # what that broke there). Train stages no package today; the part keeps a # later one from doing so unnoticed. cleanup: after: [halkyon-train, secret-backend] plugin: nil build-snaps: [core24, gnome-46-2404] override-prime: | set -eu for snap in core24 gnome-46-2404; do cd "/snap/$snap/current/usr" find . \( -type f -o -type l \) -print0 | while IFS= read -r -d '' path; do case "$path" in */blas/* | */lapack/*) continue ;; esac target="$CRAFT_PRIME/usr/$path" if [ -L "$target" ] || [ -f "$target" ]; then rm -f "$target" fi done done