Skip to content

feat(cli): template system, starter integrations, and config-aware init interview for frigg init #595

Description

@seanspeaks

Background

While building an agent-driven integration scaffolding skill for Lefthook's Frigg projects, I compared what frigg init produces against Lefthook's production Frigg templates (e.g. aes--frigg, quo--frigg, clyde--frigg). The gap is large and consistent across templates — frigg init produces a minimal stub, while every production project independently reinvents the same production posture on top.

Concretely, the Lefthook templates layer the following on top of what frigg init gives you:

  • App definition with production posturevpcIsolation: 'isolated' + enableVPCEndpoints: true + selfHeal: true; encryption.fieldLevelEncryptionMethod: 'kms'; Aurora Postgres (publiclyAccessible: false, capacity 0.5–1); multi-mode auth (friggToken, sharedSecret, password) pre-wired; ~50 lines of env var mapping.
  • Full dev/test harness — ~39 prod + 25 dev deps (@friggframework/serverless-plugin, @friggframework/test, @friggframework/devtools, jest + chai + nock + faker, serverless-esbuild + serverless-kms-grants + serverless-offline).
  • CI/CD + Changesets — 5 GitHub Actions workflows (ci, deploy-dev, deploy-prod, release, rollback), .changeset/ with @changesets/cli configured for GitHub changelog automation, AWS credential rotation, 30-minute job timeouts.
  • Reference structure + local dev — working reference integration under src/integrations/, jest setup with integration test examples, ESLint + Prettier + knip configs, Docker Compose for local Postgres + auth-server, ~8 npm test scripts.

This means every new production Frigg project today is a copy-paste-from-another-project exercise. There's no first-class path from frigg init to a production-shaped scaffold, and the current --template flag is vestigial — see "Current state" below.

Proposal

Replace the hardcoded BackendFirstHandler with a proper template system + an interactive init interview that scaffolds production-grade defaults and common starter integrations.

1. Template system (function, not hardcode)

  • Define a Template interface: name, description, files (with token substitution), post-install steps, prompts.
  • Ship a small set of first-party templates: minimal (today's BackendFirstHandler), production (Lefthook-equivalent posture), oauth-starter (production + reference OAuth integration), api-key-starter (production + reference API-key integration).
  • Allow community/external templates via frigg init --template <name> or frigg init --template github:<owner>/<repo> so org-specific scaffolds (like Lefthook's) can be selected directly rather than copy-pasted.

2. Common starter integrations

Bundle 2–3 reference integrations under src/integrations/ in the production templates:

  • One OAuth2 integration (e.g. HubSpot-style, full event lifecycle wired up).
  • One API-key integration (e.g. with getAuthorizationRequirements rendering an interactive form).
  • One webhook-driven integration (signature validation, queue fan-out, Process Model usage).

These serve as both copy-paste starting points and as living documentation of integration patterns (createFriggCommands, QueueManager, SyncOrchestrator, the USER_ACTION / CRON / QUEUE / WEBHOOK event types).

3. Default config presets

Expose the production posture as named presets the template can select:

  • posture: 'production'vpcIsolation: 'isolated', enableVPCEndpoints: true, selfHeal: true, KMS field-level encryption, Aurora Postgres non-public.
  • posture: 'development' → public Postgres, AES encryption, no VPC isolation.
  • posture: 'experimental' → today's minimal stub.

Templates declare their preset; the interview can override it.

4. Init interview that scaffolds overrides

After template selection, prompt for the choices that diverge per-project:

  • Database (Mongo vs Postgres-Aurora, capacity range)
  • Encryption method (KMS vs AES)
  • Auth modes to enable (friggToken / sharedSecret / password / SSO)
  • VPC configuration (isolated / shared / off)
  • Initial API modules to pre-install (multi-select from a curated list)
  • CI provider (GitHub Actions / none) and deploy targets (dev / staging / prod stages)
  • Changesets on/off

Write the answers into the generated backend/index.js appDefinition and the relevant CI workflows, so the project starts with overrides reflecting real choices rather than commented placeholders. Re-running frigg init in an existing project (or a frigg init --reconfigure mode) could update overrides without overwriting integration code.

Current state — --template flag is vestigial

packages/devtools/frigg-cli/index.js:93-98 declares:

.command('init [templateName]')
.option('-t, --template <template>', 'template to use', 'backend-only')

But init-command/index.js:65-90 then has:

if (!options.template && !options.legacyFrontend) {
    // ...BackendFirstHandler...
}
// otherwise:
console.log(chalk.red('Legacy template system is no longer supported.'));
process.exit(1);

Because the --template flag has a default of 'backend-only', options.template is always truthy, so the condition !options.template is always false. By the literal reading, every frigg init should hit the "Legacy template system is no longer supported" error path. Either commander's default semantics here behave differently than I expect, or this command is broken in HEAD. Either way, the template flag is half-removed and the templates directory (templates/backend/) referenced by the legacy TemplateHandler is orphaned. This proposal is also the cleanup path for that ambiguity.

Related

Why now

Agent-driven scaffolding (Claude Code skills, internal automations) needs a deterministic, parameterized way to spin up production-shaped Frigg projects. Without a template system, every agent has to either (a) copy a known-good external repo and template-substitute, or (b) re-implement the production posture procedurally. Both options exist today in Lefthook's tooling; neither scales as more orgs adopt Frigg. A first-class template system would also let the Frigg docs / starter examples stay in sync with the framework itself rather than drifting in downstream repos.

Happy to scope down (e.g. ship posture presets + the interactive interview first, leave external-template loading for a follow-up) — flagging the whole picture here so the team can decide where to draw the line.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions