sprite-apps · git:20261016.500a153 · 2026-10-16 · sha256 7e8be425bf7bcd7b

sprite-apps git:20261016.500a153A

Immutable. This exact content never changes and is served at /api/v1/blob/7e8be425bf7bcd7b.

---
name: sprite-apps
description: >-
  Umbrella workflow for building and shipping web apps with Elixir, Ash, and
  Phoenix on Fly Sprites. Use when creating, restructuring, reviewing, or
  deploying a Phoenix/Ash app that runs on a Sprite, or when a web app build
  should compose software-design, observability, web-design, and fly-io
  judgment in one pass instead of treating them as separate reviews.
---

# Sprite Apps

**sprite-apps is an umbrella skill. It does not replace the skills under it;
it composes them, in order, for one kind of build: an Elixir/Ash/Phoenix web
app that runs on a Fly Sprite.**

The overlap with `fly-io` is deliberate. `fly-io` answers how the platform
works: CLI and API contracts, limits, networking, storage, current docs.
sprite-apps answers how we build the app that runs there: domain shape, code
judgment, interface design, telemetry, and the Sprites app pattern below.
When the two disagree about a platform fact, `fly-io` and current official
docs win; sprite-apps holds no platform contracts of its own.

## Load order

1. **Domain first.** If the domain model is unsettled, use `ddd` to settle
   the ubiquitous language and invariants before designing modules.
2. **`software-design`** for module and interface judgment: deep modules,
   information locality, one canonical statement per fact, design for the
   fresh reader.
3. **Web design** — [references/web-design.md](references/web-design.md):
   the interface discipline for every screen. Less is perfection; motion
   directs attention.
4. **The stack** — [references/elixir-ash-phoenix.md](references/elixir-ash-phoenix.md):
   Elixir, Ash, and Phoenix conventions for this build, including the
   Elixir anti-patterns pass.
5. **`observability`** for telemetry: instrumentation ships in the same
   change as the behavior it explains.
6. **`fly-io`** (its Sprites reference) for every platform operation:
   creating the Sprite, services, URL exposure, checkpoints, exec, and
   current limits. Verify commands against local help and current docs.

## The Sprites app pattern

One Sprite runs one app. These are our architectural commitments on top of
the platform, not platform guarantees:

- **Co-locate app and database.** The Phoenix release and Postgres run as
  two services in the same Sprite (`sprite-env` is the supervisor; there is
  no systemd). The app service claims the one HTTP port (8080) and is
  declared as needing Postgres, and the app still waits for Postgres itself
  before migrating and booting.
- **The database is never exposed.** Postgres listens on loopback and its
  unix socket only. Its only client lives in the same box, so it needs no
  public port and no public TCP.
- **Design to one origin.** A Sprite has exactly one public URL. An app
  that needs two distinct hosts or origins does not fit one Sprite; decide
  that before building, not at deploy time.
- **State lives on the persistent filesystem**, under one data directory:
  database files, socket dir, generated secrets. Boot is idempotent and
  safe after an unclean shutdown: processes start fresh on a cold wake, so
  nothing may depend on a process having survived.
- **Filesystem persistence is not a backup.** Ship `pg_dump` to object
  storage (S3-compatible, e.g. Tigris) and a tested restore as part of the
  app. A checkpoint is filesystem rollback; it is not an
  application-consistent database backup.
- **Secrets are generated, never committed.** First boot generates what the
  app needs (database password, Phoenix secret key base) onto the
  persistent disk with owner-only permissions. Everything else is
  environment configuration. Generate secrets with a tool that cannot be
  killed mid-write by a closed pipe; first-boot-only failures hide exactly
  there.
- **Memory is the wake cost.** Idle pause is automatic and clients must
  reconnect. Keep the boot path and resident footprint lean; a heavy app is
  a slow, expensive wake.

## Build order

1. Settle the domain language and invariants; name Ash resources after
   them.
2. Design each screen against the web-design reference before building it.
3. Implement in Ash and Phoenix per the stack reference, with
   `software-design` judgment at every module boundary.
4. Add observability in the same change: structured terminal records,
   closed result and reason vocabularies, and a `/health` endpoint that
   does a real database round trip, wired as the platform check.
5. Run the anti-patterns pass and the full test suite. Ship nothing with
   compiler warnings.
6. Deploy and operate through the `fly-io` skill's Sprites contracts.

## Verify before claiming done

- Full test suite green, warning-free build.
- Live end-to-end check against the running Sprite, not the local copy.
- `/health` passing live, doing its real dependency round trip.
- Live logs grepped for what must never appear: secrets, passphrases, and
  user content. Zero hits is the pass bar.
- Backup written and restore rehearsed into a separate database.
- For a stateful app, a restart check: kill the app and database, cold
  start, confirm committed data survived.

Report per discipline, not just "done": the web-design verdict, the
software-design calls made, the observability evidence, and the deploy
evidence each get a line.