- TypeScript 60.1%
- Shell 25%
- Svelte 12.4%
- JavaScript 2.2%
- HTML 0.3%
|
Some checks failed
imager / build (--linux, false, linux) (push) Failing after 19s
imager / build (--mac, true, macos) (push) Successful in 1s
imager / build (--win, true, windows) (push) Successful in 1s
images / compute (push) Successful in 15s
images / build-live (amd64, , false) (push) Has been skipped
images / build-live (arm64, , true) (push) Has been skipped
images / build-iso (amd64, false) (push) Has been skipped
images / build-iso (arm64, true) (push) Has been skipped
images / finalize (push) Has been skipped
Replace the ad-hoc, manually versioned CI with two independent
semantic-release streams so releases are cut from the commit history
instead of by hand.
Pipelines: merge the separate kiosk-iso.yml and live-image.yml
workflows into a single images.yml. Both built OS images and already
shared triggers, runners and publishing logic, so keeping them apart
duplicated the release plumbing and made it impossible to version them
together.
Releases: add two streams isolated by commit scope --
.releaserc.images.json (tagFormat images-v${version}, scopes
live-image/os-install, changelog CHANGELOG.images.md) and
imager/.releaserc.json (tagFormat imager-v${version}, scope imager,
changelog imager/CHANGELOG.md). Scope-filtered release rules keep a
commit in one area from bumping the other stream. Supporting scripts:
scripts/seed-version-tags.sh for the one-time 0.0.0 seed tags,
imager/scripts/publish-imager-release.sh and
imager/scripts/extract-release-notes.mjs for the Forgejo asset upload,
and imager/scripts/release-mac-local.sh for local macOS builds.
Fix the Forgejo `act` parse failure: `continue-on-error` is unmarshalled
into a bool, so the `${{ matrix.gated }}` expression previously used
there aborted parsing of the whole workflow. Replaced with a gate-step
pattern that evaluates the condition in an `if:` instead.
Gate the optional legs (live-image arm64, imager windows/macos) so they
no-op green until their runners exist, and resolve the monorepo checkout
to wiederdabei/avatar@master.
Add a root .gitignore for the ephemeral npm project the images workflow
creates in the repository root, and per-target electron-builder artifact
names for the new Windows nsis/portable and macOS dmg/zip outputs.
|
||
|---|---|---|
| .forgejo/workflows | ||
| imager | ||
| live-image | ||
| os-install | ||
| scripts | ||
| shared | ||
| .gitignore | ||
| .releaserc.images.json | ||
| AGENTS.md | ||
| CHANGELOG.images.md | ||
| DECISIONS.md | ||
| README.md | ||
image-builder — DIY-Avatar device images
This repo builds and delivers the device images for the DIY-Avatar telepresence kiosk (a self-hosted system that lets a long-term-sick child attend class remotely). It holds the three ways to get a kiosk onto hardware, plus the shared provisioning contract they all speak.
It contains no application source. The kiosk stack itself — the
install-device.sh provisioner, the Python agent, the kiosk-shell web UI, the
backend — lives in the main DIY-Avatar monorepo. This repo was migrated (with its
git history) out of that monorepo so the image/installer/flasher tooling can build
and release independently.
The three parts
| Directory | What it builds | Publishes to | Docs |
|---|---|---|---|
live-image/ |
A live USB kiosk image (live-build + an appended writable AVATARCFG config partition). Boots the full kiosk from a read-only system in RAM; nothing is installed, the laptop's disk is untouched. |
rolling kiosk-live release |
live-image/README.md |
os-install/ |
An unattended installer ISO (Debian netinst repacked with a preseed + a first-boot provisioner). Wipes the target disk and installs a permanent kiosk. | rolling kiosk-installer release |
os-install/README.md |
imager/ |
A cross-platform desktop flasher GUI (Electron + Svelte, RPi-Imager-like). Picks a prebuilt live image, injects settings into its AVATARCFG partition, and flashes a USB — no dd, no manual partitioning. |
rolling imager release |
imager/README.md |
How they relate
live-image/produces whatimager/consumes. The imager downloads thekiosk-liverelease asset (or takes a local.img), injectsavatar-config.tomlinto the sameAVATARCFGpartitionbuild-live.shseeds, and flashes it. The image pipeline is unchanged by the imager.live-image/andos-install/are two paths to the same kiosk. The live image runs from the stick and leaves no trace (good for "a kiosk for a day"); the installer dedicates an old laptop to be a kiosk forever. Both end up with an identical, provisioned kiosk. See the comparison table in live-image/README.md.live-image/is a cross-repo build.build-live.shstages the kiosk stack into the live-build chroot, so it needs a checkout of the main DIY-Avatar monorepo passed via theDIY_AVATAR_SRCenv var (or--src). Without it the build errors out immediately. In CI, theimages.ymlworkflow checks the monorepo out into a sibling path and passes it through.os-install/andimager/have no such dependency.
Shared contract
shared/provisioning.ts defines the ProvisioningPayload
contract (server URL + device token + optional wifi/audio/language) and its
isProvisioningPayload type guard. It is the single source of truth for the
first-boot provisioning payload that:
- web-admin encodes into the first-run QR code,
- the live kiosk scans and applies (writing
avatar-config.tomlback to the stick), - the imager accepts to prefill its settings form.
It is vendored here (a copy also lives in the main app repo, where web-admin
imports it) and consumed by the imager via a @shared/* path alias — not duplicated
inside imager/.
Build & release at a glance
# Live USB image (needs a monorepo checkout via DIY_AVATAR_SRC):
DIY_AVATAR_SRC=/path/to/diy-avatar ./live-image/build-live.sh amd64
# Unattended installer ISO:
./os-install/build-iso.sh amd64
# Desktop flasher (node 20–22 + node-gyp toolchain; see imager/README.md):
pnpm --dir imager install && pnpm --dir imager run build
Each part's README documents its own prerequisites, flashing, booting and public URLs.
CI
CI runs on Forgejo Actions, two workflows (images.yml + imager.yml) under
.forgejo/workflows/:
| Workflow | Builds | Rolling release tag |
|---|---|---|
images.yml |
live USB image (amd64 required, arm64 gated) | kiosk-live |
images.yml |
installer ISO (per-arch matrix) | kiosk-installer |
imager.yml |
desktop flasher (Linux required; win/mac gated) | imager |
All of them use the same rolling-release pattern: resolve-or-create the release by tag, then per-asset delete-then-upload via the Forgejo API. Requirements to publish:
- a
CI_PUSH_TOKENsecret (repo WRITE) — the same secret every workflow uses to create the release and upload/replace its assets; - an enabled Actions runner on this repo (a
dockerrunner with outbound internet for the live-image/imager builds; the live-image build additionally needs a privileged container for loop devices, the imager build does not); - for the gated legs (live-image arm64, imager Windows/macOS), a dedicated
runner/toolchain before they can be un-gated — a macOS
.dmgin particular needs a real macOS runner and cannot be built inside the Debian CI container.
Repo map
image-builder/
├─ live-image/ # live USB kiosk image (live-build + AVATARCFG) → kiosk-live
├─ os-install/ # unattended installer ISO (netinst + preseed) → kiosk-installer
├─ imager/ # cross-platform desktop flasher GUI (Electron) → imager
├─ shared/ # provisioning.ts — ProvisioningPayload contract (vendored)
└─ .forgejo/ # Forgejo Actions workflows (one per part)
See DECISIONS.md for the rationale behind the imager's design and
the split-repo migration, and AGENTS.md for a fast orientation map.