Capabilities

Extend Forge Kernel with self-contained capability modules. Think of capabilities like modular additions to a house. The kernel gives you the foundation. Capabilities add what you need: database, ORM, authentication, storage, deployment — all optional, all pluggable.

Capability System Overview

Package functionality into reusable capability modules. Capabilities provide services, controllers, views, CLI commands, and more. Need a database? Install a database capability. Need an ORM? Install an ORM capability. Don't need authentication? Don't install it. The kernel stays lean. You stay in control.

Key Features

Auto-discovery and loading
Dependency management
Lifecycle hooks
Service registration
Route registration
View integration

Forge Developer Mode

Developer mode unlocks additional CLI commands for managing module registries, creating versions, and publishing capabilities. These commands replace the old php modules.php tooling.

Enabling Developer Mode

Enable developer mode by setting FORGE_DEVELOPER_MODE=true in your .env file or config/app.php:

# In .env file
                                    FORGE_DEVELOPER_MODE=true

                                    # Or in config/app.php
                                    return [
                                    'developer_mode' => true,
                                    // ... other config
                                    ];

Developer Mode Commands

Once enabled, the following commands become available:

Registry Management

  • dev:registry:init — Initialize a new module or framework registry. Wizard asks for:
    • Registry type (framework or modules)
    • Git repository URL
    • Branch name (default: main)
    • Whether it's a private repository
  • dev:registry:config — Configure registry settings

Module Registry Commands

  • dev:module:listUser-friendly dropdown interface to browse all available modules. Select any module from an interactive menu to view its versions with the last commit message for each version.
  • dev:module:versionCreate version wizard that:
    • Prompts for module name (or use --name=ModuleName)
    • Detects current version or asks for version increment type (patch/minor/major)
    • Automatically updates module version in source files
    • Creates ZIP file of the module
    • Calculates SHA-256 integrity hash
    • Updates modules.json manifest
    • Commits changes to registry (if in git repository)
  • dev:module:publish — Publish module registry changes to remote repository

Framework Registry Commands

  • dev:framework:list — List available framework versions
  • dev:framework:version — Manage framework versions
  • dev:framework:publish — Publish framework version to registry

Note: All dev:* commands are only available when developer mode is enabled. This keeps the CLI clean for regular users while providing powerful tools for developers and maintainers.

Module Lifecycle

Execute code at specific points during application boot.

Available Lifecycle Hooks

After Boot

Executed after the application has booted

After Module Load

Executed after all modules are loaded

After Module Register

Executed after a module is registered

After Config Loaded

Executed after configuration is loaded

App Booted

Executed when the application is fully booted

Before Request

Executed before each HTTP request

After Request

Executed after each HTTP request

After Response

Executed after HTTP response is sent

Using Lifecycle Hooks

use Forge\Core\Module\Attributes\LifecycleHook;
                                    use Forge\Core\Module\LifecycleHookName;

                                    #[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
                                    public function onAfterModuleRegister(): void
                                    {
                                    // Your code here
                                    }

                                    #[LifecycleHook(hook: LifecycleHookName::APP_BOOTED)]
                                    public function onAppBooted(): void
                                    {
                                    // Initialize services, register listeners, etc.
                                    }

Official Modules

ForgeAuth

Complete authentication system with user registration, login, password management, and session handling. Provides middleware, validation, and user management services. Includes optional JWT support for mobile applications when enabled via configuration.

Authentication Sessions JWT Mobile

ForgeDeployment

Complete deployment automation system. Deploy applications to cloud providers (DigitalOcean, custom providers) with automated provisioning, rollback, and zero-downtime deployments. Includes SSH key management, SSL configuration, and deployment state tracking.

Cloud Automation Provisioning Rollback

ForgeUI

Example module demonstrating how to create your own design system as a module capability. Shows that you can package UI components, styles, and design patterns as a reusable module that can be shared across Forge applications.

Example Design System Template

ForgeWire

Reactive protocol for PHP. Build dynamic interfaces with standard PHP controllers, island boundaries, and permission-based attributes. No JavaScript frameworks or separate component classes needed.

Authentication Sessions JWT Mobile

ForgeDeployment

Complete deployment automation system. Deploy applications to cloud providers (DigitalOcean, custom providers) with automated provisioning, rollback, and zero-downtime deployments. Includes SSH key management, SSL configuration, and deployment state tracking.

Cloud Automation Provisioning Rollback

ForgeUI

Example module demonstrating how to create your own design system as a module capability. Shows that you can package UI components, styles, and design patterns as a reusable module that can be shared across Forge applications.

Example Design System Template

ForgeStorage

Flexible file storage system with multiple driver support. Handles local filesystem, cloud storage providers, and custom storage backends. Includes bucket management and file operations.

Storage Files Cloud

ForgeDebugBar

Development debugging toolbar with query logging, performance metrics, timeline tracking, memory usage, request/response inspection, and exception details. Only active in development environments.

Debug Development Profiling

ForgeTesting

Complete testing framework with unit tests, integration tests, and test utilities. Supports testing in app, engine, and module scopes with test grouping and filtering capabilities.

Testing Quality TDD

ForgeHub

Admin dashboard and management interface for your Forge applications.

Admin Dashboard

ForgeMarkDown

Markdown processing and rendering with syntax highlighting support. Converts markdown text to HTML with code block highlighting and extended markdown features.

Markdown Parser Rendering

ForgeLogger

Advanced logging system with multiple drivers (file, database, syslog), log channels, log levels, and structured logging. Supports log rotation and filtering.

Logging Monitoring Debugging

ForgeTailwind

Tailwind CSS integration with build tools, asset compilation, and development server support. Provides utilities for managing Tailwind configuration and purging unused styles.

CSS Styling Build Tools

ForgeErrorHandler

Comprehensive error handling and exception management for production applications. Provides custom error pages, exception logging, error reporting, and graceful error recovery.

Error Exception Production

ForgeEvents

Event-driven architecture system with event listeners, event queues, and async event processing. Supports event broadcasting, queued listeners, and event subscribers.

Events Queues Async

ForgeNotification

Multi-channel notification system with email, SMS, and push notifications.

Notifications Multi-channel

ForgePackageManager

Package and capability management system with registry support, integrity verification, and multiple source types (Git, SFTP, FTP, HTTP, Local, Network). Manages capability installation, removal, and project scaffolding.

Package Manager Registry CLI

ForgeDatabaseSQL

SQL database support implementing the kernel's DatabaseConnectionInterface. Supports SQLite, MySQL, and PostgreSQL with PDO-based connections, migrations, and seeders.

Database SQL PDO

ForgeSqlOrm

SQL ORM implementing the kernel's QueryBuilderInterface. Provides attribute-based models, relationships, query builder, and supports SQLite, MySQL, and PostgreSQL. Includes traits like HasTimeStamps and HasMetaData.

ORM Models Relationships

ForgeMultiTenant

Multi-tenant database isolation capability. Automatically resolves tenants by domain/subdomain, provides separate database connections per tenant, and includes #[TenantScope] attribute for controllers. Supports tenant-specific migrations and seeders.

Multi-Tenant Isolation SaaS

Installing Capabilities

Use Forge CLI or manually place capability modules in the modules directory.

Using Forge CLI

Commands use an interactive wizard by default. You can skip the wizard by providing the --module= flag or by providing module names as positional arguments.

Installation Wizard: When installing, you can choose to enter the module name manually or browse available modules. When browsing, you'll select a registry, then choose between single or multiple module selection. In multi-select mode, use checkboxes to select multiple modules (Space to toggle, Enter to confirm) - all will install latest versions. In single-select mode, you'll choose a version (with commit messages for git-based registries), and finally choose whether to force download.

Removal Wizard: When removing, you can choose between single or multiple module selection. You'll see a list of all installed modules with their descriptions. In multi-select mode, use checkboxes to select multiple modules to remove at once.

Multiple Module Support: Both commands support installing or removing multiple modules at once via command-line arguments. For installation, if no version is specified, the latest version is installed automatically.

# Install a capability (wizard-based, interactive)
                                    php forge.php package:install-module

                                    # Skip wizard and install directly
                                    php forge.php package:install-module --module=forge-auth

                                    # Install a specific version (skips version selection in wizard)
                                    php forge.php package:install-module --module=forge-auth@1.2.0

                                    # Install multiple modules (latest versions)
                                    php forge.php package:install-module forge-auth forge-storage forge-logger

                                    # Install multiple modules with mixed versions
                                    php forge.php package:install-module forge-auth@1.2.0 forge-storage forge-logger@0.1.0

                                    # Force download bypassing cache
                                    php forge.php package:install-module --module=forge-auth --force

                                    # List available capabilities
                                    php forge.php package:list-modules

                                    # Remove a capability (wizard-based, shows installed modules with descriptions)
                                    php forge.php package:remove-module

                                    # Skip wizard and remove directly
                                    php forge.php package:remove-module --module=forge-auth

                                    # Remove multiple modules
                                    php forge.php package:remove-module forge-auth forge-storage forge-logger

Manual Installation

# Clone capability to modules directory
                                    cd modules/
                                    git clone https://github.com/forge-modules/ForgeAuth.git

                                    # Or download and extract
                                    wget https://github.com/forge-modules/ForgeAuth/archive/main.zip
                                    unzip main.zip -d ForgeAuth/

Auto-Discovery: Capabilities auto-load when placed in the modules directory.

Creating Custom Capabilities

Encapsulate functionality and share across projects as capability modules.

# Generate a new capability module (wizard-based)
                                    php forge.php generate:module

                                    # Skip wizard and generate directly
                                    php forge.php generate:module --name=MyCustomModule

                                    # With description and version
                                    php forge.php generate:module --name=MyCustomModule --description="My custom module" --version=1.0.0

The wizard will prompt you for:

  • Name: Module name in PascalCase (e.g., MyCustomModule)
  • Description: Brief description of the module
  • Version: Module version (default: 0.1.0)

This creates a complete capability module structure in modules/MyCustomModule/:

modules/MyCustomModule/
                                    ├── forge.json # Module configuration
                                    ├── src/ # Module source code
                                    │ ├── MyCustomModule.php # Module class
                                    │ ├── Controllers/ # Module controllers
                                    │ ├── Services/ # Module services
                                    │ ├── Models/ # Module models
                                    │ ├── Commands/ # CLI commands
                                    │ └── Contracts/ # Interfaces and contracts
                                    ├── config/ # Module configuration files
                                    ├── resources/ # Module resources
                                    │ ├── views/ # Module views
                                    │ └── assets/ # CSS, JS, images
                                    └── tests/ # Module tests

Module Structure

Module Configuration (forge.json)

{
                                    "$schema": "./../../engine/Core/Schema/module-schema.json",
                                    "name": "MyCustomModule",
                                    "version": "1.0.0",
                                    "description": "A custom module for my application",
                                    "type": "generic",
                                    "order": 100,
                                    "cli": {
                                    "commands": []
                                    },
                                    "tags": [],
                                    "config": {
                                    "defaults": {}
                                    },
                                    "author": "Your Name",
                                    "license": ""
                                    }

Module Class

<?php

                                    declare(strict_types=1);

                                    namespace App\Modules\MyCustomModule;

                                    use Forge\Core\DI\Container;
                                    use Forge\Core\Module\Attributes\Module;
                                    use Forge\Core\Module\Attributes\Service;
                                    use Forge\Core\Module\Attributes\Compatibility;
                                    use Forge\Core\Module\Attributes\ConfigDefaults;
                                    use Forge\Core\Module\Attributes\PostInstall;
                                    use Forge\Core\Module\Attributes\PostUninstall;
                                    use App\Modules\MyCustomModule\Services\CustomService;
                                    use App\Modules\MyCustomModule\Contracts\CustomInterface;
                                    use Forge\Core\Module\Attributes\LifecycleHook;
                                    use Forge\Core\Module\LifecycleHookName;

                                    #[Module(
                                    name: 'MyCustomModule',
                                    description: 'A custom module for my application',
                                    order: 100,
                                    core: false, // Set to true to skip auto-loading (manual wiring required)
                                    isCli: false // Set to true to only load in CLI context
                                    )]
                                    #[Service]
                                    #[Compatibility(framework: '>=0.1.0', php: '>=8.3')]
                                    #[ConfigDefaults(defaults: [
                                    "my_custom_module" => [
                                    "setting1" => "default_value",
                                    "setting2" => true,
                                    ]
                                    ])]
                                    #[PostInstall(command: 'migrate', args: ['--type=module', '--module=MyCustomModule'])]
                                    #[PostUninstall(command: 'migrate:rollback', args: ['--type=module', '--module=MyCustomModule'])]
                                    final class MyCustomModule
                                    {
                                    public function register(Container $container): void
                                    {
                                    // Register services
                                    $container->bind(CustomInterface::class, CustomService::class);
                                    }

                                    #[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
                                    public function onAfterModuleRegister(): void
                                    {
                                    // Module registration complete
                                    }
                                    }

Module Attributes:

  • core: true — Module won't be auto-loaded. You must wire it manually.
  • isCli: true — Module only loads in CLI context, not in web requests.
  • #[ConfigDefaults] — Define default configuration directly in the module class. You can still override these in config/.
  • #[PostInstall] — Automatically run CLI commands after module installation.
  • #[PostUninstall] — Automatically run CLI commands after module uninstallation.

Lifecycle Hooks

Modules can hook into the application lifecycle at various points using the #[LifecycleHook] attribute. The only method you implement in your module class is register() for service registration.

Available Lifecycle Hooks

After Boot

Executed after the application has booted

After Module Load

Executed after all modules are loaded

After Module Register

Executed after a module is registered

After Config Loaded

Executed after configuration is loaded

App Booted

Executed when the application is fully booted

Before Request

Executed before each HTTP request

After Request

Executed after each HTTP request

After Response

Executed after HTTP response is sent

Using Lifecycle Hooks

<?php

                                    declare(strict_types=1);

                                    namespace App\Modules\MyCustomModule;

                                    use Forge\Core\DI\Container;
                                    use Forge\Core\Module\Attributes\Module;
                                    use Forge\Core\Module\Attributes\LifecycleHook;
                                    use Forge\Core\Module\LifecycleHookName;

                                    #[Module(name: 'MyCustomModule', description: 'A custom module', order: 100)]
                                    final class MyCustomModule
                                    {
                                    public function register(Container $container): void
                                    {
                                    // Register services and bindings here
                                    $container->bind(CustomInterface::class, CustomService::class);
                                    }

                                    #[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
                                    public function onAfterModuleRegister(): void
                                    {
                                    // This hook is called after this module is registered
                                    // Perform initialization logic here
                                    }

                                    #[LifecycleHook(hook: LifecycleHookName::APP_BOOTED)]
                                    public function onAppBooted(): void
                                    {
                                    // This hook is called when the application is fully booted
                                    // Initialize services, register listeners, etc.
                                    }
                                    }

Publishing Capabilities

Publish your capabilities to a registry for distribution. This requires Forge developer mode to be enabled.

Initializing a Registry

Before publishing, you need to initialize a registry. Use the dev:registry:init command:

# Initialize a modules registry (wizard-based)
                                    php forge.php dev:registry:init

                                    # Skip wizard
                                    php forge.php dev:registry:init --type=modules

The wizard will ask for:

  • Registry type (framework or modules)
  • Git repository URL
  • Branch name (default: main)
  • Whether it's a private repository

Browsing Available Modules

Use dev:module:list to browse all available modules in your registry:

# Browse modules with interactive dropdown
                                    php forge.php dev:module:list

This command provides a user-friendly dropdown interface where you can:

  • Select any module from an interactive menu
  • View all available versions for that module
  • See the last commit message for each version

Creating a Module Version

Use dev:module:version to create a new version of your module:

# Create version (wizard-based)
                                    php forge.php dev:module:version

                                    # Skip wizard
                                    php forge.php dev:module:version --name=MyCustomModule --type=minor
                                    php forge.php dev:module:version --name=MyCustomModule --version=1.2.0

The create version wizard will:

  1. Prompt for module name (or use --name=ModuleName)
  2. Detect current version from forge.json
  3. If version needs incrementing, ask for increment type (patch/minor/major) or use --type=
  4. Automatically update module version in source files
  5. Create ZIP file of the module
  6. Calculate SHA-256 integrity hash
  7. Update modules.json manifest
  8. Commit changes to registry (if in git repository)

Publishing to Registry

After creating a version, publish it to the remote registry:

# Publish all changes to remote registry
                                    php forge.php dev:module:publish

                                    # Publish specific module
                                    php forge.php dev:module:publish --name=MyCustomModule

Publishing Checklist

  • Complete forge.json with all metadata
  • Write comprehensive documentation
  • Include unit and integration tests
  • Follow semantic versioning
  • Add proper license file
  • Test compatibility with different Forge versions
  • Ensure registry is initialized and configured

Registry Workflow: For detailed information about registry structure, integrity hashes, and source types, see the ForgePackageManager documentation.

Some Suggestions

These are just suggestions based on what tends to work well. You do you. Build modules however makes sense for your project.

Things That Often Help

  • • Descriptive module names make things easier to find
  • • PSR-4 autoloading keeps things organized
  • • Tests can catch issues before they reach production
  • • Documentation helps others (and future you) understand your code
  • • Semantic versioning makes dependency management clearer
  • • Handling dependencies gracefully reduces surprises

Things to Consider

  • • Modifying core files can make upgrades harder
  • • Tight coupling between modules reduces flexibility
  • • Error handling prevents unexpected failures
  • • Version constraints help avoid compatibility issues
  • • Hardcoded values can make configuration difficult
  • • Cleaning up resources prevents memory leaks