Skip to content

Starlark host

giant gen runs giant.star scripts in an embedded Starlark interpreter. The host is deliberately small: a workspace handle, a few parsers, and a target() builtin. Language- and tool-specific opinion lives in Starlark on top - the std collection or your own modules - never in the host.

Starlark exists only here, inside the giant-gen binary, and only to produce YAML. The engine loads the committed giant.<infix>.yaml files and has no interpreter to evaluate anything else; a build never runs a generator. See Generating config for the workflow that follows from that (commit the output, gate drift in CI with giant gen --check).

A generator script defines generate(ws). The host evaluates the script, calls generate, and collects every target() registered while it runs (the return value is ignored). Collected targets are grouped by package and written as one giant.<infix>.yaml per package, where <infix> comes from the generate: entry:

generate:
- { script: gen-go.star, infix: go } # writes giant.go.yaml files
- { script: gen-docker.star, infix: docker } # writes giant.docker.yaml files

Emission is deterministic and byte-stable, which is what makes giant gen --check a diff gate.

FormResolves to
load("@std//go.star", ...)A module in the std collection - the workspace’s std: pin or path, a GIANT_STD directory, or an install-relative copy.
load("star/cargo.star", ...)A repo-local file, relative to the workspace root (the vendoring convention).

Loaded modules see the same globals as the entry script, and each module loads once per run.

MethodReturns
ws.glob(pattern)Workspace-relative paths matching a glob; sorted, gitignore-aware.
ws.read(path)The contents of a workspace-relative file.
ws.exec(args, cwd = None, check = True)Runs a subprocess from the workspace root (or cwd, workspace-relative). Returns struct(stdout, stderr, code); raises on nonzero exit unless check = False.
ws.rel(path)An absolute or //-rooted path, relativized against the workspace root.
ws.stem(path)A filename without its directory or extension.

ws.exec is how generators ask toolchains about the tree - go list, cargo metadata, buf ls-files - instead of reimplementing their file layouts.

FunctionParses
parse_json(s)One JSON value.
parse_json_stream(s)Concatenated JSON objects (the go list -json shape) into a list.
parse_yaml(s)One YAML document.
parse_toml(s)One TOML document.

All return plain Starlark data (dicts, lists, strings, ints, bools, None). parse_yaml(ws.read("giant.yaml")) is the idiom for reading workspace-level generator config out of the root file.

Validated against the same wire schema as hand-written giant.yaml targets; a bad call fails the generation run, never the build.

ParameterTypeMeaning
namestringRequired. Target name, unique in its package.
commandstringRequired. The shell command.
inputslistFile globs feeding the cache key. Package-relative; // anchors the workspace root.
outputslistFiles the command produces.
depslistExplicit deps as labels (inference fills the rest at link time).
envdictEnvironment variables, hashed into the cache key.
cwdstringWorking dir; defaults to the package dir.
cacheboolFalse disables caching. Default: True for build targets, False for tests.
remote_cacheboolFalse excludes from remote uploads. Default True.
networkboolNetwork access when sandboxed. Default False.
sandboxboolFalse exempts the target from --sandbox. Default True.
existsstringExternal check; exit 0 skips the command.
timeout_secsintKill the command after this long.
testboolMarks a test target. Default False.
tagslistFree-form labels for --tag filtering.
packagestringWhich package’s giant.<infix>.yaml the target lands in. Defaults to the dir of a relative cwd, else the root package.
labelstringExplicit label override; rarely needed.

After all generators run, a link pass resolves inferred dependencies (an input glob matching another target’s output) across the whole generated tree and writes them into the files.

Standard Starlark: no while, no recursion, no unbounded loops - generation always terminates. Determinism is on you only where you call out: ws.exec output is whatever the tool prints, so keep generator commands deterministic (sorted output, no timestamps) or sort what you take from them.