Skip to content

Designing Phases and Scopes

Leonard Ramminger edited this page Aug 9, 2026 · 1 revision

Designing Phases and Scopes

Beez does not prescribe a schema. This page suggests practical ways to name and structure phase+scope pairs.

Start simple

For a small project, one scope is enough:

step({ name = "configure", phase = "build", scope = "default", ... })
step({ name = "compile",   phase = "build", scope = "default", ... })
step({ name = "test",      phase = "test",  scope = "default", ... })

workflow("all", {
    { phase = "build", scope = "default" },
    { phase = "test",  scope = "default" },
})

Add scopes when you need to run subsets independently.

When to add a new phase

Use a new phase for a distinct pipeline stage you might invoke alone:

Phase (examples) Typical steps
configure CMake, Conan install
build Compile, link
test Unit, integration tests
qa Lint, format-check
package Archive, install
clean Remove artifacts

Phases map well to workflow order:

workflow("ci", {
    { phase = "build", scope = "default" },
    { phase = "test",  scope = "default" },
    { phase = "qa",    scope = "default" },
})

When to add a new scope

Use a new scope for a variant of the same phase that should not mix steps with other variants:

Situation Example scopes under build
Release vs debug release, debug
Host vs cross-compile native, arm
Fast vs full checks smoke, full

Each variant often has its own configure step in the same or a configure phase:

step({ name = "configure:debug",   phase = "configure", scope = "debug",   ... })
step({ name = "build:debug",     phase = "build",     scope = "debug",   ... })
step({ name = "configure:release", phase = "configure", scope = "release", ... })
step({ name = "build:release",   phase = "build",     scope = "release", ... })
beez -p build:debug
beez -p build:release

Naming conventions

Pick one style and stay consistent:

Style Step name Phase Scope
Colon in step name build:compile build default
Plain step name compile build default
Phase in step name configure:setup configure code

order() always uses step name:

order("configure:setup", "build:compile")

Phase and scope strings in workflows do not need to match step name prefixes.

Patterns that work well

Isolated toolchains per scope

Each scope owns a full configure/build/test chain. Workflows pick one scope:

workflow("sanitize", {
    { phase = "configure", scope = "sanitize" },
    { phase = "build",     scope = "sanitize" },
    { phase = "test",      scope = "sanitize" },
})

Same phase, parallel scopes in workflow

Generate docs and code at the same time:

workflow("ci", {
    { parallel = {
        { phase = "generate", scope = "docs" },
        { phase = "generate", scope = "code" },
    }},
    { phase = "compile", scope = "code" },
})

QA as its own phase

Keep lint/format under qa so beez -p qa:default runs checks without building:

workflow("quality", {
    { phase = "qa", scope = "default" },
})

Anti-patterns

Using scope as a file path

-- Misleading: scope does not limit files
step({ name = "lint", phase = "qa", scope = "src/lib", mutate = { "src/**" }, ... })

Use input/mutate for files. Use scope for selection (for example default vs strict).

One giant phase

Putting configure, build, test, and deploy all under phase = "all" with only order() works but removes the benefit of -p and readable workflows. Prefer separate phases unless the pipeline is tiny.

Duplicate step names across scopes

step({ name = "compile", phase = "build", scope = "debug", ... })
step({ name = "compile", phase = "build", scope = "release", ... })  -- replaces first

The second registration wins globally. Use unique names: compile:debug, compile:release.

Expecting -p phase:s1,s2 to parallelize

Comma-separated scopes run sequentially. Use workflow parallel for concurrent phase+scope pairs.

Checklist before adding a scope

  • Can I run this subset with beez -p phase:newscope?
  • Do steps in this scope need separate configure from other scopes?
  • Are step names unique across the whole build.lua?
  • Does a workflow (or documented -p command) expose this scope to users?

Next steps

Clone this wiki locally