Skip to content

Step Context

Leonard Ramminger edited this page Aug 9, 2026 · 2 revisions

Step Context

Lua step callbacks receive one argument: the step context table, conventionally named ctx.

step({
    name = "lint",
    phase = "qa",
    scope = "default",
    run = function(ctx)
        return 0
    end,
})

Only available inside Lua run callbacks. Shell steps do not get ctx.

Properties

Member Type Description
project_root string Absolute path to project root

ctx.get_config()

Returns the merged step config table, or nil if none.

local config = ctx.get_config()
local patterns = config.patterns

See Configure Step.

ctx.glob(patterns)

Expand glob patterns relative to project_root.

local files = ctx.glob({ "src/**/*.cpp", "include/**/*.hpp" })
Argument Type Description
patterns string array Glob patterns (same syntax as step input/output)

Returns a 1-based Lua array of relative file paths (sorted). Empty if nothing matches.

Uses the glob metadata cache when enabled in performance settings.

Workers

Run shell commands in parallel from a Lua callback. Use colon syntax (:) for these methods.

ctx:spawn(spec)

Start a background worker.

local job = ctx:spawn({
    name = "lint-file",
    cmd = "clang-tidy " .. file,
    inputs = { file },
    outputs = { file .. ".linted" },
})
Field Required Type Description
name yes string Worker label (logs)
cmd yes string or string array Shell command(s) run sequentially in the worker
inputs no string array Input paths for worker cache key
outputs no string array Output paths for worker cache key

Returns a worker handle (integer id).

ctx:wait(handle)

Wait for one worker. Returns shell exit code.

local code = ctx:wait(job)
if code ~= 0 then
    return code
end

On success, records worker duration for cache_file_success().

ctx:wait_all(handles)

Wait for multiple workers. Returns 0 if all succeeded, otherwise the first non-zero exit code.

local jobs = {}
for _, file in ipairs(files) do
    jobs[#jobs + 1] = ctx:spawn({ name = file, cmd = "lint " .. file })
end
return ctx:wait_all(jobs)
Argument Behavior
Table of handles Wait for those workers
nil or empty table Drain all pending workers in the pool

Workers require the worker pool (available during Lua step execution). If unavailable, spawn throws worker pool is not available in this step context.

Success cache API

Per-file or per-key incremental cache inside a Lua callback. Stored under .cache/success/. Disabled when --no-cache or cache.enabled = false.

ctx.file_success_cached(path)

Returns true if relative file path path was previously cached as successful.

if ctx.file_success_cached(source_path) then
    skipped = skipped + 1
else
    -- run tool on source_path
end

ctx.cache_file_success(path)

Mark path as successfully processed. Uses pending worker duration from the last ctx:wait() when applicable.

ctx.cache_file_success(source_path)

ctx.success_cached(key)

Generic string key success check (not file-based).

ctx.cache_success(key)

Mark generic key as successful.

ctx.record_file_cache_miss(path)

Record that path failed, so the next run re-checks it even if other files are cached.

ctx.record_cache_miss(key)

Record generic key miss.

ctx.get_cache_misses()

Returns a 1-based array of paths/keys that failed in the previous run (for incremental re-check).

local misses = ctx.get_cache_misses()
for _, entry in ipairs(misses) do
    print("re-checking: " .. entry)
end

Bump a revision field in configure_step() when the tool or rules change without source file changes.

Method syntax

Call style Functions
Dot (ctx.glob) glob, get_config, success cache helpers
Colon (ctx:spawn) spawn, wait, wait_all

Example: parallel workers

run = function(ctx)
    local files = ctx.glob({ "src/**/*.cpp" })
    local jobs = {}
    for _, file in ipairs(files) do
        jobs[#jobs + 1] = ctx:spawn({
            name = "compile-" .. file,
            cmd = "g++ -c " .. file,
            inputs = { file },
            outputs = { file .. ".o" },
        })
    end
    return ctx:wait_all(jobs)
end

Next steps

Clone this wiki locally