Project Structure
AI Scaffolding is organized into several key components that work together to create customized project files and folders.
Understanding this structure is essential for extending the tool with new packages and features.
Directory Structure
The codebase follows a modular organization that separates concerns and promotes extensibility:
src/
├── packages/ # Package templates and configuration
│ ├── root/ # Files copied to project root
│ ├── hardhat/ # Hardhat package files
│ ├── vite/ # Vite package files
│ ├── nextjs/ # Next.js package files
│ ├── nestjs/ # NestJS package files
│ └── index.ts # Package exports and prompt configuration
├── builders/ # Code generation logic
│ ├── MainBuilder.ts # Orchestrates the entire build process
│ └── PackageBuilder.ts # Base class for package builders
├── main.ts # Main application logic
├── run.ts # CLI entry point
├── types.ts # Type definitions
├── prompts.ts # Main project prompts
└── handlebars.ts # Handlebars template engine setupCore Components
Entry Point
The CLI tool's entry point is run.ts, which sets up the command-line interface using Commander.js. This file defines the available commands and routes them to the appropriate handlers:
// Main command to scaffold a new project
program
.name('ai-scaffolding-v2')
.description('Scaffold a new Web(3) (d)App project')
.version(packageJson.version)
.argument('[path]', 'Path for the project (e.g., my-app or ../my-app)')
.option('--skipInstall', 'Skip the installation of dependencies', false)
.action(main);
// Additional commands
program.command('cursor')
.description('Update Cursor rules')
// ...options
program.command('config')
.description('Show the current configuration')
// ...subcommandsWorkflow Phases
The tool operates in two distinct phases:
- Prompt Phase:
Collects user input through interactive prompts to configure the project.
The prompts are organized by:
- Main project configuration (project name, location, package manager)
- Package selection (which packages to include)
- Package-specific configuration (options for each selected package)
- Execution Phase:
Generates the project based on the collected configuration:
- Creates the directory structure
- Applies templates using Handlebars
- Copies static files
- Sets up git repository
- Installs dependencies
Type System
The type system in types.ts defines the structure of configuration objects and ensures type safety throughout the application:
// Main configuration interfaces
export interface ProjectConfigV2 {
projectName: string;
packageManager: PackageManager;
projectPath: string;
targetDir: string;
packages: Record<'hardhat', PackageConfig<HardhatConfig>>
& Record<'vite', PackageConfig<ViteConfig>>
& Record<'nextjs', PackageConfig<NextjsConfig>>
& Record<'nestjs', PackageConfig<NestJsConfig>>;
global: GlobalConfig;
skipInstall: boolean;
}
// Context passed to prompt functions
export interface PromptContext {
projectName: string
projectPath: string
targetDir: string
packageManager: PackageManager
shouldAddHardhat: boolean
shouldAddVite: boolean
shouldAddNextjs: boolean
skipInstall: boolean
}
// Package prompt function type
export type PackagePrompt<T extends Record<string, unknown>> =
(ctx: PromptContext) => Promise<PackageConfig<T>>Configuration Object
The central piece connecting the prompt and execution phases is the ProjectConfig object defined in main.ts. This object stores all user selections and is passed to the builders for project generation:
const config: ProjectConfig = {
projectName,
packageManager,
packages,
projectPath,
targetDir,
skipInstall,
global: {
useSilentData,
shouldAddHardhat,
shouldAddVite,
shouldAddNextjs,
shouldAddNestjs,
networks,
isPnpm: packageManager === PackageManager.PNPM,
isYarn: packageManager === PackageManager.YARN,
isNpm: packageManager === PackageManager.NPM,
defaultNetwork
}
};This configuration becomes available as variables in Handlebars templates, allowing conditional file generation.
Template System
AI Scaffolding uses Handlebars as its templating engine. The engine is configured in handlebars.ts with custom helpers:
// Custom Handlebars helpers
Handlebars.registerHelper('uppercase', (str) => str.toUpperCase());
Handlebars.registerHelper('lowercase', (str) => str.toLowerCase());
Handlebars.registerHelper('ifeq', (val1, val2, options) => val1 === val2 ? options.fn(val1) : undefined);
Handlebars.registerHelper('ifneq', (val1, val2, options) => val1 !== val2 ? options.fn(val1) : undefined);Package files can include Handlebars directives for dynamic content generation:
// Example from hardhat.config.ts
/*#{{#if packages.hardhat.useIgnition}}*/
import '@nomicfoundation/hardhat-ignition'
/*#{{/if}}*/
// Network configuration with dynamic values
const networks = {
/*#{{#each packages.hardhat.networks}}*/
/*#{{#ifneq this 'hardhat'}}*/
['{{this}}']: {
url: process.env.{{uppercase this}}_RPC_URL || '',
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
/*#{{/ifneq}}*/
/*#{{/each}}*/
}Package System
AI Scaffolding is built around a modular package system that allows for easy extension with new features and frameworks. Each package is a self-contained module that can be selected during project creation.
For detailed information on how packages work and how to create new ones, see the Development Guide.
Build Process
The MainBuilder class orchestrates the entire build process through a series of well-defined tasks:
public async build() {
// Orchestrate tasks
this._createProjectStructure();
this._buildPackages();
this._createCursorrules();
this._installDependencies();
this._formatAll();
this._initGitRepository();
// Run tasks
await this.tasks.run();
}Each task is implemented as a private method that adds one or more tasks to the task list:
- _createProjectStructure(): Sets up the basic project structure
- _buildPackages(): Builds each selected package using its builder
- _createCursorrules(): Adds Cursor AI assistant rules to the project
- _installDependencies(): Installs all dependencies
- _formatAll(): Formats all generated code
- _initGitRepository(): Initializes a Git repository
Each package builder extends the PackageBuilder base class and implements its own build logic.
Next Steps
Now that you understand the structure, proceed to the Development Guide to learn how to extend AI Scaffolding with new packages and features.