lzc-build.yml Specification
1. Overview
Build config is split into only two layers:
lzc-build.yml: the default build config and also the release config.lzc-build.dev.yml: an optional dev override file that only keeps diffs relative to release.
package_override follows these rules:
- It only overrides the final
package.ymlin the output package. - Matching fields are replaced at the top level; no recursive merge is performed.
- An empty top-level value clears that field.
- If
lzc-build.dev.ymlalso definespackage_override, it replaces the parentpackage_overrideas a whole.
Recommended command defaults:
lzc-cli project deploy: preferslzc-build.dev.yml, otherwise falls back tolzc-build.yml.lzc-cli project info/start/exec/cp/log/sync: follow the same rule by default.lzc-cli project release: always useslzc-build.yml.lzc-cli project build: useslzc-build.ymlby default, unless-fis specified.- Every
projectcommand prints the activeBuild config; use--releasewhen you want the release config explicitly.
2. Top-level BuildConfig
2.1 Basic fields
| Field | Type | Description |
|---|---|---|
buildscript | string | Path to a build script or a direct shell command |
manifest | string | Path to lzc-manifest.yml |
contentdir | string | Optional content directory. If omitted, no content.tar / content.tar.gz is generated |
pkgout | string | Output directory for the built LPK |
icon | string | Icon path. PNG only |
package_override | map[string]any | Optional top-level override for the final package.yml; no recursive merge; an empty top-level value clears that field; package_override.package affects the final LPK file name and package-name validation |
envs | []string | Optional build-time variable list using KEY=VALUE strings |
images | map[string]ImageBuildConfig | Dockerfile-based image build config for embed:<alias> |
compose_override | ComposeOverrideConfig | Advanced compose override config, requires lzc-os >= v1.3.0 |
resource_exports | []ResourceExportConfig | Optional resource export config. Requires lzcos >= v1.5.2. See Resource export ResourceExportConfig |
2.2 Recommended file layout
.
├── lzc-build.yml
├── lzc-build.dev.yml
├── lzc-manifest.yml
└── package.ymlGuidelines:
lzc-build.ymlstores the default and release build config.lzc-build.dev.ymlstores dev-only diffs, such as:package_override.package: org.example.demo.dev- dev-only
buildscript - dev-only
envs
- For image-only release packages,
contentdircan be omitted entirely. - Do not copy the full config into
lzc-build.dev.yml; keep only the diff.
3. Build-time variables envs
envs is a build-time variable list only.
Behavior:
envsmust be an array ofKEY=VALUEstrings.KEYmust match^[A-Za-z_][A-Za-z0-9_]*$.- Duplicate keys are not allowed.
- These variables are injected into the
buildscriptprocess environment. - They are also available to manifest build preprocessing.
- They are not written into the final LPK and are not used by deploy-time manifest render.
Example:
# lzc-build.dev.yml
package_override:
package: org.example.demo.dev
envs:
- DEV_MODE=1
- FRONTEND_PORT=30004. Manifest build preprocessing
Before packaging, lzc-manifest.yml is passed through a lightweight build preprocessor.
Directives must be written in YAML comments using the fixed form #@build <directive>.
The current directives are intentionally minimal:
#@build if profile=dev#@build if env.DEV_MODE=1#@build else#@build end#@build include ./relative/path.yml
Evaluation rules:
ifstarts a conditional block and remains active until the matchingelseorend.elseis optional and only keeps the following text when theifbranch does not match.endcloses the current conditional block.profile=dev/profile=releasematches the current build profile.env.KEY=VALUEperforms an exact string comparison against build-time variables frombuild.yml:envs; missing keys do not match.- Build preprocessing runs before packaging, so it only decides which text is copied into the final
manifest.yml. - Deployment-time manifest render still only evaluates
.U/.S; it does not process#@build.
Constraints:
includeonly supports plain text fragments.- Included files must not contain further
#@builddirectives. - Include paths are resolved relative to the main
lzc-manifest.yml. - Build preprocessing decides which text exists in the final
manifest.yml; deploy-time render still only resolves.Uand.S. #@buildis meant for dev/release text selection, not deployment-time dynamic logic.
Example:
#@build if env.DEV_MODE=1
application:
injects:
- id: frontend-dev-proxy
on: request
when:
- "/*"
do:
- src: |
if (ctx.dev.id) {
ctx.proxy.to("http://127.0.0.1:3000", {
via: ctx.net.via.client(ctx.dev.id),
use_target_host: true,
});
}
#@build else
application:
routes:
- /=file:///lzcapp/pkg/content/dist
#@build endinclude example:
application:
routes:
- /=file:///lzcapp/pkg/content/dist
#@build if profile=dev
#@build include ./manifest.dev.inject.yml
#@build end5. Image build ImageBuildConfig
images builds Docker images during packaging and generates the images/ and images.lock layout required by LPK v2.
The key of images is the alias referenced by embed:<alias> in lzc-manifest.yml.
| Field | Type | Description |
|---|---|---|
dockerfile | string | Optional Dockerfile path; mutually exclusive with dockerfile-content |
dockerfile-content | string | Optional inline Dockerfile content; mutually exclusive with dockerfile |
context | string | Optional build context directory |
upstream-match | string | Optional upstream image prefix, default registry.lazycat.cloud |
6. Advanced compose override
compose_overrideis supported bylzc-cli >= 1.2.61.- It is intended for runtime permissions or compose fields that are not yet covered by the current LPK spec.
See compose override.
7. Resource export ResourceExportConfig
resource_exports declares resource categories that should be exported during build. The config contains kind and the local source directory. lzc-cli expands the source directory into the standard LPK layout exports/<kind>/<resource-id>/... during build.
This feature requires lzcos >= v1.5.2.
7.1 Fields
| Field | Type | Description |
|---|---|---|
kind | string | Required resource category name, for example skills or mcp-providers |
source | string | Required path to the resource source directory |
7.2 Expansion rules
sourcemust point to a directory.- Each first-level subdirectory under
sourceis treated as oneresource-id. - All contents inside each
resource-iddirectory are packaged as-is into the LPK. - The final package layout is always
exports/<kind>/<resource-id>/....
Example:
resource_exports:
- kind: skills
source: ./resources/skills
- kind: mcp-providers
source: ./resources/mcp-providersIf the project directory is:
resources/
skills/
summarize/
SKILL.md
translate/
SKILL.md
mcp-providers/
filesystem/
mcp.ymlThen the resulting LPK layout becomes:
exports/
skills/
summarize/
SKILL.md
translate/
SKILL.md
mcp-providers/
filesystem/
mcp.yml7.3 Validation rules
The build process must run the following validations. Any failure should stop the build immediately with an error:
kindmust be a valid resource name.sourcemust exist and must be a directory.- The same
kindmust not be declared more than once in onelzc-build.yml. - Files must not exist directly under
source; all first-level entries must be directories. - Every first-level subdirectory name under
sourcemust be a validresource-id. - Every first-level subdirectory must contain at least one actual payload file.
- A single LPK can declare at most 100
kindvalues.
7.4 Design notes
kindrepresents the resource category, for example a consumer importsskillsormcp-providersthroughimport_resourcesinpackage.yml.resource-iddoes not need to be declared explicitly inlzc-build.yml; it is inferred from the first-level subdirectory names undersource.- The final package layout remains
exports/<kind>/<resource-id>/....