Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

ac-m4l: PIPELINE.md — future options + credential map

Freezes the notepat.com build/distribution pipeline state we just
shipped and logs five deferred options for later:

1. Migrate archive to releases-aesthetic-computer to strictly
parallel ac-os's OTA layout.
2. GC old <hash>.amxd objects on S3 (retention policy).
3. Version-browser page on /ableton so users can roll back.
4. Auto-prune the equivalent local dir on lith.
5. Generalize build-notepat.mjs to build any featured device.

Also documents the current credential source map (spaces/.env.gpg
for AWS creds, oven/deploy.env.gpg for DO_TOKEN) and the 10-bucket
Spaces inventory with a copy-paste inspection recipe.

+189 -6
+183
ac-m4l/PIPELINE.md
··· 1 + # Notepat.com M4L Build & Distribution Pipeline 2 + 3 + Versioned build stream for the `notepat.com.amxd` Max for Live device. 4 + Modeled after the `ac-os` OTA pattern (`fedac/native/ac-os`): every 5 + lith deploy that touches an amxd input rebuilds from the deployed 6 + commit, versions the artifact by git hash, and pushes to DO Spaces as 7 + the long-term archive. 8 + 9 + ## Layout 10 + 11 + ### Local (repo + lith filesystem) 12 + 13 + ``` 14 + system/public/m4l/ 15 + ├── notepat.com.amxd ← current alias (committed) 16 + └── notepat.com/ 17 + ├── latest.json ← manifest (committed, drives staleness check) 18 + └── <git-hash>.amxd ← immutable versioned build (gitignored) 19 + ``` 20 + 21 + ### DO Spaces archive 22 + 23 + ``` 24 + s3://assets-aesthetic-computer/m4l/notepat.com/ 25 + ├── notepat.com.amxd ← root alias (non-cached) 26 + ├── latest.json ← rolling pointer (no-cache) 27 + └── <git-hash>.amxd ← immutable (max-age=31536000,immutable) 28 + ``` 29 + 30 + CDN: `https://assets.aesthetic.computer/m4l/notepat.com/<hash>.amxd` 31 + 32 + ### User-facing permalink 33 + 34 + ``` 35 + https://notepat.com/amxd 36 + └─ Caddy rewrite → /m4l/notepat.com.amxd (lith-served) 37 + with Content-Disposition: attachment 38 + ``` 39 + 40 + ## Commands 41 + 42 + - `npm run notepat:build` — build to local paths only 43 + - `npm run notepat:build:desktop` — also drop a copy on `~/Desktop` 44 + - `npm run notepat:publish` — build + sync to DO Spaces from dev machine 45 + (requires `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` or 46 + `DO_SPACES_KEY` / `DO_SPACES_SECRET` in env) 47 + - `fish lith/deploy.fish` — deploys lith; rebuilds the amxd on the 48 + server (with `--if-stale`) and pushes to DO Spaces (with 49 + `--sync-spaces`) when `spaces/.env(.gpg)` is available in the vault 50 + 51 + ## `--if-stale` 52 + 53 + Skips the rebuild when no amxd-input file changed since the last 54 + successful build. Tracked inputs (`INPUT_PATHS` in 55 + `ac-m4l/build-notepat.mjs`): 56 + 57 + - `system/public/aesthetic.computer/disks/notepat-remote.mjs` 58 + - `system/public/aesthetic.computer/bios.mjs` 59 + - `system/public/aesthetic.computer/lib/` 60 + - `oven/bundler.mjs` 61 + 62 + Compares: 63 + 64 + 1. Committed diff (`prev.piece_git…HEAD`) under those paths 65 + 2. Uncommitted working-tree changes under those paths (only when dirty) 66 + 67 + If both are empty → skip. Otherwise rebuild and print the offending 68 + files. 69 + 70 + ## Staleness UX 71 + 72 + `bios.mjs` fetches `/m4l/notepat.com/latest.json` on DAW bridge setup, 73 + compares `packGit` (from the offline bundle) against `piece_git`. The 74 + notepat-remote piece surfaces `UPDATE AVAILABLE` inside its 75 + case-doors readout when the two differ. 76 + 77 + ## Future options 78 + 79 + These are tracked for later — nothing urgent. 80 + 81 + ### 1. Move the archive to `releases-aesthetic-computer` 82 + 83 + The ac-os OTA already lives in 84 + `s3://releases-aesthetic-computer/os/`, with `builds/<slug>.vmlinuz` 85 + for versioned kernels and `latest-manifest.json` for the rolling 86 + pointer. Mirroring that layout for m4l would strictly parallel the 87 + OS pattern: 88 + 89 + ``` 90 + s3://releases-aesthetic-computer/m4l/notepat.com/ 91 + ├── builds/<git-hash>.amxd 92 + ├── notepat.com.amxd 93 + └── latest.json 94 + ``` 95 + 96 + Requires: 97 + - Caddy rule for `releases.aesthetic.computer` (or update the piece 98 + to fetch from the `releases-*` CDN subdomain) 99 + - Migrate existing archived builds from `assets-*/m4l/notepat.com/` 100 + (or leave them — they stay reachable under the old path) 101 + 102 + ### 2. Garbage-collect old `<hash>.amxd` builds on S3 103 + 104 + Every deploy with an amxd-input change adds a new immutable 105 + `<hash>.amxd` object. After a few dozen commits the bucket will 106 + accumulate obsolete versions. Options: 107 + 108 + - A scheduled cron on lith (or as part of deploy.fish) that keeps 109 + the latest N builds + anything under 30 days old, deletes the rest. 110 + - Mirror ac-os's `builds/` subdirectory with slug names + retention 111 + policy. 112 + 113 + ### 3. Version-browser page under `/ableton` 114 + 115 + All published versions sit at predictable paths, so a 116 + `ListObjectsV2` against the bucket can power a "browse past 117 + releases" section on the ableton piece. Users could roll back to a 118 + specific hash if a recent build regressed, or compare SHA-256s when 119 + something looks off. 120 + 121 + Would need: 122 + - Backend endpoint listing `m4l/notepat.com/<hash>.amxd` objects 123 + (either a cached JSON or a live S3 list) 124 + - UI in `disks/ableton.mjs` to render the list + per-version 125 + download buttons linking to the S3/CDN URLs 126 + 127 + ### 4. Auto-prune `system/public/m4l/notepat.com/` on lith 128 + 129 + Similar to (2) but for the local filesystem on lith. Currently 130 + `<hash>.amxd` files accumulate in `/opt/ac/system/public/m4l/ 131 + notepat.com/` (they're gitignored so they don't sync down). Not 132 + user-visible unless someone guesses the URL structure, but eats 133 + disk. A `find -mtime +30 -delete` in deploy.fish would handle it. 134 + 135 + ### 5. Multi-device generalization 136 + 137 + `build-notepat.mjs` is hardcoded to `notepat-remote`. If another 138 + piece gets promoted to a flagship amxd, the script should generalize 139 + to a list (like `ac-m4l/devices.json` already has). Would refactor 140 + into `ac-m4l/build-device.mjs <piece-name>` and update the deploy 141 + step to iterate devices flagged `featured: true`. 142 + 143 + ## Credential sources 144 + 145 + | What | Vault path | Used by | 146 + |------|-----------|---------| 147 + | `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` | `aesthetic-computer-vault/spaces/.env.gpg` | `build-notepat.mjs --sync-spaces`, `assets:sync:up` | 148 + | `DO_TOKEN` | `aesthetic-computer-vault/oven/deploy.env.gpg` | `doctl` commands, `ac-lith` droplet lookup | 149 + | `ART_SPACES_*`, `AT_BLOBS_SPACES_*` | `aesthetic-computer-vault/oven/.env.gpg` | `oven/baker.mjs`, `oven/grabber.mjs` | 150 + 151 + The deploy flow decrypts `spaces/.env.gpg` on-the-fly, scp's to 152 + `/tmp/notepat-spaces.env` on lith for the lifetime of the build step, 153 + and removes it. S3 keys don't persist in `/opt/ac/system/.env`. 154 + 155 + ## DO Spaces inventory 156 + 157 + As of 2026-04-24 the account has 10 buckets in `sfo3`: 158 + 159 + - `art-aesthetic-computer` 160 + - `assets-aesthetic-computer` ← **m4l archive lives here** 161 + - `at-blobs-aesthetic-computer` 162 + - `pals-aesthetic-computer` 163 + - `pix.nopaint.art` 164 + - `private-aesthetic-computer` 165 + - `releases-aesthetic-computer` ← **ac-os OTA target** 166 + - `sotce-aesthetic-computer` 167 + - `user-aesthetic-computer` 168 + - `wand-aesthetic-computer` 169 + 170 + Inspect with: 171 + 172 + ```bash 173 + TMP_ENV=$(mktemp) 174 + gpg --batch --pinentry-mode loopback \ 175 + -d aesthetic-computer-vault/spaces/.env.gpg > "$TMP_ENV" 176 + set -a; source "$TMP_ENV"; set +a 177 + 178 + aws s3 ls --endpoint-url "$SPACES_ENDPOINT" 179 + aws s3 ls "s3://assets-aesthetic-computer/m4l/notepat.com/" \ 180 + --endpoint-url "$SPACES_ENDPOINT" 181 + 182 + rm -f "$TMP_ENV" 183 + ```
system/public/m4l/notepat.com.amxd

This is a binary file and will not be displayed.

+6 -6
system/public/m4l/notepat.com/latest.json
··· 1 1 { 2 2 "name": "notepat.com", 3 - "version": "110c359993afbf1f17cda2fd07a9b241373c0a2a-dirty", 4 - "piece_git": "110c359993afbf1f17cda2fd07a9b241373c0a2a", 3 + "version": "12a160ead4205b9b555a1aec24c819b548331094-dirty", 4 + "piece_git": "12a160ead4205b9b555a1aec24c819b548331094", 5 5 "dirty": true, 6 - "built": "2026-04-24T20:07:01.429Z", 6 + "built": "2026-04-24T21:22:23.559Z", 7 7 "amxd": { 8 8 "filename": "notepat.com.amxd", 9 - "versionedPath": "/m4l/notepat.com/110c359993afbf1f17cda2fd07a9b241373c0a2a-dirty.amxd", 9 + "versionedPath": "/m4l/notepat.com/12a160ead4205b9b555a1aec24c819b548331094-dirty.amxd", 10 10 "aliasPath": "/m4l/notepat.com.amxd", 11 11 "permalink": "https://notepat.com/amxd", 12 - "sizeBytes": 1167417, 13 - "sha256": "c9b5c5d707f6209f323c670ebc1d99f2fb70c82c07b511fdce48ef3827ade597" 12 + "sizeBytes": 1167857, 13 + "sha256": "3c5da89fb4784fdb3455a0991a947b43681f9c6a0f3d6633c038d48abbe5b635" 14 14 } 15 15 }