Graph API
build.graph() is the public access point to the build graph in build.fol.
All graph construction goes through method calls on the returned handle.
This layer is intentionally narrower than the whole build surface:
- package metadata belongs on
build.meta({...}) - direct dependencies belong on
build.add_dep({...}) - future dependency queries and output handles sit above raw graph mutation and should not collapse back into ad hoc string-only graph APIs
The canonical shape is:
pro[] build(): non = {
var build = .build();
build.meta({ name = "app", version = "0.1.0" });
var graph = build.graph();
...
}
Artifacts
graph.add_exe
Adds an executable artifact.
var app = graph.add_exe({
name = "app",
root = "src/main.fol",
fol_model = "memo", // spell this explicitly for each artifact
target = target, // optional
optimize = optimize, // optional
});
Returns an Artifact handle.
Required fields: name, root.
Optional fields: fol_model, target, optimize.
root is the path to the entry-point .fol source file relative to the
package root.
fol_model selects the runtime capability tier for the artifact:
coreno heap, no OS/runtime servicesmemoheap-backed facilities, still no OS/runtime servicesstdhosted/runtime services on top ofmemo
The recommended style is to spell fol_model explicitly on every artifact so
the capability contract is visible in build.fol.
The important boundary is semantic and runtime-facing:
coreartifacts must not use heap-backedstr,vec,seq,set, ormapcoreartifacts may still use arrays, records, routines, control flow, anddefermemoartifacts may use heap-backed runtime types but not hosted services- bundled
stdwrappers require an explicit internalstandarddependency - hosted
run/testare not tied to bundled std presence
Current implementation note:
corealready means “no heap and no OS/runtime services” at the language and runtime-contract levelcoreartifacts are still emitted through the current Rust backend pipeline- that means
coreis ready for semantic/runtime restriction work now, but it should not yet be read as “finished embedded backend support”
Mixed-model example:
pro[] build(): non = {
var build = .build();
build.meta({ name = "workspace_tools", version = "0.1.0" });
var graph = build.graph();
var corelib = graph.add_static_lib({
name = "corelib",
root = "core/lib.fol",
fol_model = "core",
});
var memolib = graph.add_static_lib({
name = "memolib",
root = "memo/lib.fol",
fol_model = "memo",
});
var tool = graph.add_exe({
name = "tool",
root = "app/main.fol",
fol_model = "memo",
});
graph.install(tool);
graph.add_run(tool);
};
graph.add_static_lib
Adds a static library artifact.
var core = graph.add_static_lib({ name = "core", root = "src/core/lib.fol" });
Returns an Artifact handle.
Library and test artifact config records follow the same optional fields:
fol_modeltargetoptimize
graph.add_shared_lib
Adds a shared (dynamic) library artifact.
var sdk = graph.add_shared_lib({ name = "sdk", root = "src/sdk/lib.fol" });
Returns an Artifact handle.
graph.add_test
Adds a test artifact.
var tests = graph.add_test({ name = "tests", root = "src/tests.fol" });
Returns an Artifact handle.
graph.add_module
Adds a standalone module that can be imported by other artifacts.
var utils = graph.add_module({ name = "utils", root = "src/utils.fol" });
Returns a Module handle.
Installation and Runs
graph.install
Marks an artifact for installation.
graph.install(app);
Returns an Install handle.
Install projections use the selected install prefix. Artifact installs resolve under the prefix by kind:
- executables under
bin/ - libraries under
lib/
graph.install_file
Installs either a source-file handle or a generated output handle.
var defaults = graph.file_from_root("config/defaults.toml");
graph.install_file({ name = "defaults", source = defaults });
var cfg = graph.write_file({
name = "cfg",
path = "config/generated.toml",
contents = "ok",
});
graph.install_file({ name = "generated-cfg", source = cfg });
Returns an Install handle.
graph.install_dir
Installs a source directory handle.
var assets = graph.dir_from_root("assets");
graph.install_dir({ name = "assets", source = assets });
Returns an Install handle.
The install prefix is selected by frontend/workspace configuration, not by the
package itself. Changing the prefix should move projected install destinations
without changing build.fol.
graph.add_run
Registers an artifact as a run target. Binds the default run step when only
one executable exists and no explicit run step has been registered.
var run = graph.add_run(app);
Returns a Run handle. See Handle API for Run methods.
Steps
graph.step
Creates a named custom step.
var docs = graph.step("docs");
var docs = graph.step("docs", "Generate documentation");
Returns a Step handle. See Handle API for Step methods.
Named steps are selectable on the command line:
fol code build docs
fol code build --step docs
When a description is present, frontend step planning and unknown-step diagnostics surface it as part of the available step catalog.
Native System Libraries
graph.add_system_lib
Declares a typed system-library request that can be linked into an artifact.
var ssl = graph.add_system_lib({
name = "ssl",
mode = "dynamic",
search_path = "/usr/lib",
});
app.link(ssl);
Supported config fields:
namerequired library or framework namemodeoptional, defaults todynamic, also acceptsstaticframeworkoptional bool, defaults tofalsesearch_pathoptional system library search root
Current scope is intentionally narrow:
- library names are typed, not raw linker fragments
- frameworks are expressed through
framework = true - frameworks must use
dynamic - the build graph records native link intent without exposing a linker-script DSL
Dependency Config Notes
Forwarded dependency args are already best suited for stable build config:
targetoptimize- named user options
The current build story intentionally does not treat dependency config as a general environment-selection surface. Keep forwarded dependency args explicit and typed rather than mixing them with ad hoc environment shaping.
Generated Directories
graph.add_system_tool_dir
Declares a typed system-tool step that produces a directory handle.
var assets = graph.add_system_tool_dir({
tool = "assetpack",
output_dir = "gen/assets",
});
graph.install_dir({ name = "assets", source = assets });
graph.add_codegen_dir
Declares a codegen step that produces a directory handle.
var docs = graph.add_codegen_dir({
kind = "asset",
input = "assets/raw",
output_dir = "gen/packed",
});
Generated directory handles are valid in directory-oriented consumers:
graph.install_dirbuild.export_dir
Current Execution Semantics
Step execution is still serial today. The build graph keeps deterministic step ordering and explicit dependency edges, but it does not claim parallel execution yet.
Current reporting distinguishes:
- requested
- executed
- skipped-from-cache
- skipped-by-foreign-run-policy
- produced outputs
That reporting is intended for frontend summaries and tests. Produced outputs now participate in step cache-key semantics, so generated-file changes can invalidate dependent steps predictably.
Options
graph.standard_target
Reads the -Dtarget option. Returns a Target handle.
var target = graph.standard_target();
The value is provided at build time via -Dtarget=x86_64-linux-gnu. If no
value is provided, target resolves to the host target.
An optional config record is accepted:
var target = graph.standard_target({ default = "x86_64-linux-gnu" });
graph.standard_optimize
Reads the -Doptimize option. Returns an Optimize handle.
var optimize = graph.standard_optimize();
The value is provided via -Doptimize=release-fast. Defaults to debug if
not set.
Valid values: debug, release-safe, release-fast, release-small.
graph.option
Declares a named user option readable via -D.
var root_opt = graph.option({
name = "root",
kind = "path",
default = "src/main.fol",
});
Returns a UserOption handle.
Required fields: name, kind.
Optional field: default.
Option kinds:
| Kind | Description | CLI Example |
|---|---|---|
bool | Boolean flag | -Dstrip=true |
int | Integer value | -Djobs=4 |
str | Arbitrary string | -Dprefix=/usr/local |
enum | One of a fixed set of strings | -Dbackend=llvm |
path | File or directory path | -Droot=src/main.fol |
target | Target triple | -Dtarget=x86_64-linux-gnu |
optimize | Optimization mode | -Doptimize=release-fast |
Generated Files
graph.write_file
Declares a file to be written with static contents at build time.
var header = graph.write_file({
name = "version.h",
path = "gen/version.h",
contents = "#define VERSION 1\n",
});
Returns a GeneratedFile handle.
graph.copy_file
Declares a file to be copied from a source-file handle.
var template = graph.file_from_root("config/template.toml");
var cfg = graph.copy_file({
name = "config",
source = template,
dest = "gen/config.toml",
});
Returns a GeneratedFile handle.
graph.add_system_tool
Declares a system tool invocation that produces a file.
var packed = graph.add_system_tool({
tool = "flatc",
args = { "--fol" },
file_args = { schema, defaults },
env = { MODE = "strict" },
output = "gen/schema.fol",
});
Returns a GeneratedFile handle.
The generated file is keyed by the output path. Use this handle with
step.attach(...) or artifact.add_generated(...).
Typed fields:
toolrequired tool nameargsoptional string argumentsfile_argsoptional source-file or generated-output handles passed as file argumentsenvoptional string-to-string environment mapoutputrequired generated output path
graph.add_codegen
Declares a FOL codegen step.
var schema = graph.add_codegen({
kind = "schema",
input = "schema/api.yaml",
output = "gen/api.fol",
});
Returns a GeneratedFile handle.
Codegen kinds: fol-to-fol, schema, asset-preprocess.
Path Utilities
graph.file_from_root
Returns a source-file handle rooted under the package root.
var cfg = graph.file_from_root("config/default.toml");
Useful when passing source files into copy_file, install_file, or
run.add_file_arg.
graph.dir_from_root
Returns a source-dir handle rooted under the package root.
var assets = graph.dir_from_root("assets");
graph.build_root
Returns the package root directory as an absolute path string.
var root = graph.build_root();
graph.install_prefix
Returns the installation prefix. Defaults to the workspace install directory.
var prefix = graph.install_prefix();
Dependencies
Direct dependencies are declared on build.add_dep({...}), not on graph.
See Handle API for querying modules, artifacts, steps,
and generated outputs from a Dependency handle.