Skip to content

Recommended Gate Resources

LumenFlow’s gates layer accepts a vendor-agnostic resource registry under software_delivery.gates.resources. The registry has two opt-in sub-fields:

  • env — environment variables to inject into every gate subprocess (caller env wins on collision).
  • runners — flag-injection rules keyed by runner name. Each rule says: “if the gate command contains match as a substring AND does not already specify flag, splice <flag>=<value> into the command before any shell operator (|, >, &&, …).”

The runtime mechanism is opt-in — gate execution passes the configured command through without choosing a runner. During lumenflow init and lumenflow:upgrade, LumenFlow can project a safe scoped default when the project already provides explicit runner evidence. This page also lists snippets you can adjust for repository-specific needs.

Choose the command your project already uses and wire that command into software_delivery.gates.commands. Runtime gates store and execute that consumer command verbatim. Initialisation and upgrade may infer Vitest, Jest, Nx, or Turbo only from package.json, a runner configuration file, or an explicit changed-test script; a language preset alone is never treated as runner evidence.

software_delivery:
  test_runner: vitest
  gates:
    commands:
      test_full: 'pnpm vitest run'
      test_incremental: 'pnpm exec vitest run --changed origin/main --passWithNoTests'
    resources:
      runners:
        vitest-workers:
          match: 'vitest'
          flag: '--maxWorkers'
          value: 1

Use resources.runners when your CI or local machines need bounded workers. If the command already includes --maxWorkers, LumenFlow leaves that explicit choice untouched. CLI flags in gates.commands take precedence over the resource rule, so LumenFlow emits a non-blocking warning naming the command and flag when it detects that override.

gates.commands is the source of truth for a particular gate invocation. A flag hardcoded in a command, such as --maxWorkers=4, overrides the matching resources.runners value, such as --maxWorkers=1. LumenFlow preserves the command and continues execution; the warning is advisory and emitted once per process for each distinct command/flag combination.

The same advisory also covers common worker, reporter, and timeout flags even when no resource injection rule exists. This helps surface command-level settings that may be taking precedence over a runner configuration file.

To centralize a setting, remove the flag from gates.commands and add the corresponding resources.runners rule. Keep the command flag when a specific gate intentionally needs different behavior; its explicit CLI value wins.

software_delivery:
  test_runner: jest
  gates:
    commands:
      test_full: 'pnpm jest --runInBand'
      test_incremental: 'pnpm exec jest --changedSince origin/main --passWithNoTests'
    resources:
      runners:
        jest-workers:
          match: 'jest'
          flag: '--maxWorkers'
          value: 2

For Jest, keep the command semantics in your package scripts or gate command. LumenFlow only injects a configured resource flag when the command token matches match and the flag is absent.

software_delivery:
  test_runner: mocha
  gates:
    commands:
      test_full: 'pnpm mocha "test/**/*.spec.js"'
    resources:
      runners:
        mocha-timeout:
          match: 'mocha'
          flag: '--timeout'
          value: 30000

Mocha does not define a universal changed-test mode. Leave test_incremental unset unless your repository has a package script that maps changed files to Mocha arguments. An unset or full-equivalent incremental command safely falls back to test_full.

software_delivery:
  test_runner: 'bun:test'
  gates:
    commands:
      test_full: 'bun test'
    resources:
      runners:
        bun-timeout:
          match: 'bun'
          flag: '--timeout'
          value: 30000

test_runner is a label for your workspace. It can name bun:test while the resource rule matches the actual binary token in the shell command. Add test_incremental only when the project owns a genuinely scoped Bun command.

software_delivery:
  test_runner: uvu
  gates:
    commands:
      test_full: 'pnpm uvu tests'

For small runners such as uvu, keep the full gate command close to the command you would run by hand. Add a changed-test script only when the project can map changed code to the correct test files.

LumenFlow chooses a generated test_incremental command in this order:

  1. A project-owned test:changed, test:incremental, or test:affected package script.
  2. File-level impact analysis from evidenced Vitest or Jest tooling.
  3. Nx affected projects.
  4. Turbo affected packages as a last resort.

The generated command uses the configured integration remote and branch instead of assuming origin/main. Turbo is intentionally last: --affected works at package level, so a change to a shared core package can select most reverse dependants. Vitest or Jest changed-test analysis is usually more precise for repositories that expose those runners directly.

For unsupported ecosystems, init leaves test_incremental empty and gates fall back to test_full. Upgrade repairs only a missing/blank value or a legacy value equal to test_full, and only when a full fallback is already configured; it preserves custom commands and YAML comments.

software_delivery:
  gates:
    commands:
      # Configure the runner that owns incremental tests for your repo.
      test_incremental: 'pnpm exec vitest run --changed origin/main --passWithNoTests'
    resources:
      env:
        # Uncomment to cap Turbo concurrency on memory-constrained machines:
        # TURBO_CONCURRENCY: 1
      runners:
        vitest-workers:
          match: 'vitest'
          flag: '--maxWorkers'
          value: 1
        vitest-teardown:
          match: 'vitest'
          flag: '--teardownTimeout'
          value: 30000
        playwright-workers:
          match: 'playwright'
          flag: '--workers'
          value: 1
        # Add other runners (jest, mocha, custom shell scripts) as needed.

Each rule is conditional:

  • A rule only fires when the resolved gate command contains its match substring. So a vitest-workers rule is a no-op when the active command invokes a non-Vitest runner.
  • A rule never overwrites a flag the user has already specified. If your test_incremental reads vitest --changed --maxWorkers=4, the vitest-workers rule sees --maxWorkers is already present and leaves the command alone. The command-level value takes precedence and produces a non-blocking advisory. Same for the paired --flag value form.
  • Flag injection is spliced before the first shell operator, so chained redirection / pipelines remain attached to the correct process.

Prior to v5.8 LumenFlow auto-injected --maxWorkers=1 and --teardownTimeout=30000 whenever it detected a vitest --changed command. That coupling lived in the software-delivery pack’s buildVitestChangedArgs helper and the augmentVitestIncrementalCommand follow-up (which fixed a bug where the original helper overwrote user-supplied flags).

A later release removed both helpers from runtime gate execution as part of LumenFlow’s vendor-neutral execution boundary. Hardening defaults still live in consumer config and remain opt-in. Init and upgrade runner detection is a separate configuration-projection step and does not rewrite commands at run time.

If your project relied on the implicit Vitest hardening before v5.8:

  1. Paste the snippet above into your workspace.yaml.
  2. Run pnpm gates and confirm that the incremental test command logs the expected --maxWorkers=1 --teardownTimeout=30000 suffix (or your repo-specific overrides if you set them explicitly).
  3. No change is required to your gates.commands.test_incremental value itself — the resources mechanism augments it at run() time.

If you do not configure test_incremental, or it is equal to test_full, LumenFlow falls back to the configured full command. Runtime execution never invents a runner-specific command.

The resources block is validated by GateResourcesSchema in @hellmai/lumenflow-packs-software-delivery/config/lumenflow-config-schema. Each runner entry has shape:

<runner-name>:
  match: '<substring to look for in the gate command>'
  flag: '<long flag to inject, e.g. --maxWorkers>'
  value: <number-or-string injected as flag=value>

Invalid blocks log a warning and are ignored; they do not break gate execution.

  • The release that introduced applyGateResources and the schema.
  • The original “preserve configured flags” bug fix that this page supersedes.
  • The change that deleted the runner-specific hardening helpers and routed hardening through this page’s snippet.