Correction: the spec is on branch streamline-jelly-provisioning, not violent-wombat (that is the worktree directory's name). Commit 824035a1, docs/superpowers/specs/2026-09-15-app-blueprints-design.md.
Blueprints: set an app up from what it declares, with one operator click (Jelly as the worked example) Feature Request open
Standing up one Jelly team today is DEPLOY.md's nine steps and about twenty carlos invocations, repeated per team. The person types HOST four times (route, domain, JAM_ORIGIN, sending address), mints JAM_INSTANCE_KEY with openssl, learns that store grant is operator-only from a 403, and keeps the DNS records and Google redirect URIs in their head.
Proposal, with Jelly as the worked example. The spec is docs/superpowers/specs/2026-09-15-app-blueprints-design.md on branch violent-wombat, PR to follow.
A blueprint rides in the release manifest (additive, beside capabilities, from .carlos/blueprint.json). It holds:
- inputs to ask for (
SITE,HOST,FROMdefaulting tojelly@{{HOST}}) envrendered from them (JAM_ORIGIN = https://{{HOST}})- secrets to generate, only when absent (
hex:32,vapid) - the
email/store/schedulesneeds, each with awhysentence followups: the owner's remaining work, with values rendered
Templates are {{NAME}} substitution only, and a bad reference is refused at ship.
Setting up a new app from a blueprint is one form or carlos setup start. It becomes a request at setup/requests/<sqid>/<app>.json (console-only, outside the fleet read ACL). A console pass walks it through the existing doors, resumably:
- claim app → release → config → email → store → schedules → instance → domain → restart
- email, store and domain wait in parallel, each with a visible state and clock
- a step gives up after 72h, and a re-run resumes it
The one-click approval needs no new authority. Of the seven things Jelly needs, only object storage is operator-gated, and the self-serve store spec already made that decision per account, with a queue at /fleet/store and keymail to operators. Setup applies on the owner's behalf with the blueprint's why as the note, and the queue row shows the whole ask. Approving is one click, once per account. A need marked required: false (Jam's store: blobs fall back to disk) doesn't hold the instance up.
A status page shows progress, one DNS table with live check state (host CNAME, DKIM / MAIL FROM / SPF), follow-ups as secret fields that write through the ordinary config door, and what an operator is being waited on for.
Ruling (James, 2026-09-15): a team is an app. Email, store, schedules and releases are per app, and per-instance email/store is ruled out. That leaves the question of where a team app's releases come from:
- phase 2 copies the pinned version into the new app, with no box change
- phase 4 adds a
release_appfield to instance records, so adoption reads the source's pointer and artifacts
Phase 4 touches registry columns, adoption's shape match and bake-hold keys. It is same-account only, because a box reads only apps/<own sqid>/**.
Phasing: (1) blueprint package, ship validation and carlos setup plan; (2) client-side carlos setup start over existing doors, plus release copy; (3) request record, console pass, status page, form and /fleet/store context; (4) release source.
Open questions (spec §13):
- Should an admin, not only an owner, be able to apply for storage through a setup?
- What happens to existing team apps when a later release's blueprint adds a need?
- Should an app be able to serve on the platform host first and swap origin when the domain is live? That is dangerous for passkeys.
- Is phase 2's copy fan-out worth shipping, or wait for phase 4?
- May a blueprint ask for a pipeline ladder?
- Inbound mail: Jam reads
JAM_RECEIVING_DOMAINandJAM_SES_HOOK_SECRET, and DEPLOY.md doesn't mention them.
Non-goals: the SES sandbox/cap (deployment-wide), minting Google OAuth clients (no API), cross-account setup, re-applying a blueprint to an existing app, teardown.