Projects, products, and dependencies

Chapter 4 introduced the daily project commands. This chapter explains the contracts that make a project deterministic and suitable for larger software.

Discovery

Project commands search the current directory and then its parents for the nearest tulam.project.tl. --project PATH selects a directory or manifest explicitly. All paths are canonicalized before source or dependency discovery.

Typed manifest boundary

Every manifest begins:

module Project;
import Tulam.Build.V1;
value project : Project = Project { ... };

Pure helper functions and values are allowed. No other import is permitted at bootstrap time. Evaluation is pure, deterministic, total within fixed budgets, and isolated from filesystem, network, environment, clocks, effects, intrinsics, and targets.

Product kinds

Each product explicitly lists package dependencies it may import. A transitive dependency is not automatically visible.

Profiles

A profile selects ordered target identifiers plus optimization, debug information, and floating contraction settings. llvm.native is the current provider. Profiles describe artifacts; they do not inject target conditionals into source.

Local and Git dependencies

Local dependencies point at another project. Git dependencies require a full 40- or 64-hex commit identifier; branches, tags, abbreviations, and version ranges are rejected. Dependency projects expose an unambiguous library product.

Locking and offline replay

tulam.lock is canonical JSON recording manifest and dependency identity plus content hashes. --locked verifies without rewriting. --offline forbids Git acquisition and requires matching local checkouts.

Build outputs

Executables default to:

.tulam/build/PROFILE/PRODUCT/PRODUCT

Libraries are currently checked and consumed from source. Serialized typed interfaces, standalone library artifacts, and definition-level incremental identity belong to the separate-compilation phase.

Inspection

Use project show to see normalized selection and project graph for the dependency-first reachable module graph. Project failures use stable TLC-PROJECT-* diagnostics before later compiler stages consume invalid state.

Common mistakes

Do not import application code into the manifest, name a Git branch instead of an exact revision, depend on an undeclared transitive package, or expect a library product to emit a serialized artifact in the current phase.

Recap

The typed manifest selects products, profiles, and exact dependencies inside a restricted pure boundary. Discovery, locks, and hashes make that selection reproducible.

Authoritative details: Project Design.