Architecture Overview
Forge follows a configuration-first design where user preferences drive code generation through a modular generator system.
High-Level Flow
flowchart LR
A[forge init] --> B[Configuration Collection]
B --> C[.forge/config.json]
C --> D[Generators Execution]
D --> E[Generated Project]
The generation process follows these steps:
User runs
forge initInteractive prompts collect preferences
Configuration saved to
.forge/config.jsonProjectGeneratorreads configurationStructureGeneratorcreates directoriesGeneratorOrchestratordiscovers and executes generatorsEach generator creates specific files
Core Components
CLI Layer
main.py: Entry point using Typer framework
app = typer.Typer(name="forge")
app.command(name="init")(init_command)
commands/init.py: Interactive configuration collection using questionary
Collects project name
Database and ORM selection
Feature toggles (auth, Redis, Celery, etc.)
Saves configuration to
.forge/config.json
Configuration Layer
ConfigReader (core/config_reader.py): Reads and validates configuration
class ConfigReader:
def __init__(self, project_path: Path):
self.config = self._load_config()
def get_project_name(self) -> str: ...
def get_database_type(self) -> str: ...
def has_auth(self) -> bool: ...
def has_redis(self) -> bool: ...
Provides a clean API for generators to query configuration without parsing JSON directly.
Generation Layer
ProjectGenerator (core/project_generator.py): Coordinates generation
class ProjectGenerator:
def generate(self):
# 1. Create directory structure
self.structure_generator.create_project_structure()
# 2. Execute all generators
self.orchestrator.execute_generators()
StructureGenerator (core/generators/structure.py): Creates directories
Creates
app/,app/core/,app/models/, etc.Creates
__init__.pyfilesInitializes Alembic if migrations enabled
GeneratorOrchestrator (core/generators/orchestrator.py): Manages generators
Discovers all registered generators
Filters based on configuration
Resolves dependencies
Sorts by priority
Executes in order
Generator Layer
@Generator Decorator (core/decorators/generator.py): Registers generators
GENERATOR_REGISTRY = {}
def Generator(category, priority, requires=None, enabled_when=None, description=""):
def decorator(cls):
GENERATOR_REGISTRY[cls.__name__] = {
"class": cls,
"category": category,
"priority": priority,
"requires": requires or [],
"enabled_when": enabled_when,
"description": description,
}
return cls
return decorator
BaseTemplateGenerator (core/generators/templates/base.py): Base class
class BaseTemplateGenerator:
def __init__(self, project_path: Path, config_reader: ConfigReader):
self.project_path = project_path
self.config_reader = config_reader
self.file_ops = FileOperations(base_path=project_path)
def generate(self) -> None:
raise NotImplementedError
Utility Layer
FileOperations (core/utils/file_operations.py): File writing utilities
create_file(): Create any filecreate_python_file(): Create Python file with docstring and importscreate_json_file(): Create JSON filecreate_markdown_file(): Create Markdown file
Generator Categories
Generators are organized by category and priority:
Category |
Priority |
Examples |
|---|---|---|
config |
1-10 |
pyproject.toml, .env, .gitignore |
app_config |
11-20 |
Settings modules |
database |
21-30 |
Database connection |
model |
31-50 |
User model, Token model |
schema |
51-60 |
Pydantic schemas |
crud |
61-70 |
CRUD operations |
service |
71-80 |
Auth service |
router |
81-90 |
API routes |
test |
100-115 |
Test files |
deployment |
100-110 |
Dockerfile, docker-compose |
migration |
120 |
Alembic configuration |
Dependency Resolution
Generators declare dependencies via the requires parameter:
@Generator(
category="router",
priority=80,
requires=["UserModelGenerator", "UserSchemaGenerator", "UserCRUDGenerator"]
)
class UserRouterGenerator(BaseTemplateGenerator):
...
The orchestrator builds a dependency graph and ensures:
All required generators exist
No circular dependencies
Dependencies execute before dependents
Conditional Generation
Generators use enabled_when to conditionally execute:
@Generator(
category="router",
priority=80,
enabled_when=lambda c: c.has_auth()
)
class AuthRouterGenerator(BaseTemplateGenerator):
...
The orchestrator evaluates these conditions against the ConfigReader and skips disabled generators.
Generated Project Architecture
The generated FastAPI project follows a layered architecture:
flowchart TB
subgraph API["API Layer"]
R[Routers<br/>app/routers/v1/*.py]
end
subgraph Business["Business Layer"]
S[Services<br/>app/services/*.py]
end
subgraph Data["Data Access Layer"]
C[CRUD<br/>app/crud/*.py]
end
subgraph Model["Model Layer"]
M[Models<br/>app/models/*.py]
end
subgraph DB["Database Layer"]
D[Database<br/>app/core/database/]
end
R --> S
S --> C
C --> M
M --> D
Routers: Handle HTTP requests, validate input, return responses
Services: Business logic, orchestrate operations
CRUD: Database operations (Create, Read, Update, Delete)
Models: Database table definitions
Database: Connection management, session handling
This separation allows:
Easy testing (mock lower layers)
Clear responsibilities
Reusable components