Vix.cpp v2.7.1

Vix.cpp v2.7.1 introduces the first complete foundation for Vix App Modules.

Applications and backend projects can now declare internal modules in vix.app, enable or disable them from one place, generate module-specific source structures, wire enabled modules into the executable automatically, and validate architectural problems before they become build failures.

The release also updates vix dev so changes to vix.app trigger the configuration work required to regenerate module wiring. SDK lifecycle handling and vix uninstall receive a broader command workflow for inspecting and removing CLI installations, SDK profiles, and globally installed packages.

Release focus

A small C++ application can remain understandable with one executable target and a compact src/ directory. As the project grows, that structure often becomes less clear.

Authentication, projects, package management, storage, billing, build history, administration, and other areas begin to share the same source tree. Routes are registered from several places, tests lose their connection to the feature they cover, and disabling one part of the application may require manual edits across CMake, startup code, and source files.

Vix App Modules provide an internal organization layer for this kind of project.

A module belongs to one application. It can contain its own source files, routes, controller, tests, migrations, and metadata, while the application keeps one executable, one dependency graph, and one main runtime.

This is different from creating an independent library for every feature. Internal modules are intended to organize one application without forcing each feature to become a separately versioned or installed package.

Declaring modules in vix.app

Application modules are declared through [module.<name>] sections in vix.app.

A basic declaration looks like this:

[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []

The module name comes from the section name. The remaining fields describe how the application should load it.

enabled determines whether the module participates in the active build.

path points to the module directory relative to the project root.

kind describes the role of the module in the application workflow.

depends records dependencies between internal application modules.

For example:

[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = ["auth"]

This states that projects is active and requires the auth module.

The declaration is part of the application manifest because module activation is an application-level decision. A module directory may exist on disk without participating in every build.

Application manifest support

The vix.app loader now parses module declarations into structured application metadata.

Each module is represented with its:

name
enabled state
path
kind
internal dependencies

This metadata is used consistently by module listing, validation, generated CMake, runtime wiring, dev-mode rebuild decisions, and CLI module commands.

The application manifest also supports:

type = "backend"

A backend application is mapped internally to an executable target. This gives backend projects the same module-aware generated build path as other executable vix.app applications.

Creating an application module

A module can be created with:

vix modules add auth

Inside a vix.app project, the command now performs more than creating a folder.

It generates the module structure, writes a vix.module manifest, creates a test file, and registers the new module in the root vix.app.

The developer does not need to add the [module.auth] section manually after generation.

The exact generated structure depends on the application type. Backend projects receive a backend-oriented module, while general application projects receive a routed service module.

Backend module generation

Inside a backend project, vix modules add generates a module prepared for routes, controllers, migrations, tests, and future data or service layers.

A generated module contains files such as:

modules/auth/
├── CMakeLists.txt
├── vix.module
├── include/
│   ├── AuthModule.hpp
│   └── AuthController.hpp
├── src/
│   ├── AuthModule.cpp
│   └── AuthController.cpp
├── migrations/
└── tests/
    └── test_auth.cpp

The generated controller and module provide a small working route rather than an empty placeholder.

This allows the module to compile, register itself, and demonstrate the expected application integration immediately after creation.

The initial skeleton remains deliberately small. It creates the boundaries required by the workflow without deciding that every backend module must use a particular repository, service, model, or persistence architecture.

Those layers can be added when the module actually needs them.

Service modules for application projects

General executable app projects receive routed service modules.

A generated service module contains:

<Module>Module.hpp
<Module>Module.cpp
<Module>Controller.hpp
<Module>Controller.cpp
vix.module
tests/test_<module>.cpp

The generated example includes route registration and a minimal HTTP response so the developer can verify that the module is active.

Service modules are recorded with:

kind = "service"

This allows generated application wiring to distinguish them from unrelated source folders and include them in route registration.

The module remains part of the main application runtime. It does not create a separate server process or executable.

Module manifests

Every generated module receives a vix.module file.

The manifest describes the module itself rather than its application-level activation state.

A basic generated manifest can contain:

name = "auth"
kind = "backend"

[routes]
prefix = "/api/auth"

[tests]
enabled = true

The root vix.app decides whether the module is enabled and where it lives. The module manifest describes details that belong to the module, such as its kind, route prefix, and test configuration.

This separation allows module metadata to stay close to the module source while keeping the active application composition visible from one root file.

Enabling and disabling modules

Declared modules can be activated through the CLI:

vix modules enable auth

They can be disabled with:

vix modules disable auth

These commands update the corresponding enabled value in vix.app.

A disabled module can remain in the repository without being compiled or linked. Its files, tests, and manifest stay available for later use, but it does not participate in the current application.

This is useful for optional features, experimental work, deployment variants, and modules that are temporarily unavailable while another part of the project is being changed.

Disabling a module is not implemented by deleting its CMake files or commenting out startup code. The application manifest remains the source of truth.

Listing application modules

The active module state can be inspected with:

vix modules list

The output includes the declared module name, enabled state, kind, configured path, filesystem status, and internal dependencies.

This helps distinguish several conditions that would otherwise look similar during a build:

  • a module is declared and enabled;
  • a module is declared but disabled;
  • a module is declared but missing on disk;
  • a directory exists but is not declared;
  • a module depends on another module.

The command reflects vix.app, not every arbitrary folder found under modules/.

Enabled-module build generation

Generated vix.app CMake projects now load only the modules enabled in the application manifest.

Vix emits the active set through:

VIX_ENABLED_MODULES

This list controls which module directories are added to the generated build.

An empty list is emitted explicitly when no modules are enabled. This is important because the absence of the variable could otherwise cause the older CMake fallback to load every directory under modules/.

The behavior now differs intentionally between project types:

vix.app project:
  load only VIX_ENABLED_MODULES

classic CMake project:
  preserve legacy modules/* discovery

Classic projects continue to use the previous convention unless they adopt the vix.app module workflow.

Automatic application wiring

Enabled modules are connected to executable applications through generated source files:

.vix/generated/app/include/vix_app_modules.hpp
.vix/generated/app/vix_app_modules.cpp

The generated implementation includes the enabled routed modules and provides the registration code used by the application startup path.

For executable vix.app targets, vix_app_modules.cpp is added automatically to the generated CMake target.

The application template keeps a small integration point rather than requiring developers to modify src/main.cpp whenever a module is added or disabled.

This allows the root application bootstrap to remain stable while module registration follows the manifest.

Module registry integration

Generated app projects now include a small module registry layer:

include/app/ModuleRegistry.hpp
src/app/ModuleRegistry.cpp

The registry provides a clear point where generated module registration and application startup meet.

The goal is not to hide module construction behind a large runtime framework. It is to prevent the main source file from becoming a manually maintained list of every route and feature in the application.

A typical application entry point can initialize its core runtime and delegate module registration to the registry.

When the module set changes, Vix regenerates the application module wiring without requiring the developer to rewrite the main bootstrap.

Route registration

Enabled routed modules register their routes automatically.

For a module with:

[routes]
prefix = "/api/auth"

the generated application wiring includes the module registration hook associated with that route group.

When the module is disabled, its generated registration disappears from the active build. The route is no longer available because the module itself is not compiled or wired into the executable.

This behavior was validated for both service modules in app projects and backend modules in backend projects.

Route availability therefore follows the same activation state as compilation and linking.

Internal module dependencies

Modules can declare dependencies on other modules:

[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = ["auth"]

Internal dependencies describe application structure rather than registry packages.

The declaration says that the projects module expects the auth module to participate in the same application.

Vix validates these relationships before the generated build is configured.

An enabled module cannot depend on an undeclared module, and it cannot depend on a module that is currently disabled.

This prevents application configurations where compilation succeeds partially but required runtime behavior is absent.

Circular dependency detection

vix modules check now detects circular internal dependencies.

For example:

auth depends on projects
projects depends on auth

This structure is rejected before CMake generation.

Circular module relationships usually indicate that the boundary between two features is unclear or that shared behavior should move into a lower-level module.

Detecting the cycle at the manifest level gives the developer a direct architectural error rather than allowing the relationship to emerge later through include paths, link order, or runtime initialization.

Module validation

The module checker now validates the complete relationship between vix.app, the filesystem, module manifests, and internal dependencies.

Run:

vix modules check

The command reports conditions such as:

declared module missing on disk
enabled module missing CMakeLists.txt
enabled module missing vix.module
module directory not declared in vix.app
dependency on an undeclared module
dependency on a disabled module
circular module dependency
duplicate route prefix

These checks are intended to catch architectural drift early.

Without them, a module may appear in the source tree but never compile, two modules may register the same route prefix, or a disabled dependency may leave another feature in an invalid state.

Duplicate route prefixes

Vix now checks route prefixes declared in enabled module manifests.

Two modules declaring the same prefix can create ambiguous or order-dependent route behavior.

For example:

# modules/auth/vix.module
[routes]
prefix = "/api/users"

and:

# modules/accounts/vix.module
[routes]
prefix = "/api/users"

will produce a module validation error.

The check happens before runtime registration, where the resulting behavior would be harder to understand.

Generated module tests

New modules include a test file by default.

Generated CMake creates module test targets when the application test option is enabled:

<app>_BUILD_TESTS

The generated application CMake now declares its test options before module directories are loaded.

This ordering is important because modules decide whether to create their test targets while their CMake files are being evaluated.

Previously, the application test option could be introduced after the modules had already been processed, causing valid module tests to be skipped.

Module tests can now be discovered and run through:

vix tests

The generated test provides a starting point and confirms that the module target participates correctly in the application build.

Dev mode and manifest changes

vix dev now treats vix.app as an active project configuration file.

A source or header change can continue through the fast rebuild path. The existing generated CMake structure remains valid, so Vix rebuilds and restarts the application without repeating unnecessary project generation.

A change to vix.app is different.

Enabling a module, disabling a module, changing a module path, or editing the application target can alter generated CMake and module wiring.

Vix now recognizes this distinction:

source or header change:
  fast rebuild

vix.app change:
  regenerate, reconfigure, rebuild, restart

This makes dev mode follow the real project state rather than continuing to run an executable generated from an older manifest.

Manifest-aware regeneration

When vix.app changes, vix dev can regenerate:

generated application CMake
VIX_ENABLED_MODULES
vix_app_modules.hpp
vix_app_modules.cpp
module registration
target source lists

The project is then reconfigured before rebuilding.

This fixes cases where editing the module list appeared to have no effect during watch mode because the previous fast rebuild path did not revisit application generation.

The developer can now enable or disable a module while vix dev is active and receive an application built from the updated manifest.

SDK lifecycle improvements

This release also improves how installed SDK profiles are registered and removed.

SDK upgrades now register installed profiles with the CMake user package registry.

This helps CMake-based consumer projects locate the installed SDK through the expected package discovery mechanisms.

The uninstall workflow removes the related SDK state rather than deleting only the main installation directory.

Cleanup can include:

installed SDK directory
current profile metadata
current profile pointer
CMake user package registry entry

This prevents a removed SDK from continuing to appear active through stale metadata or CMake registration.

Expanded uninstall workflow

vix uninstall now provides a command experience aligned with the newer vix upgrade workflow.

Normal output uses clearer sections, status lines, hints, and completion messages.

A removal can be inspected before files are deleted with:

vix uninstall --dry-run

Machine-readable output is available through:

vix uninstall --json

Detailed diagnostic output can be requested with:

vix uninstall --verbose

The command now covers CLI removal, SDK profiles, and globally installed packages through one consistent interface.

SDK uninstall commands

Installed SDK profiles can be managed with:

vix uninstall --sdk <profile>
vix uninstall --sdk-all
vix uninstall --sdk-list

--sdk-list shows the installed profiles available for removal.

--sdk <profile> removes one selected profile and its associated metadata.

--sdk-all removes all installed SDK profiles.

These commands do not uninstall the Vix CLI unless the user explicitly selects the broader CLI removal workflow.

This separation is useful when changing SDK profiles while keeping the command-line tool itself installed.

Global package uninstall

Globally installed packages can be removed with:

vix uninstall -g <package>

or:

vix uninstall --global <package>

The package entry is removed from the global installation manifest together with the files owned by that package.

This fixes cases where the files were removed but the global package registry continued to report the package as installed.

The command also uses the newer uninstall output rather than a separate older presentation path.

CLI uninstall path detection

Removing the Vix CLI safely requires identifying the actual binary being used.

The command can now resolve the installation path from several sources:

installation metadata
VIX_CLI_PATH
shell command lookup
explicit installation prefix
explicit binary path

Explicit options include:

--prefix <dir>
--path <file>
--system

This avoids assuming that every installation lives under one fixed system directory.

A user-built CLI, a system installation, and a custom-prefix installation may all resolve differently.

Removal safety

The uninstall command provides options for broader cleanup:

--purge
--all
--system

Potentially destructive operations are made explicit and can be reviewed with --dry-run.

The command reports when another vix binary remains available through the shell path after removal.

This can happen when several installations exist, such as one under /usr/local/bin and another in a user directory.

Instead of reporting a misleading success and leaving the user confused when vix still runs, the CLI explains that another binary is being resolved.

Fixed module activation behavior

This release fixes a conflict between the new manifest-driven module system and the older modules/* CMake fallback.

In early implementations, disabling a module in vix.app did not always prevent the legacy loader from discovering its folder and compiling it anyway.

Vix now emits the enabled module list for every vix.app project, including when that list is empty.

The legacy folder scan remains available only for classic CMake projects that do not use the application manifest module model.

As a result:

[module.auth]
enabled = false

now reliably prevents auth from being added to the generated application target.

Fixed generated registration

vix modules add now registers new modules in vix.app automatically.

Generated service modules use the correct:

kind = "service"

metadata and participate in the generated app wiring.

Backend modules compile with their generated route registration and become available through the normal application startup path.

Disabling either kind removes its route because the module no longer enters the generated build or registration code.

Fixed module test generation

Generated module tests are now created once and included in the correct build phase.

The release removes duplicate file output previously produced during some module generation paths.

Application test options are declared before module loading so each enabled module can create its test target when requested.

This makes the workflow consistent:

vix modules add auth
vix build
vix tests

No manual CMake edits are required to make the generated test visible.

Application structure

A backend can now grow around feature-oriented directories:

modules/
├── auth/
├── projects/
├── builds/
└── packages/

Each module can keep its own manifest, routes, controller, implementation, migrations, and tests.

The application bootstrap remains responsible for shared runtime configuration, server startup, global middleware, and infrastructure used across modules.

Feature-specific behavior remains inside the module that owns it.

The model is intentionally internal to the application. It provides structure without requiring a distributed system, plugin runtime, or separate package for every feature.

Example workflow

Create a backend project:

vix new cloud --template backend
cd cloud

Add two modules:

vix modules add auth
vix modules add projects

Declare the dependency of projects on auth:

[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []

[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = ["auth"]

Check the structure:

vix modules check

Build and run:

vix build
vix run

Disable one module:

vix modules disable projects

During vix dev, the manifest change triggers application regeneration and removes the disabled module from the active executable.

Validation

The App Modules workflow was validated across manifest parsing, generation, CMake integration, runtime registration, module state changes, tests, and development mode.

Coverage includes:

  • parsing [module.<name>] sections;
  • enabled and disabled module state;
  • custom module paths;
  • service and backend module kinds;
  • internal dependency lists;
  • automatic registration in vix.app;
  • vix.module generation;
  • generated controller and route files;
  • backend migration directories;
  • generated test files;
  • ModuleRegistry generation;
  • vix_app_modules.hpp and vix_app_modules.cpp;
  • executable target integration;
  • automatic route registration;
  • empty enabled-module lists;
  • exclusion of disabled modules;
  • legacy loading compatibility for classic CMake projects;
  • missing module directories;
  • missing CMakeLists.txt;
  • missing vix.module;
  • undeclared folders;
  • disabled dependencies;
  • undeclared dependencies;
  • circular dependencies;
  • duplicate route prefixes;
  • module test discovery through vix tests;
  • manifest-aware rebuilds through vix dev.

The uninstall workflow was validated for SDK profile listing, single-profile removal, complete SDK cleanup, global package removal, dry-run behavior, JSON output, explicit installation paths, and stale shell-path detection.

Compatibility

Classic CMake projects can continue to load modules through the existing modules/* convention.

The stricter enabled-module behavior applies to projects using vix.app, where the manifest is now the authoritative source of application composition.

Existing vix.app projects without module declarations remain valid. Their generated executable workflow continues without requiring a modules/ directory.

Generated modules remain ordinary C++ and CMake source directories. Developers can inspect and modify their files without relying on a hidden binary format or runtime service.

SDK uninstall commands do not remove the Vix CLI unless the broader CLI uninstall option is selected.

Existing global package installations remain compatible with the improved uninstall manifest cleanup.

Known limitations

Vix App Modules in this release are internal application modules. They are not independently published registry packages.

The first generated structures focus on routed service and backend modules. More specialized module workflows can be added later without changing the manifest foundation.

Internal dependencies are validated for declaration, activation state, and cycles, but this release does not yet provide module-level registry package declarations. External package ownership inside modules is introduced in v2.7.2.

Generated route registration assumes the standard Vix application and backend startup model. Projects with heavily customized bootstraps may need to connect the generated module registry at their own integration point.

Disabling a module removes it from compilation and generated registration, but it does not delete its source files or migration history.

Release summary

Vix.cpp v2.7.1 gives C++ applications a manifest-driven internal module structure.

Modules can be declared, generated, enabled, disabled, listed, validated, tested, and wired into the application without maintaining separate registration code in main.cpp.

Backend projects receive feature-oriented module skeletons with controllers, routes, migrations, and tests. General applications receive routed service modules connected through a small generated module registry.

vix dev now understands that application manifest changes can alter the generated build and performs the required regeneration instead of treating them like ordinary source edits.

The release also improves SDK registration and expands vix uninstall into a clearer workflow for CLI installations, SDK profiles, and global packages.

This establishes the application module foundation extended by later v2.7 releases with module-level package dependencies and generated WebSocket workflows.