---
name: scaffold-bare-metal-feature-defaults
description: Use this skill when the user wants to choose or write down the feature defaults for a new AI-native application in the Bare Metal Software style - sign-in, roles, tenancy, audit trail, files, search, reports, backups, jobs, and the rest of the two-dozen features almost every app needs - and turn them into a committed spec. Triggers on requests like "spec out the defaults for my new app," "apply Bare Metal Software's feature catalog to this project," "what should our auth/backup/jobs setup be," or "help me fill in the feature defaults sheet."
---

# Scaffold Bare Metal Feature Defaults
This skill is Labor as Code™ for one chapter of *Bare Metal Software*:
"The Features Every App Needs, and One Choice for Each." Read that
chapter for the reasoning behind each default — this skill only
executes the method (fill in the sheet, commit it to the spec) and
does not carry the argument for why any one default is right. It also
does not decide anything the book leaves to the reader: which features
actually apply to this project, whether the project is enterprise or
prosumer, whether Rust is acceptable, and whether any "change it only
when" condition has actually been met are always the user's calls.

The book's own fieldwork prompt for this chapter is "Fill In the
Feature Sheet" — this skill is that prompt turned into a repeatable
procedure, with the book's own default table as the ground truth
instead of something reconstructed from memory each time.

## Before running

Confirm these with the user before producing anything, in plain
conversation. Do not guess any of them:

1. **Enterprise or prosumer.** An enterprise app is one hosted system
   many organizations use (tenancy, per-customer SQLite files, Stripe
   subscriptions, single sign-on eventually). A prosumer app is one a
   single serious user installs and runs on their own machine (one
   data folder, a one-time purchase, self-updating signed binary). Get
   this right first — a dozen of the defaults below split on it.
2. **What this application actually is** — the real product, not a
   generic CRUD app. From that, and only from that, decide with the
   user which features in the catalog below are actually in scope.
   Do not run every row against every project: an internal tool with
   no payment, no mobile app, and no field devices has no business
   filling in Billing, Mobile release pipelines, or Edge device rows.
   Draft a candidate in-scope list and have the user confirm or edit
   it before step 1.
3. **Is Rust acceptable?** The book's default stack is one Rust binary
   for the reasons its preface gives (single-file program, compiler
   safety, no runtime to install, a small container image). If the user's organization has
   ruled Rust out, the fallback is a JavaScript platform that compiles
   to a single binary (Deno or Bun) — note this once, up front, and
   do not re-litigate it feature by feature.
4. **Does this project handle regulated or sensitive data** (health
   information, payment data, other regulated PII)? Several defaults
   below (virus scanning, business associate agreements, the runtime
   model's data-handling default) change meaningfully if so, and the
   answer has to come from the user, not be inferred from the product
   description.

## Step 1: Confirm the in-scope feature list

Using the user's answers above, propose which rows from the table
below actually apply to this project. Typical exclusions: Billing (no
paid product yet), Offline/sync (no mobile or edge component), the
mobile and edge device rows (web-only product). Get explicit
confirmation before moving on — an unconfirmed scope list produces a
spec full of defaults for features the project doesn't have.

## Step 2: Walk the feature table

This is the book's own table, one row per in-scope feature. For each
row, state the default and its reversal condition exactly as written
below — do not paraphrase them into something vaguer, and do not
substitute a different default because it "feels more modern." The
whole point of the chapter is that these are settled choices, not a
menu.

| Feature | Default | Change it only when |
| --- | --- | --- |
| Sign-in | Passkeys + email link, mature auth library, session rows in SQLite | An enterprise customer requires single sign-on; add OpenID Connect only |
| Roles | Four roles (owner, admin, member, viewer) in one table; one permission function | A paying customer needs a rule the four roles cannot express |
| State | The lowest level of the State Complexity Ladder that fits each kind of state; files first | Queries, concurrency, or operations need the next level, measured |
| Tenants | One SQLite file per customer | Thousands of customers or cross-customer queries, measured |
| Audit | Append-only table written in the same transaction as every change | A regulator requires storage your own admins cannot touch |
| Files | On disk by content hash; row in SQLite; object store for backup only | More than one server must serve the same files |
| Search | SQLite FTS5 | Millions of documents and a relevance team |
| Reports | Nightly Parquet export + DuckDB; CSV/Excel download | Numbers must be minutes old, not hours |
| PDFs | Print-styled HTML rendered by a headless browser | A fixed official form is required |
| Imports | Staging table, validate, error workbook back | Source is a live system, not a file |
| Jobs | Jobs table + worker threads in the same program | More than one server must share the queue |
| Schedules | Schedules table read by the program’s worker threads | A job must run while the program is stopped; the host scheduler starts a one-off container |
| Live updates | Server-sent events | Browser must send many messages per second |
| Cache | None | A measured slow query; in-memory map only |
| Email | Outbox table + provider over SMTP/HTTP; inbound via provider webhook | Provider pricing changes the business |
| Notifications | Table + badge + daily digest; urgent kinds immediate | Users ask for different timing |
| API | JSON over HTTPS at /api/v1; hashed API keys; OpenAPI generated from the spec | A partner requires OAuth |
| Webhooks | Subscriptions table, HMAC-signed, six retries over a day | Never |
| Billing | Stripe Checkout + portal; entitlements table; signed license file (prosumer) | Selling where Stripe does not serve |
| Settings/flags | One settings table with scopes | Never |
| Backups | Litestream + nightly copies + monthly automatic restore drill | Never |
| Logs/health | JSON lines to standard output, kept by the container runtime; /health; /status page | Customer ops team requires OpenTelemetry |
| Front door | Inside the program: rustls TLS, ACME certificates, rate and size limits, timeouts | A second host arrives; a load balancer takes over TLS and limits |
| Updates | New image replaces the container + forward-only migrations; self-update (prosumer) | Never |
| Offline/sync | Device SQLite + change log + one sync endpoint; conflicts kept | Never |
| Languages | English only; strings table when a customer pays for a second | A paying customer needs another language |
| Admin | /admin pages in the same program | Never |
| Runtime model | Plain HTTPS, schema-checked output, no write access, eval set, audit every call | No vendor will sign the agreement you need; run a model on your own host |
| Identifiers, time, money | UUIDv7; UTC ISO 8601 text; whole cents | Never |
| Uploads | Allow-list by first bytes; size limit at the front door; no virus scan | A customer contract requires scanning |
| Host | Debian stable, container runtime, keys-only SSH, three ports, hardened container | Never |
| Build | Lock file, pinned toolchain, vendored dependencies, static signed binary in a minimal image | Never |
| Deployment | Container-first: one image, one Compose file, one volume; scripts in the repository build and deploy it | More hosts than one Compose file per host can manage, measured |
| Signing (prosumer) | Windows code signing and macOS notarization from release one | Never |
| Third-party scripts | None on any page, ever | Never |

## Step 3: Test every "never" and every condition against today's evidence

For each in-scope row, ask the user one question: **does the "change
it only when" condition already hold, today, with evidence?**

- If no (the common case), the default stands. Move on.
- If yes, do not silently swap in the alternative. Stop and ask the
  user to state the measurement that moved them (a load number, a
  contract clause, a customer count) — this is the book's own rule:
  "write down the measurement that moved you." A default changed
  without a stated measurement is exactly the failure mode this
  chapter exists to prevent, so do not proceed past this point on the
  user's assertion alone; get the actual number or document.
- Every row that escalates gets one short file in the project's
  `decisions/` folder: the feature, the default, the alternative
  chosen, and the measurement. Draft this file's contents but do not
  invent a measurement that wasn't given to you.

## Step 4: Write the spec section

Turn the confirmed table (defaults plus any escalated rows) into the
project's own specification document, one sentence per feature, in
the plain-language style the book itself uses for the table — this
is meant to be read by both a human and a harness, so keep each line
a single settled statement of the default:

```
Sign-in: passkeys, plus a sign-in link by email for devices without
passkeys. Session is a random token in a cookie with a matching row
in SQLite; an admin can revoke by deleting the row.

Roles: four roles (owner, admin, member, viewer) in one table. All
permission checks go through one function.

[... one line per confirmed feature ...]
```

## Step 5: Scaffold the repository shape, if asked

Only if the user wants the actual folder structure created (not every
user does — some just want the spec written), lay out the shape the
book describes as "the repository the harness works in":

```
mkdir -p spec constitutional-tests ops decisions
```

- `spec/` — the feature-defaults document from Step 4, plus one file
  per boundary as the project grows.
- `constitutional-tests/` — the tests, models, and proofs the harness
  may never weaken to make its own change pass.
- `ops/` — the Dockerfile, the Compose file, and the deploy, backup, restore, and check scripts,
  once they exist.
- `decisions/` — one short file per default the project changed from
  the book's own default, and the measurement that moved it (Step 3).

Do not scaffold application code from this skill. This skill's job
ends at a written, confirmed spec and (optionally) the empty folder
shape a harness will fill in from that spec.

## The check that catches this chapter's own failure mode

Before calling the sheet done, reread every row that is NOT the book's
default. For each one, confirm there is a real, stated, measured
condition attached to it — not "it seemed safer," not "we might need
it later," not "that's how we did it at my last company." The chapter
opens with the warning this check exists to catch: "Add one [vendor or
service] per feature and a small app is carrying twenty dependencies
before it has served its first customer." A feature sheet with several
unjustified deviations from the defaults is that failure happening in
real time. Flag every such row back to the user before treating the
sheet as finished.
