# Scaffold — v1.16.0

Scaffolding lets you spin up a new SaaS project from a curated template
in one command. Templates ship with manifest-driven post-install steps
and `{{token}}` substitution so the output is ready to run.

## Commands

```bash
openlife scaffold list                                          # all available
openlife scaffold info <id>                                     # manifest detail
openlife scaffold <name> --template=<id> [--description=...]    # apply
openlife scaffold custom <name> --from=<local-path>             # one-off template
```

## Built-in templates

| id | Stack |
|---|---|
| `nextjs-supabase-clerk-stripe` | Next.js 16 + Supabase + Clerk + Stripe + Tailwind, Vercel-ready |

v1.16.1 will add `sveltekit-postgres-lucia` (Railway-ready). Community
templates are loaded automatically from `~/.openlife/templates/<id>/`.

## Anatomy of a template

```
templates/<id>/
├── manifest.yaml               # required — see schema below
├── package.json
├── README.md
├── (any other files)
└── (nested dirs preserved as-is)
```

### manifest.yaml schema

```yaml
id: my-template
name: Human-readable Name
description: One-sentence summary that shows up in `scaffold list`.

stack:
  framework: nextjs@16
  database: supabase
  auth: clerk
  billing: stripe
  styling: tailwind
  deploy_target: vercel

# Surfaced by `scaffold info`. Optional but recommended.
required_env:
  - DATABASE_URL
  - API_KEY

# Printed after a successful apply. Tokens get substituted here too.
post_install_steps:
  - "cd {{project_name}}"
  - "Run `supabase db push` to apply migrations"
  - "Add API_KEY to .env.local"

# Optional minimum Node. Warning only — does not block apply.
required_node_version: ">=20.0.0"

# Files/dirs NOT copied. Supports:
#   - exact paths: `secret.env`
#   - directories: `private/`
#   - extension globs: `*.log`
exclude:
  - node_modules/
  - .next/
  - .vercel/
```

## Token substitution

The engine substitutes `{{var}}` patterns in:

- All text file content
- File basenames using the `__var__` pattern (e.g.
  `__project_name__.config.ts` → `my-app.config.ts`)
- Strings in `post_install_steps`

Built-in vars (always available):

- `{{project_name}}` — the `<name>` arg to `scaffold`
- `{{description}}` — `--description` flag, or auto-generated
- `{{node_version}}` — current Node version

User-defined vars via `--var key=value` (repeatable).

Binary files are copied verbatim (no substitution). The engine
recognizes: `.png .jpg .jpeg .gif .webp .ico .icns .woff .woff2 .ttf .otf
.eot .mp4 .webm .mp3 .wav .ogg .zip .tar .gz .pdf .psd .sketch .fig .bin
.exe .dll .so .dylib`.

After apply, any surviving `{{token}}` patterns are reported as
warnings (top 5 + count).

## Authoring a custom template

1. Pick an existing project that's the shape you want.
2. Copy its files into `~/.openlife/templates/<your-id>/`.
3. Create `manifest.yaml` at the root.
4. Replace concrete values with `{{var}}` tokens (e.g.
   `"name": "{{project_name}}"`).
5. Test with `openlife scaffold list` (your template should appear)
   then `openlife scaffold test-app --template=<your-id>`.

For one-off / not-installed templates: `openlife scaffold <name>
--from=<local-path>`. The engine copies the template into
`~/.openlife/templates/` first then applies normally.

## Force overwrite

```bash
openlife scaffold my-app --template=nextjs-supabase-clerk-stripe --force
```

By default `apply` refuses to write into a non-empty target.

## Dry run

```bash
openlife scaffold my-app --template=nextjs-supabase-clerk-stripe --dry-run --json
```

Reports what would be copied without touching disk.

## Composing with the rest of OpenLife

```bash
# Pull a brand's design tokens (v1.15)
openlife design pull core

# Scaffold using a brand's design
openlife scaffold my-saas --template=nextjs-supabase-clerk-stripe \
  --var design_profile=stripe

# Story-driven feature work (v1.12+)
openlife story list
openlife story execute 1.1   # v1.17 autonomous loop

# Ship (v1.18)
openlife ship
openlife deploy --provider=vercel
```

## Security

- `--from=<git-url>` deferred to v1.16.1 (requires
  `SecurityDownloadGuard.downloadAndScan` integration).
- Bundled templates ship no real secrets — `.env.example` documents
  what you need.
- No code execution at scaffold time. Pure file copy + string
  substitution.
- Templates run code only after `npm install && npm run dev` —
  same trust model as `create-next-app`.

## Troubleshooting

| Symptom | Likely cause |
|---|---|
| `template_not_found: <id>` | Run `scaffold list` to confirm spelling. User templates live in `~/.openlife/templates/`. |
| `target_not_empty: <dir>` | Pass `--force` or scaffold into an empty/non-existent dir. |
| `unresolved_token: <file>:{{var}}` warnings | The template references a var you didn't provide. Pass `--var var=value`. |
| Build fails after scaffold | Check `.env.example` — most templates need API keys before `npm run dev` works. |

## See also

- `docs/v1.16-changelog.md` — release notes
- `docs/design-hub.md` — design.md catalog (v1.15) for token-driven scaffolds
- `MANIFESTO.md` — broader OpenLife vision
