Skip to main content

Stage 0: workspace quality gate

Stage 0 runs a repository's checks locally before changes reach CI. The example below wraps dependency installation, toolchain setup, and quality checks in a Loom workflow. Recorded runs produce receipts and manifests that point to the job or script output to inspect.

loom run --local --workflow .loom/workflow.yml

This example shows the Stage 0 pattern using Loom repository tasks. For the maintained repository workflow, see .loom/workflow.yml.

Prerequisites

RequirementWhy
Loom installedRuns the workflow via loom run --local. See CLI → run.
Docker availableThe workflow builds and runs Docker images. The Docker daemon must be reachable.
Linux targetLocal execution targets linux in the current release. On macOS or Windows, run inside a Linux environment (VM, container, or CI runner).

The workflow

This illustrative workflow requires the Loom repository's Nix Dockerfile, task definitions, and a configured KeePass reference for the service check. Adapt those inputs for your repository:

version: v1

stages:
- deps
- ci

default:
cache:
- name: pnpm
key:
prefix: loom-cache
files:
- pnpm-lock.yaml
paths:
- .pnpm-store
policy: pull-push
when: always
- name: go
key:
prefix: loom-cache
files:
- go.work
- go.work.sum
- apps/**/go.sum
- libs/**/go.sum
paths:
- .go
policy: pull-push
when: always
variables:
PNPM_STORE_DIR: .pnpm-store
GOPATH: /workspace/.go
GOCACHE: /workspace/.go/cache
GOMODCACHE: /workspace/.go/pkg/mod
target: linux

build-nix-image:
stage: deps
target: linux
image:
name: loom:nix-local
build:
context: .
dockerfile: nix/Dockerfile
cache: []
script:
- echo "built by loom"

test-services:
stage: deps
target: linux
cache: []
image: postgres:16
secrets:
POSTGRES_PASSWORD:
ref: keepass://beepbeepgo/loom-platform/loom#services/test/db:password
file: false
services:
- name: postgres:16
variables:
POSTGRES_DB: testdb
POSTGRES_USER: runner
POSTGRES_HOST_AUTH_METHOD: trust
script:
- >-
i=0; until pg_isready -h postgres -U runner -d testdb;
do i=$((i+1)); [ "$i" -ge 30 ] && echo "postgres not ready after 30s" && exit 1; sleep 1; done
- psql -h postgres -U runner -d testdb -c "SELECT 1;"

install-deps:
stage: ci
image: loom:nix-local
variables:
PNPM_STORE_DIR: .pnpm-store
script:
- pnpm i --frozen-lockfile
- pnpm nx run-many -t go-deps-verify

check-task:
stage: ci
image: loom:nix-local
needs:
- install-deps
variables:
PNPM_STORE_DIR: .pnpm-store
cache:
- name: pnpm
policy: pull
- name: go
policy: pull
script:
- pnpm i --frozen-lockfile
- task check

check-pnpm:
stage: ci
image: loom:nix-local
needs:
- install-deps
variables:
PNPM_STORE_DIR: .pnpm-store
cache:
- name: pnpm
policy: pull
- name: go
policy: pull
script:
- pnpm i --frozen-lockfile
- pnpm nx run loom-platform:check

What each job does

Stage: deps

JobPurpose
build-nix-imageBuilds the loom:nix-local Docker image containing the repository's Nix-defined toolchain. Uses the image.build mapping form to build the image before execution. Disables cache (cache: []) since image builds don't benefit from workspace caching.
test-servicesValidates sidecar service infrastructure by running a Postgres health check. Uses services to start a Postgres container alongside the job, and secrets to resolve the database password from a KeePass vault at runtime.

Stage: ci

JobPurpose
install-depsInstalls pnpm dependencies and verifies Go module checksums. Runs in the Nix toolchain image. Populates the shared cache that downstream jobs pull from.
check-taskRuns task check (the Taskfile quality gate). Depends on install-deps via needs. Pulls cache in read-only mode (policy: pull) to avoid redundant saves.
check-pnpmRuns the Nx check target for the workspace. Same dependency and cache strategy as check-task.

Features demonstrated

This workflow uses most of Loom's v1 feature set:

FeatureHow it's usedLearn more
Stagesdeps runs first, then ciSyntax → stages
Default configurationdefault sets shared cache, variables, and target for all jobsSyntax → default
Named multi-cacheTwo caches (pnpm, go) with independent keys and pathsCache
Cache policyinstall-deps uses pull-push; check jobs use pull onlySyntax → cache:policy
Glob patterns in cache keysapps/**/go.sum and libs/**/go.sum match Go modules anywhere in the treeSyntax → cache:key:files
Image buildbuild-nix-image uses the image.build mapping to build before runningDocker provider
Servicestest-services runs Postgres as a sidecar containerSyntax → services
Secretstest-services resolves a password from KeePass at runtimeSecrets
DAG dependenciescheck-task and check-pnpm use needs to depend on install-depsSyntax → needs
Explicit variable valuesGo cache paths use literal /workspace/.go paths; YAML values do not expand $GOPATHVariables
Provider routingAll jobs set image and use Docker; build-nix-image also builds its imageProviders

Caching strategy

The workflow restores paths that the dependency and build tools can reuse:

CacheKey derived fromPaths cachedStrategy
pnpmpnpm-lock.yaml.pnpm-storeDependency changes invalidate. install-deps populates; check jobs pull only.
gogo.work, go.work.sum, **/go.sum.goGo module changes invalidate. Same populate/pull pattern.

The check-task and check-pnpm jobs use policy: pull to avoid saving the caches populated by install-deps. Loom still invokes their script commands after restoring cached paths.

If you change inputs that should invalidate the cache (install flags, toolchain versions, additional build outputs), update cache.key.files accordingly.

Adapting this pattern

Keep the workflow in version control and use it to call your repository's existing checks. Declare the tools, services, variables, and cached paths those checks need. The snapshot and container image reduce some local dependencies; matching CI results also requires matching source and external inputs.

Diagnosing failures

For a recorded failure, follow the receipt's logs_dir, then inspect:

  1. Pipeline summary — check pipeline/summary.json for overall status and exit code.
  2. Pipeline manifest — check pipeline/manifest.json to identify which job failed.
  3. Job manifest — check jobs/<job_id>/manifest.json for the failing step or system section.
  4. Failing events — open the events.jsonl file pointed to by the manifest for the specific failure details.

The paths above are relative to .loom/.runtime/logs/<run_id>/. If setup fails before a receipt is written, use the CLI error on stderr.

For the full triage process, see:

Running the gate

Validate the workflow structure:

loom check

Run the full Stage 0 pipeline:

loom run --local --workflow .loom/workflow.yml

Planned

  • Remote runners — run the same workflow on remote infrastructure without bespoke wrappers.
  • Richer structured events — more granular step-level and system-section events for deeper diagnostics.

Next steps