vix.app Project Resolution

vix.app project resolution is the step where Vix decides what kind of project it is working with.

Before Vix can build or run anything, it needs to answer a few questions:

Where is the project root?
Is this a CMake project?
Is this a vix.app project?
What source directory should CMake use?
What target name should be built?
Where should build directories be created?

This resolution step is small, but it is important.

If project resolution is wrong, the build system can use the wrong directory, the wrong target name, or the wrong generated CMake source.

The resolution rule

Vix uses this rule:

1. If CMakeLists.txt exists, use CMakeLists.txt.
2. Otherwise, if vix.app exists, use vix.app.

This keeps existing CMake projects safe.

A project like this is resolved as a CMake project:

myapp/
  CMakeLists.txt
  vix.app
  src/
    main.cpp

A project like this is resolved as a vix.app project:

myapp/
  vix.app
  src/
    main.cpp

CMake has priority because it is the full-control path.

vix.app is used only when there is no CMakeLists.txt.

Why CMake has priority

CMake projects can contain arbitrary build logic.

If a CMakeLists.txt exists, Vix should not ignore it.

That file may define:

custom targets
generated sources
install rules
CTest integration
toolchains
package exports
platform branches
dependency setup

Using vix.app instead would risk breaking the project.

The safe rule is:

CMakeLists.txt is explicit full control.
vix.app is the simple project path.

The project root

The project root is the directory that contains one of these files:

CMakeLists.txt
vix.app

When Vix starts from a directory, it can search upward until it finds a project root.

Example:

myapp/
  vix.app
  src/
    main.cpp
    features/
      auth.cpp

If the user runs Vix from:

myapp/src/features/

Vix can walk upward and find:

myapp/vix.app

The resolved project root is:

myapp/

CMake project resolution

For a normal CMake project:

myapp/
  CMakeLists.txt
  src/
    main.cpp

the resolved model is simple:

project kind:       CMake
user project dir:   myapp/
CMake source dir:   myapp/
CMakeLists path:    myapp/CMakeLists.txt
target name:        usually myapp
generated:          false

In this case, the user project directory and the CMake source directory are the same.

Vix can configure CMake with:

cmake -S myapp -B myapp/build-ninja

vix.app project resolution

For a vix.app project:

myapp/
  vix.app
  src/
    main.cpp

Vix resolves the project differently.

The user project directory is still:

myapp/

But the CMake source directory is generated:

myapp/.vix/generated/app/

The resolved model becomes:

project kind:       vix.app
user project dir:   myapp/
CMake source dir:   myapp/.vix/generated/app/
CMakeLists path:    myapp/.vix/generated/app/CMakeLists.txt
target name:        manifest name
generated:          true

So if vix.app contains:

name = hello
type = executable
standard = c++20

sources = [
  src/main.cpp,
]

then the default target name is:

hello

not necessarily the project folder name.

Why target name matters

The target name is important because it is used by:

vix build
vix run
CMake target selection
executable lookup
diagnostics
artifact identity

If the project folder is called:

hello-project/

but the manifest says:

name = hello

then Vix should build and run:

hello

not:

hello-project

This is why vix.app resolution must expose the manifest target name.

The important separation

For vix.app, there are two different directories:

userProjectDir
cmakeSourceDir

They must not be confused.

The user project directory is where the real project lives:

myapp/

It contains:

vix.app
src/
include/
assets/
tests/

The CMake source directory is internal:

myapp/.vix/generated/app/

It contains the generated:

CMakeLists.txt

These two paths serve different purposes.

userProjectDir

userProjectDir should be used for user-facing project operations.

Examples:

build directories
.env lookup
.vix metadata
resources
source path resolution
snapshots
local cache state
exported binaries
watch mode

For a vix.app project:

userProjectDir = myapp/

That should remain true even though the generated CMake file is somewhere else.

cmakeSourceDir

cmakeSourceDir should be used for CMake configuration.

Examples:

cmake -S
generated CMake diagnostics
CMakeLists.txt path
CMake configure source directory

For a vix.app project:

cmakeSourceDir = myapp/.vix/generated/app/

So Vix configures CMake with:

cmake -S myapp/.vix/generated/app -B myapp/build-ninja

not with:

cmake -S myapp -B myapp/build-ninja

because the original project root does not contain a CMakeLists.txt.

The bug this separation avoids

A common mistake is to store only one projectDir.

For CMake projects, that works because:

projectDir = user project dir = CMake source dir

But for vix.app, that breaks down.

If projectDir is changed to:

myapp/.vix/generated/app/

then other systems may accidentally treat the generated directory as the real project.

That can break:

target name detection
build directory placement
export paths
input snapshots
watch mode
resource paths
.env lookup
cache keys

The correct model is to keep both paths.

A better build plan model

A build plan should distinguish:

userProjectDir
cmakeSourceDir
defaultTargetName
generatedFromVixApp

For a CMake project:

userProjectDir       = myapp/
cmakeSourceDir       = myapp/
defaultTargetName    = myapp
generatedFromVixApp  = false

For a vix.app project:

userProjectDir       = myapp/
cmakeSourceDir       = myapp/.vix/generated/app/
defaultTargetName    = manifest.name
generatedFromVixApp  = true

This makes the rest of the build system simpler.

Each operation can choose the correct path.

Configure uses cmakeSourceDir

CMake configure should use:

cmakeSourceDir

For CMake projects:

cmake -S myapp -B myapp/build-ninja

For vix.app projects:

cmake -S myapp/.vix/generated/app -B myapp/build-ninja

This is the only path that should be passed to cmake -S.

Build directories use userProjectDir

Build directories should be created under the user project directory.

For example:

myapp/build-ninja/
myapp/build-dev/
myapp/build-release/

Not under:

myapp/.vix/generated/app/build-ninja/

The generated CMake directory is internal source metadata.

It should not become the visible project root.

Default target uses manifest name

For vix.app, the default target should come from:

name = hello

So vix build should build:

cmake --build build-ninja --target hello

not:

cmake --build build-ninja --target app

The generated directory is named app, but that is not the target name.

The target name belongs to the manifest.

vix build project resolution

For vix build, project resolution should produce a build plan.

The build plan should contain:

userProjectDir
cmakeSourceDir
buildDir
configureLog
buildLog
defaultTargetName
generatedFromVixApp

Then the build command can do:

configure:
  cmake -S cmakeSourceDir -B buildDir

build:
  cmake --build buildDir --target defaultTargetName

cache/snapshot/export:
  use userProjectDir

This keeps CMake integration and user project handling separate.

vix run project resolution

vix run also needs the same resolved project metadata.

It needs to know:

where to configure
where to build
which target to build
which executable to run
where the real project lives

For vix.app, it should use:

resolved.userProjectDir
resolved.cmakeSourceDir
resolved.targetName
resolved.generated

Then it can build the correct target and search for the executable by manifest name.

Executable lookup

After building, vix run needs to find the executable.

For a vix.app project:

name = hello
output_dir = bin

Vix should search common locations such as:

build-ninja/hello
build-ninja/bin/hello
build-ninja/src/hello

The lookup should use:

targetName = hello

not the folder name and not the generated directory name.

Watch mode

Watch mode should watch the real project directory.

For CMake projects:

watch myapp/

For vix.app projects:

watch myapp/

It should not watch only:

myapp/.vix/generated/app/

The generated directory does not contain the user’s real source files.

Watch mode belongs to the user project directory.

Diagnostics

Project resolution also affects diagnostics.

For a generated vix.app project, build errors may involve:

generated CMakeLists.txt
real source files
manifest fields

A good diagnostic should show the correct context.

Examples:

Project directory:
  myapp/

Generated CMake source:
  myapp/.vix/generated/app/

Build directory:
  myapp/build-ninja/

This helps engineers understand which layer failed.

Generated CMake path

When configure fails for a vix.app project, the relevant CMake file is:

.vix/generated/app/CMakeLists.txt

So CMake diagnostics should point there.

But source validation errors should point back to:

vix.app
src/main.cpp
include/

The diagnostic layer should not confuse generated files with user-authored files.

Why AppProjectResolver exists

A dedicated project resolver makes this logic reusable.

Both vix build and vix run need the same answer:

What project is this?
Where is the real root?
Where is the CMake source?
What target should I build?
Was this generated from vix.app?

If each command implements its own resolution logic, they can drift.

A shared resolver keeps behavior consistent.

Resolver result

A useful resolver result contains:

kind
userProjectDir
cmakeSourceDir
cmakeListsPath
appManifestPath
targetName
generated
error

For a CMake project:

kind            = CMake
userProjectDir  = project/
cmakeSourceDir  = project/
cmakeListsPath  = project/CMakeLists.txt
targetName      = project folder name
generated       = false

For a vix.app project:

kind            = vix.app
userProjectDir  = project/
cmakeSourceDir  = project/.vix/generated/app/
cmakeListsPath  = project/.vix/generated/app/CMakeLists.txt
appManifestPath = project/vix.app
targetName      = manifest.name
generated       = true

Search behavior

The resolver can start from:

current directory
a file path
a directory passed with --dir

Then it searches upward for:

CMakeLists.txt
vix.app

The first directory containing either file becomes the project root.

Inside that root, CMake has priority.

Example: current directory

Project:

hello/
  vix.app
  src/
    main.cpp

Command:

cd hello
vix build

Resolved result:

kind            = vix.app
userProjectDir  = hello/
cmakeSourceDir  = hello/.vix/generated/app/
targetName      = manifest.name

Example: nested directory

Project:

hello/
  vix.app
  src/
    features/
      auth.cpp

Command:

cd hello/src/features
vix build

The resolver walks upward and finds:

hello/vix.app

Resolved root:

hello/

Example: CMake wins

Project:

hello/
  CMakeLists.txt
  vix.app
  src/
    main.cpp

Resolved result:

kind            = CMake
userProjectDir  = hello/
cmakeSourceDir  = hello/
generated       = false

The vix.app file is ignored for project resolution.

Failure cases

Resolution can fail when neither file exists.

Example:

empty-folder/
  src/
    main.cpp

Command:

vix build

Error:

Unable to determine the project directory.
Missing CMakeLists.txt or vix.app.

The fix is to add either:

CMakeLists.txt

or:

vix.app

Manifest load failure

For vix.app, resolution includes loading the manifest.

This can fail when:

name is missing
sources are missing
type is invalid
standard is invalid
array syntax is malformed
unknown field is present

In that case, project resolution should return a structured error.

The command should display that error clearly and stop before CMake runs.

Generated CMake failure

After the manifest is loaded, Vix generates the internal CMake project.

Generation can fail when:

source files do not exist
resource paths are invalid
output paths are invalid
package syntax is invalid
target name is invalid

These are still manifest-level or generation-level errors.

They should be reported before the configure/build stage when possible.

Why this is important for native builds

Project resolution is also the foundation for future native vix.app builds.

The future build path may be:

vix.app
  -> native BuildGraph
  -> ObjectCache
  -> Scheduler
  -> Link

That path still needs the same resolved metadata:

userProjectDir
targetName
sources
include_dirs
defines
output_dir
resources

So clean project resolution is not only about generated CMake.

It is also preparation for a native build engine.

The clean architecture

A clean architecture has three layers:

Project resolution
  decides what project this is

Build planning
  decides what to configure, build, cache, and run

Execution
  runs CMake, Ninja, native tasks, or the final executable

vix.app should enter the system at the resolution layer.

It should not be patched into every command separately.

Practical rule for engineers

When changing Vix project resolution, keep this rule in mind:

CMake source directory is not always the user project directory.
Target name is not always the project folder name.

This is the core lesson from vix.app.

For normal CMake projects, those values often look the same.

For generated projects, they are different.

Conclusion

vix.app project resolution is about keeping identities separate.

A vix.app project has:

a real user project directory
a generated CMake source directory
a manifest-defined target name
a generated flag

CMake projects remain the full-control path.

vix.app projects become the simple path.

The resolver connects both models through one consistent result.

That consistency lets vix build, vix run, diagnostics, caching, and future native builds all reason about the project the same way.