Skip to content

lzc-build.yml Specification

1. Overview

Build config is split into only two layers:

  1. lzc-build.yml: the default build config and also the release config.
  2. lzc-build.dev.yml: an optional dev override file that only keeps diffs relative to release.

package_override follows these rules:

  1. It only overrides the final package.yml in the output package.
  2. Matching fields are replaced at the top level; no recursive merge is performed.
  3. An empty top-level value clears that field.
  4. If lzc-build.dev.yml also defines package_override, it replaces the parent package_override as a whole.

Recommended command defaults:

  1. lzc-cli project deploy: prefers lzc-build.dev.yml, otherwise falls back to lzc-build.yml.
  2. lzc-cli project info/start/exec/cp/log/sync: follow the same rule by default.
  3. lzc-cli project release: always uses lzc-build.yml.
  4. lzc-cli project build: uses lzc-build.yml by default, unless -f is specified.
  5. Every project command prints the active Build config; use --release when you want the release config explicitly.

2. Top-level BuildConfig

2.1 Basic fields

FieldTypeDescription
buildscriptstringPath to a build script or a direct shell command
manifeststringPath to lzc-manifest.yml
contentdirstringOptional content directory. If omitted, no content.tar / content.tar.gz is generated
pkgoutstringOutput directory for the built LPK
iconstringIcon path. PNG only
package_overridemap[string]anyOptional 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[]stringOptional build-time variable list using KEY=VALUE strings
imagesmap[string]ImageBuildConfigDockerfile-based image build config for embed:<alias>
compose_overrideComposeOverrideConfigAdvanced compose override config, requires lzc-os >= v1.3.0
resource_exports[]ResourceExportConfigOptional resource export config. Requires lzcos >= v1.5.2. See Resource export ResourceExportConfig

2.2 Recommended file layout

text
.
├── lzc-build.yml
├── lzc-build.dev.yml
├── lzc-manifest.yml
└── package.yml

Guidelines:

  1. lzc-build.yml stores the default and release build config.
  2. lzc-build.dev.yml stores dev-only diffs, such as:
    • package_override.package: org.example.demo.dev
    • dev-only buildscript
    • dev-only envs
  3. For image-only release packages, contentdir can be omitted entirely.
  4. 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:

  1. envs must be an array of KEY=VALUE strings.
  2. KEY must match ^[A-Za-z_][A-Za-z0-9_]*$.
  3. Duplicate keys are not allowed.
  4. These variables are injected into the buildscript process environment.
  5. They are also available to manifest build preprocessing.
  6. They are not written into the final LPK and are not used by deploy-time manifest render.

Example:

yml
# lzc-build.dev.yml
package_override:
  package: org.example.demo.dev
envs:
  - DEV_MODE=1
  - FRONTEND_PORT=3000

4. 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:

  1. #@build if profile=dev
  2. #@build if env.DEV_MODE=1
  3. #@build else
  4. #@build end
  5. #@build include ./relative/path.yml

Evaluation rules:

  1. if starts a conditional block and remains active until the matching else or end.
  2. else is optional and only keeps the following text when the if branch does not match.
  3. end closes the current conditional block.
  4. profile=dev / profile=release matches the current build profile.
  5. env.KEY=VALUE performs an exact string comparison against build-time variables from build.yml:envs; missing keys do not match.
  6. Build preprocessing runs before packaging, so it only decides which text is copied into the final manifest.yml.
  7. Deployment-time manifest render still only evaluates .U / .S; it does not process #@build.

Constraints:

  1. include only supports plain text fragments.
  2. Included files must not contain further #@build directives.
  3. Include paths are resolved relative to the main lzc-manifest.yml.
  4. Build preprocessing decides which text exists in the final manifest.yml; deploy-time render still only resolves .U and .S.
  5. #@build is meant for dev/release text selection, not deployment-time dynamic logic.

Example:

yml
#@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 end

include example:

yml
application:
  routes:
    - /=file:///lzcapp/pkg/content/dist
#@build if profile=dev
#@build include ./manifest.dev.inject.yml
#@build end

5. 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.

FieldTypeDescription
dockerfilestringOptional Dockerfile path; mutually exclusive with dockerfile-content
dockerfile-contentstringOptional inline Dockerfile content; mutually exclusive with dockerfile
contextstringOptional build context directory
upstream-matchstringOptional upstream image prefix, default registry.lazycat.cloud

6. Advanced compose override

  1. compose_override is supported by lzc-cli >= 1.2.61.
  2. 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

FieldTypeDescription
kindstringRequired resource category name, for example skills or mcp-providers
sourcestringRequired path to the resource source directory

7.2 Expansion rules

  1. source must point to a directory.
  2. Each first-level subdirectory under source is treated as one resource-id.
  3. All contents inside each resource-id directory are packaged as-is into the LPK.
  4. The final package layout is always exports/<kind>/<resource-id>/....

Example:

yml
resource_exports:
  - kind: skills
    source: ./resources/skills
  - kind: mcp-providers
    source: ./resources/mcp-providers

If the project directory is:

text
resources/
  skills/
    summarize/
      SKILL.md
    translate/
      SKILL.md
  mcp-providers/
    filesystem/
      mcp.yml

Then the resulting LPK layout becomes:

text
exports/
  skills/
    summarize/
      SKILL.md
    translate/
      SKILL.md
  mcp-providers/
    filesystem/
      mcp.yml

7.3 Validation rules

The build process must run the following validations. Any failure should stop the build immediately with an error:

  1. kind must be a valid resource name.
  2. source must exist and must be a directory.
  3. The same kind must not be declared more than once in one lzc-build.yml.
  4. Files must not exist directly under source; all first-level entries must be directories.
  5. Every first-level subdirectory name under source must be a valid resource-id.
  6. Every first-level subdirectory must contain at least one actual payload file.
  7. A single LPK can declare at most 100 kind values.

7.4 Design notes

  1. kind represents the resource category, for example a consumer imports skills or mcp-providers through import_resources in package.yml.
  2. resource-id does not need to be declared explicitly in lzc-build.yml; it is inferred from the first-level subdirectory names under source.
  3. The final package layout remains exports/<kind>/<resource-id>/....