Back to skills
extension
Category: AI Agent CapabilitiesNo API key required

constructive-boilerplate-authoring

Create and customize boilerplate templates for pgpm init. Use when authoring custom boilerplate templates, configuring .boilerplate.json, defining placeholder questions, or setting up a custom template repository.

personAuthor: jakexiaohubgithub

Create and customize boilerplate templates for pgpm init.

Overview

PGPM uses the genomic library to scaffold projects from templates. Templates are stored in a boilerplate repository (default: constructive-io/pgpm-boilerplates) and use placeholder substitution for customization.

Template Repository Structure

my-boilerplates/
  .boilerplates.json       # Root config (points to default directory)
  pgpm/                    # Default template variant (PGPM)
    module/
      .boilerplate.json    # Module template config
      package.json         # Template files with placeholders
      pgpm.plan
      ...
    workspace/
      .boilerplate.json    # Workspace template config
      package.json
      pgpm.json
      ...
  pnpm/                    # Alternative variant (pure PNPM, no pgpm files)
    module/
      .boilerplate.json
      ...
    workspace/
      .boilerplate.json
      ...

Root Configuration

The .boilerplates.json file at the repository root specifies the default template directory:

{
  "dir": "pgpm"
}

Template Configuration

Each template has a .boilerplate.json file defining its type, workspace requirements, and questions.

Basic Structure

{
  "type": "workspace",
  "questions": [
    {
      "name": "____repoName____",
      "message": "Enter the repository name",
      "required": true
    }
  ]
}

Template Types

| Type | Description | |------|-------------| | workspace | Creates a new monorepo workspace | | module | Creates a package within a workspace | | generic | Standalone template (no workspace context) |

Workspace Requirements

The requiresWorkspace field controls what type of workspace the template needs:

{
  "type": "module",
  "requiresWorkspace": "pgpm"
}

| Value | Description | |-------|-------------| | "pgpm" | Requires PGPM workspace (pgpm.json), creates pgpm.plan/.control files | | "pnpm" | Requires PNPM workspace (pnpm-workspace.yaml) | | "lerna" | Requires Lerna workspace (lerna.json) | | "npm" | Requires npm workspace (package.json with workspaces) | | false | No workspace required |

Placeholder System

Templates use the ____placeholder____ pattern (4 underscores on each side) for variable substitution:

{
  "name": "@____username____/____moduleName____",
  "version": "0.0.1",
  "description": "____moduleDesc____",
  "author": "____fullName____ <____email____>"
}

Question Configuration

Question Fields

| Field | Type | Description | |-------|------|-------------| | name | string | Placeholder name (e.g., ____fullName____) | | message | string | Prompt shown to user | | required | boolean | Whether the field is required | | type | string | Input type: text, list, checkbox | | options | string[] | Static options for list/checkbox | | default | any | Static default value | | defaultFrom | string | Resolver for dynamic default | | setFrom | string | Auto-set value (skips prompt) | | optionsFrom | string | Resolver for dynamic options |

Question Types

Text Input (default):

{
  "name": "____moduleName____",
  "message": "Enter the module name",
  "required": true
}

List Selection:

{
  "name": "____access____",
  "message": "Module access?",
  "type": "list",
  "options": ["public", "restricted"],
  "default": "public"
}

Checkbox (multi-select):

{
  "name": "____extensions____",
  "message": "Select PostgreSQL extensions",
  "type": "checkbox",
  "options": ["plpgsql", "uuid-ossp", "citext", "pgcrypto"]
}

Resolvers

Resolvers dynamically populate values from the environment or workspace context.

defaultFrom Resolvers: | Resolver | Description | |----------|-------------| | git.user.name | Git config user.name | | git.user.email | Git config user.email | | npm.whoami | npm whoami result | | workspace.dirname | Current directory name |

setFrom Resolvers (auto-set, skips prompt): | Resolver | Description | |----------|-------------| | workspace.name | Workspace name from pgpm.json/package.json | | workspace.author.name | Workspace author name | | workspace.author.email | Workspace author email | | workspace.license | Workspace license | | workspace.organization.name | Workspace organization |

optionsFrom Resolvers: | Resolver | Description | |----------|-------------| | licenses | List of SPDX license identifiers |

Example: Complete Module Template

{
  "type": "module",
  "requiresWorkspace": "pgpm",
  "questions": [
    {
      "name": "____fullName____",
      "message": "Enter author full name",
      "setFrom": "workspace.author.name",
      "defaultFrom": "git.user.name",
      "required": true
    },
    {
      "name": "____email____",
      "message": "Enter author email",
      "setFrom": "workspace.author.email",
      "defaultFrom": "git.user.email",
      "required": true
    },
    {
      "name": "____moduleName____",
      "message": "Enter the module name",
      "required": true
    },
    {
      "name": "____moduleDesc____",
      "message": "Enter the module description",
      "required": true
    },
    {
      "name": "____repoName____",
      "message": "Enter the repository name",
      "setFrom": "workspace.name",
      "required": true
    },
    {
      "name": "____username____",
      "message": "Enter your github username",
      "setFrom": "workspace.organization.name",
      "defaultFrom": "npm.whoami",
      "required": true
    },
    {
      "name": "____access____",
      "message": "Module access?",
      "type": "list",
      "options": ["public", "restricted"],
      "default": "public",
      "required": true
    },
    {
      "name": "____license____",
      "message": "Choose a license",
      "type": "list",
      "optionsFrom": "licenses",
      "setFrom": "workspace.license",
      "required": true
    }
  ]
}

Creating a Custom Boilerplate Repository

  1. Create a new repository with the structure above
  2. Add .boilerplates.json pointing to your default directory
  3. Create template directories with .boilerplate.json configs
  4. Add template files with ____placeholder____ patterns
  5. Use with pgpm init --repo owner/your-boilerplates

Using Custom Templates

# Use your own boilerplate repository
pgpm init workspace --repo myorg/my-boilerplates

# Use a specific branch
pgpm init workspace --repo myorg/my-boilerplates --from-branch develop

# Use a variant directory
pgpm init workspace --repo myorg/my-boilerplates --dir custom-variant

# Use the --template flag (recommended)
pgpm init --template pnpm/module --repo myorg/my-boilerplates
pgpm init -t custom-variant/module --repo myorg/my-boilerplates

# Create workspace + module in one command
pgpm init -t pnpm/module -w --repo myorg/my-boilerplates

Best Practices

  1. Use setFrom for values that should inherit from workspace context
  2. Use defaultFrom for sensible defaults that users can override
  3. Keep placeholder names descriptive and consistent
  4. Document custom templates in your repository README
  5. Test templates with --no-tty to ensure all required fields are defined