Living dev note. Iterate freely.
Goal: skip the R2 release pipeline when iterating on nymph against multiple remote daemons. Today the inner loop is:
With nymph push, it becomes:
Trades a CDN/R2 step for a controlplane endpoint. Fine for debug fleets; not a replacement for tagged R2 releases.
Surface
Output (human form):
Server endpoints
Two new admin-authed routes in lakeshore-controlplane:
The download path is un-authed (matches /v1/daemon/* patterns) —
auth is by knowing the SHA. Daemons OTA via the existing daemon update command, pointing at this URL.
Storage
v1: Mongo blob. Nymph is ~4 MB; Mongo's 16 MB document limit is
plenty of headroom. New collection NymphRelease with shape:
Pros: zero new infrastructure, works on Heroku immediately, blob is durable.
Cons: bloats mongo backups; reads pull 4 MB through Prisma per download. For debug-fleet use (a handful of daemons, few releases per day) this is fine. If usage grows, swap to S3 with a signed URL.
CLI plumbing
- New
src/cli/nymph/module —push.ts,list.ts,index.ts. - Re-uses the existing admin auth (
LAKESHORE_ADMIN_TOKEN). - Detects target triple from ELF magic + machine field. Reject Mach-O (friendly hint to cross-compile).
--updateflag glues into the existingrunDaemonUpdatefromsrc/cli/daemon/update.ts— same--all/--prefixsemantics.
Out of scope (v1)
- Garbage collection / TTL on releases. Hand-prune via
nymph delete <sha>for now (add the verb if/when it's annoying). - Signing / verification beyond sha256. The download URL embeds the sha; the daemon recomputes and compares.
- Multi-target uploads in one command. Push each separately.
Tests
- Server: upload → list → download → verify sha. Concurrent uploads of the same binary collapse to one row (uniqueness on sha256).
- CLI: file-not-found → exit 2; Mach-O input → friendly error; happy path → POSTs multipart and prints the URL.
Open question
- Do daemons need to resolve the URL? The existing OTA path
takes a URL. If the controlplane URL changes (Heroku ⇄ prod), old
daemons holding a controlplane-relative URL get stuck. Maybe the
CLI prints a fully-qualified URL based on
LAKESHORE_URL. Thendaemon updatejust curls it.