Skip to content

CI providers

llms.txt lists every page for a coding agent.

The component pipeline is generated from the same graph chant graph --components prints: one stage per wave, one job per component, dependency edges from dependsOn, and each stack’s outputs handed to the next job as artifacts. Around it sit a gated deploy and the scheduled Ops.

GitHubGitLabForgejo
Generated component pipeline.github/workflows/components.yml (npm run generate:github).gitlab/components.yml (npm run generate:gitlab), included by .gitlab-ci.yml on push and merge requests.forgejo/workflows/components.yml (npm run generate:forgejo)
Drift check of the committed filesrc/github-pipeline.test.tssrc/gitlab-pipeline.test.tssrc/forgejo-pipeline.test.ts
Run against Flocijust github-runtime-e2e (with act)just gitlab-runtime-e2e (with gitlab-ci-local)just forgejo-runtime-e2e (with act)
Gated deploy.github/workflows/deploy.ymlthe deploy job in .gitlab-ci.yml, a manual button, never on a schedule.forgejo/workflows/deploy.yml
Scheduled Opsfive workflows (below)schedule-only jobs in .gitlab-ci.ymlworkflows mirroring GitHub’s

The drift checks are part of npm test, so a committed pipeline that differs from a fresh generate fails CI. The Floci runs deploy the light tier’s infrastructure components with the output handoff between waves; they need Docker and aren’t part of the gating CI.

On GitLab the component pipeline is skipped on schedule pipelines, so a scheduled Op never triggers a deploy. A Forgejo deploy needs a runner with Docker access for the image builds, and Forgejo’s reconcile opens its pull request through the Forgejo API.

.github/workflows/ci.yml runs on every pull request and push to main: typecheck, chant lint ., the unit tests and the Ops build. It needs no credentials.

Each generated job is a thin trigger, chant run --components <name>, and assumes chant, its dependencies and the AWS CLI are on the runner. Each component’s first phase synthesizes its own template from the job’s LOOM_* variables, so there is no separate synth job. Provide the rest once, through generateComponentPipeline’s beforeScript, image or extraScript: a runner image with chant and the AWS CLI installed, or npm ci plus an AWS CLI install on a stock image.

deploy.yml runs chant run --components all --env "$LOOM_ENV". It stays inert until you set:

  1. the repository variable DEPLOY to true;
  2. a GitHub environment named production holding the AWS credentials the job uses.
WorkflowRunsCronTurned on byAlso needs
watch.ymlloom-watchevery 15 minutesSCHEDULED_WATCH=truethe production environment
reconcile.ymlloom-reconcilehourlySCHEDULED_RECONCILE=true and LOOM_TIER set to a production tierthe production environment
backup.ymlloom-backupdailySCHEDULED_BACKUP=truethe production environment; LOOM_DR_REGION and LOOM_DR_KMS_KEY_ID for a DR copy
restore-drill.ymlloom-restore-drillmonthlySCHEDULED_RESTORE_DRILL=truethe production environment
cost-report.ymlnpm run synth && npm run estimate-costweeklySCHEDULED_COST_REPORT=trueinfracost and an INFRACOST_CLI_AUTHENTICATION_TOKEN secret for real numbers
audit.ymlloom-auditdailySCHEDULED_AUDIT=truenothing

Every one also has workflow_dispatch for an on-demand run. The gated Ops are never scheduled.

Skip the generated pipeline and deploy the synthesized templates with aws cloudformation deploy from whatever CI you run (Deploy without chant).