Monorepo for Aesthetic.Computer
aesthetic.computer
1# FedAC Native Score
2
3`fedac/native` ships a USB-bootable kernel image with embedded initramfs and pieces.
4
5## Definition Of Shipped
6
7All of the following must be true:
8
91. `build/vmlinuz` is rebuilt from current `HEAD`.
102. Release is uploaded to CDN (`upload-release.sh`).
113. CDN metadata and hash verify.
124. Running devices can detect the new version and enter update flow.
135. At least one target medium (USB/internal EFI) is flashed and readback-verified.
14
15## Release Procedure
16
17### Default path: remote OTA via oven (preferred)
18
19OTAs are built remotely on `oven.aesthetic.computer`. After landing
20fedac/native/ changes on `origin/main`, the oven git poller auto-triggers
21a build — but you can also trigger and observe explicitly:
22
23```bash
24ac-os oven # Trigger remote OTA build for HEAD (or push to main)
25ac-os oven status # Show oven build queue + last builds
26ac-os oven watch # Tail logs for the active oven build (SSE)
27ac-os oven cancel # Cancel the active oven job
28```
29
30**This is the path agents should use.** Do NOT run `ac-os upload` to ship an
31OTA — that is the legacy local-build-and-push path; it requires a clean tree
32and has historically clobbered uncommitted work via auto-stash. The oven
33flow is the source of truth for `releases.aesthetic.computer/os/`.
34
35### Local commands (rarely needed)
36
37```bash
38ac-os build # Build binary + initramfs + kernel locally
39ac-os flash # Build + flash USB
40ac-os upload # Local-build + push to OTA CDN (NOT for routine OTAs — use `ac-os oven`)
41ac-os flash+upload # Build + flash + upload
42```
43
44`ac-os` is the preferred path for real devices. It layers user-local credentials
45and repo context into the initramfs on top of the base image:
46
47- Claude OAuth state, when present locally
48- GitHub PAT, when `gh auth token` succeeds
49- Tangled SSH identity, when `ssh -G knot.aesthetic.computer` resolves a local key
50
51### Manual steps
52
53```bash
54cd fedac/native
55
56# 1) Build image
57bash scripts/build-and-flash.sh --skip-binary
58sha256sum build/vmlinuz
59
60# 2) Publish CDN release (updates latest.version/latest.sha256/releases.json)
61bash scripts/upload-release.sh build/vmlinuz
62
63# 3) Verify CDN state
64curl -fsSL https://releases.aesthetic.computer/os/native-notepat-latest.version
65curl -fsSL https://releases.aesthetic.computer/os/native-notepat-latest.sha256
66curl -fsSL https://releases.aesthetic.computer/os/releases.json | jq '.latest'
67```
68
69## Credentials & Secrets
70
71- **DO Spaces (OTA upload)**: `aesthetic-computer-vault/fedac/native/upload.env.gpg`
72 - GPG-encrypted with Jeffrey's key (`77E1473C0FF13AB2`)
73 - Decrypt: `gpg --decrypt aesthetic-computer-vault/fedac/native/upload.env.gpg > /tmp/upload.env`
74 - Contains: `DO_SPACES_KEY`, `DO_SPACES_SECRET`
75- **GPG private key**: `.tmp-key-jeffrey-private.asc` (in repo root, gitignored)
76- **Handle colors API**: `https://aesthetic.computer/.netlify/functions/handle-colors` (public, no auth)
77
78## Device Repo Access
79
80- The on-device working tree lives at `/mnt/ac-repo`.
81- On WiFi connect, AC Native clones or pulls from the public GitHub HTTPS mirror:
82 - `https://github.com/whistlegraph/aesthetic-computer.git`
83- If a Tangled SSH key was baked at build time, the repo is also configured so:
84 - `origin` fetches from GitHub
85 - `origin` push mirrors to `git@knot.aesthetic.computer:aesthetic.computer/core`
86 - `origin` also pushes to the GitHub mirror
87 - `tangled` points directly at the knot remote
88- If no Tangled key is baked, the repo stays GitHub-only for pushes.
89
90## Update Signal Expectations
91
92- Native notepat checks `native-notepat-latest.version` on WiFi connect and periodic background checks.
93- When remote version differs from local `system.version`, UI shows update availability and emits audible notification.
94- Download+flash uses:
95 - `system.fetchBinary(...)` -> `/tmp/vmlinuz.new`
96 - `system.flashUpdate(...)` -> boot EFI partition
97 - `system.reboot()` after successful flash
98
99## USB Flash Methods
100
101### Method 1: build-and-flash.sh (full pipeline)
102
103Builds binary, packs initramfs, compiles kernel, partitions + flashes USB.
104
105```bash
106cd fedac/native
107bash scripts/build-and-flash.sh --flash /dev/sdX
108# Options: --skip-kernel (reuse existing vmlinuz), --skip-binary (reuse ac-native)
109```
110
111Requires privileged access to block devices. In devcontainer, `sfdisk`/`mkfs` may lack permissions.
112
113### Method 2: Docker privileged container (from devcontainer)
114
115When the devcontainer can't directly access block devices, use the Docker host:
116
117```bash
118# 1. Build binary and initramfs inside devcontainer
119cd fedac/native
120make CC=gcc # builds build/ac-native
121bash scripts/build-and-flash.sh --skip-kernel --skip-binary # rebuilds initramfs only
122
123# 2. Rebuild kernel to embed new initramfs (uses cached objects, fast)
124cd build/linux-6.14.2
125make -j$(nproc) bzImage
126cp arch/x86/boot/bzImage ../vmlinuz
127
128# 3. Flash via privileged Docker container (host path: /home/me/aesthetic-computer)
129sudo docker run --rm --privileged \
130 -v /home/me/aesthetic-computer/fedac/native/build:/build:ro \
131 -v /dev:/dev \
132 fedora:41 bash -c '
133 dnf install -y -q dosfstools util-linux
134 DISK=/dev/sdX
135 umount ${DISK}1 2>/dev/null || true
136 sfdisk --force $DISK <<EOF
137label: gpt
138type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, size=512M
139EOF
140 sleep 1
141 mkfs.vfat -F 32 -n ACBOOT ${DISK}1
142 mkdir -p /mnt/efi && mount ${DISK}1 /mnt/efi
143 mkdir -p /mnt/efi/EFI/BOOT
144 cp /build/vmlinuz /mnt/efi/EFI/BOOT/BOOTX64.EFI
145 sync && sleep 1 && sync
146 sha256sum /mnt/efi/EFI/BOOT/BOOTX64.EFI /build/vmlinuz
147 umount /mnt/efi
148'
149```
150
151**Key detail**: devcontainer workspace is at `/workspaces/aesthetic-computer` but the host path is `/home/me/aesthetic-computer`. Docker bind mounts must use the host path.
152
153### Method 3: Reflash existing USB (no repartition)
154
155If USB already has an EFI partition, skip partitioning:
156
157```bash
158sudo docker run --rm --privileged \
159 -v /home/me/aesthetic-computer/fedac/native/build:/build:ro \
160 -v /dev:/dev \
161 fedora:41 bash -c '
162 dnf install -y -q dosfstools
163 mount /dev/sdX1 /mnt
164 cp /build/vmlinuz /mnt/EFI/BOOT/BOOTX64.EFI
165 sync && sleep 1 && sync
166 sha256sum /mnt/EFI/BOOT/BOOTX64.EFI /build/vmlinuz
167 umount /mnt
168'
169```
170
171### Verification
172
173Always verify SHA256 match between source vmlinuz and flashed BOOTX64.EFI:
174
175```bash
176sha256sum build/vmlinuz # local
177# Must match the sha256sum printed inside the docker container
178```
179
180### Device node creation
181
182If `lsblk` shows the USB but `/dev/sdX` doesn't exist in the devcontainer:
183
184```bash
185sudo mknod /dev/sda b 8 0
186sudo mknod /dev/sda1 b 8 1
187```
188
189## OTA Update Hardening (2026-03-11)
190
191Critical fixes applied to the OTA flash path:
192
1931. **posix_fadvise instead of drop_caches**: `drop_caches=3` was destroying tmpfs-backed source file pages. Now uses `POSIX_FADV_DONTNEED` on only the destination file.
1942. **Fresh mount for flash**: Always mounts EFI partition at `/tmp/efi` instead of reusing `/mnt` (which may lack `EFI/BOOT/`).
1953. **EFI directory validation**: Aborts flash if `EFI/BOOT/` not found on mounted partition.
1964. **Source file pre-flight**: Validates source exists and is >1MB before copying.
1975. **Double sync with delay**: `syncfs` + `sync` + 500ms sleep + `sync` before verify and before reboot, giving vfat write-back time to flush.
1986. **Error logging**: syncfs failures, mount failures, and device detection logged with errno.
199
200## Next Features
201
202- **Multitouch input**: Track touch slots in `input.c` (MT protocol B),
203 expose multiple simultaneous touch points to JS pieces via `act({ event })`.
204 Enables chord playing in notepat and multi-finger gestures on 2-in-1 devices.
205- **Firmware blobs**: Add Realtek (RTW88/RTW89), MediaTek (MT7921/MT7925),
206 and Intel SOF audio firmware to initramfs for runtime driver loading.
207- **@sat hardware validation**: Get `lspci -nn` dump from ARDOR NEO G15
208 to confirm WiFi chip and audio codec, then add matching firmware.
209
210## Architecture
211
212See [internals.md](internals.md) for the full boot sequence and system architecture narrative.
213
214## Operational Checks
215
216- USB logs must be checked on every release candidate:
217 - `ac-native.log` for `[fetch]`, `[fetchBinary]`, `[flash]`, `[verify]`, `[mic]`, `[sample]`
218 - `ac-audio.log` for ALSA/capture diagnostics
219- Any `curl exit=77` or cert-path errors are a release blocker.
220- Any repeated mic open/close race errors are a release blocker.
221- Flash verify must report `OK: N bytes match` — any `MISMATCH` is a release blocker.
222
223## Commits from the Device
224
225When a commit is made directly from a running AC native device (via Claude Code on-device):
226
227- **Prefix**: `[ac-native]` at the start of the commit subject line
228- **Body**: Include `Committed from AC native device.` as the last line
229
230Example:
231```
232[ac-native] enable CONFIG_TYPEC, UCSI, UCSI_ACPI for USB-C power role swap
233
234Adds USB Type-C connector class support.
235
236Committed from AC native device.
237```
238
239This distinguishes on-device commits from dev-machine commits in git log.