guild-scaffold

module
v0.0.0-...-92f4536 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 27, 2026 License: MIT

README

Guild Scaffold Banner

Guild Scaffold

A template-agnostic project scaffolding tool. Create and manage reusable project templates with variable substitution and directory structure generation.

Features

  • Template-based scaffolding - Define project structures with Go templates
  • Variable substitution - Customizable variables with types, defaults, and validation
  • Registry system - Discover scaffolds from multiple sources with precedence rules
  • Dry-run mode - Preview what will be created before executing
  • Empty directory tracking - Automatic .gitkeep generation for empty directories
  • Configurable paths - Override default directories via environment variables

Installation

# From source
just install

# Or manually
go build -o bin/scaffold ./cmd/scaffold
cp bin/scaffold ~/go/bin/

Quick Start

# List available scaffolds
scaffold list

# Initialize a new project from a scaffold
scaffold init my-project --template minimal

# Validate a scaffold definition
scaffold validate --template my-scaffold

# Preview without creating files
scaffold init my-project --template my-scaffold --dry-run

Configuration

Environment Variables

Guild Scaffold supports environment variable overrides for customizing paths:

Variable Default Description
GUILD_SCAFFOLD_GLOBAL_DIR ~/.config/guild/ Global configuration and templates directory
GUILD_SCAFFOLD_WORKSPACE_DIR .campaign Workspace directory name (relative to project root)
XDG_CONFIG_HOME ~/.config Standard XDG base directory for config

Example:

# Use a custom global templates directory
export GUILD_SCAFFOLD_GLOBAL_DIR=~/.my-scaffolds/

# Use a custom workspace directory
export GUILD_SCAFFOLD_WORKSPACE_DIR=.scaffold

Registry System

Guild-scaffold uses a registry system to discover scaffolds from multiple sources:

Source Priority (highest to lowest)
  1. Workspace Templates (.campaign/templates/) - Project-specific scaffolds
  2. Global Templates (~/.config/guild/templates/) - User-installed scaffolds
  3. Legacy Registries - For backward compatibility with older configurations

When the same scaffold name exists in multiple sources, the higher-priority source wins.

Installing Templates

To install a scaffold from the examples directory:

# Copy an example scaffold to your global templates directory
cp -r examples/go-cli ~/.config/guild/templates/

# Or create a new scaffold
mkdir -p ~/.config/guild/templates/my-scaffold
# Then create scaffold.yaml and templates/ in that directory
Legacy Registry Configuration

For backward compatibility, registry YAML files are also supported:

# ~/.guild/scaffold.yaml or .campaign/scaffold.yaml
scaffolds:
  - name: my-scaffold
    path: ~/scaffolds/my-scaffold/
    description: "My custom project scaffold"

  - name: go-cli
    path: /path/to/scaffolds/go-cli/
    description: "Go CLI application template"

Creating Custom Scaffolds

Each scaffold is a directory containing:

my-scaffold/
├── scaffold.yaml      # Scaffold definition
└── templates/         # Template files (mirrors output structure)
    ├── README.md.tmpl
    ├── go.mod.tmpl
    └── cmd/
        └── app/
            └── main.go.tmpl

The simplest approach - templates mirror your desired output structure:

# scaffold.yaml
scaffold_version: "1.0.0"
templates_dir: templates
mirror_structure: true
scan_templates: true

vars:
  project_name: ""
  module_path: ""
  description: "A project"

With scan_templates: true, the directory structure under templates/ becomes your output. Just create your templates where you want them to appear.

Explicit Tree Scaffolds

For more control, define the structure explicitly:

name: my-scaffold
version: "1.0"
description: "Description of this scaffold"

variables:
  project_name:
    type: string
    required: true

tree:
  README.md: README.md.tmpl
  config/:
    app.yaml: config.yaml.tmpl
  src/:
    _empty: true  # Creates .gitkeep
Variable Types
Type Description Constraints
string Text value pattern, enum
int/integer Whole number min, max
bool Boolean -
array List of values -
object Key-value map -
Empty Directories

Git doesn't track empty directories. Use _empty: true to create directories with .gitkeep:

tree:
  logs/:
    _empty: true
  data/:
    cache/:
      _empty: true

Template Syntax

Templates use Go's text/template syntax with additional functions:

# {{ .vars.project_name }}

Port: {{ .vars.port | default 8080 }}
Name: {{ .vars.project_name | lower }}
Hash: {{ hash .vars.project_name }}
Available Template Functions

String manipulation:

  • lower, upper, title - Case conversion
  • trimSpace - Remove leading/trailing whitespace
  • replace old new - String replacement
  • split delimiter - Split into array
  • join delimiter array - Join array into string
  • contains, hasPrefix, hasSuffix - String checks

Formatting:

  • quote - Wrap in double quotes
  • indent n text - Indent text by n spaces
  • toYAML, toJSON - Format as YAML/JSON

Path operations:

  • pathBase, pathDir, pathExt - Path components
  • pathJoin, pathClean - Path manipulation

Utilities:

  • default value fallback - Provide default if empty
  • empty value - Check if value is empty
  • not bool - Negate boolean
  • hash input - Generate short SHA256 hash (8 chars)

Date/Time:

  • now - Current time
  • date format - Format current date
  • dateISO - ISO 8601 formatted date

Type checking:

  • isString, isMap, isList - Type assertions

Commands

scaffold list

List all available scaffolds from the merged registry.

scaffold list           # Brief list
scaffold list -v        # Verbose with variables
scaffold init

Initialize a new project from a scaffold.

scaffold init my-project --template go-cli
scaffold init my-project --template go-cli --dry-run  # Preview only
scaffold init my-project --template go-cli --force    # Overwrite existing
scaffold validate

Validate a scaffold definition and templates.

scaffold validate --template my-scaffold
scaffold sync

Sync scaffolds from a source to your global templates directory.

scaffold sync --from /path/to/scaffolds

Examples

The examples/ directory contains sample scaffolds:

  • go-project/ - Recommended - Uses scan-based approach with mirrored structure
  • minimal/ - Bare-bones scaffold with explicit tree
  • go-cli/ - Go CLI with explicit tree and justfile
  • Additional YAML examples for reference

To use an example:

# Copy to global templates
cp -r examples/go-project ~/.config/guild/templates/

# Then use it
scaffold init my-app --template go-project \
  --var project_name=my-app \
  --var module_path=github.com/user/my-app

Development

# Run tests
just test unit          # Unit tests
just test integration   # Container-based integration tests

# Build
just build              # Build binary
just check              # Vet + build

# Lint
just lint               # Run linter

# Development
just dev watch          # Watch mode
just dev pre-commit     # Pre-commit checks

Project Structure

guild-scaffold/
├── cmd/scaffold/           # CLI entry point
├── pkg/scaffold/           # Core library
│   ├── config/             # Path configuration
│   ├── cli/                # CLI command implementations
│   ├── registry.go         # Registry types and operations
│   ├── loader.go           # Registry loading from sources
│   ├── parser.go           # YAML parsing
│   ├── renderer.go         # Template rendering
│   ├── validator.go        # Scaffold validation
│   └── filesystem.go       # Safe file operations
├── examples/               # Example scaffolds
├── tests/integration/      # Container-based tests
└── .justfiles/             # Modular just recipes

Library Usage

Guild Scaffold can be used as a Go library:

import "github.com/lancekrogers/guild-scaffold/pkg/scaffold"

// Create a registry loader
loader, err := scaffold.NewRegistryLoader()
if err != nil {
    log.Fatal(err)
}

// Load all registries
registry, err := loader.Load(ctx)
if err != nil {
    log.Fatal(err)
}

// Find and resolve a scaffold
entry, err := loader.FindScaffold(ctx, "my-scaffold")
if err != nil {
    log.Fatal(err)
}

def, fsys, err := scaffold.ResolveScaffold(ctx, entry)
if err != nil {
    log.Fatal(err)
}

Contributing

See CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Directories

Path Synopsis
cmd
scaffold command
internal
buildutil command
internal/buildutil/main.go
internal/buildutil/main.go
buildutil/tasks
internal/buildutil/tasks/build.go
internal/buildutil/tasks/build.go
buildutil/ui
internal/buildutil/ui/ansi.go
internal/buildutil/ui/ansi.go
pkg
scaffold/config
Package config provides configuration directory management for guild-scaffold.
Package config provides configuration directory management for guild-scaffold.
tests

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL