status: active
timestamp: 2026-07-02
tags: [ci, dagger, pipeline, portable]
Everything should be in Dagger — GHA/GitLab/Codeberg are thin adapters only
All CI/CD logic lives in Dagger TS modules. GitHub Actions, GitLab CI, Woodpecker, Codeberg are 5-line wrappers that call `dagger call`. No real logic in YAML.
Everything should be in Dagger
The rule
Every CI/CD pipeline must be implemented as a Dagger TS module. GitHub Actions, GitLab CI, Woodpecker, and Codeberg workflows are 5-line thin adapters that invoke dagger call. Zero real logic lives in YAML.
What “thin adapter” means
# .github/workflows/ci.yml — this is the ENTIRE workflow
name: ci
on: [push, pull_request]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dagger/[email protected]
with:
version: latest
call: ci --source=.
The actual lint, typecheck, test, build, deploy logic lives in dagger/src/index.ts.
Why
- Local reproducibility:
dagger call ci --source=.on laptop = identical to CI. No “works on my machine” gaps. - Provider portability: same Dagger module runs on GHA, GitLab, Woodpecker, Codeberg, self-hosted — swap the 5-line YAML adapter, zero logic changes.
- Testability: Dagger functions are TypeScript — unit-testable, type-safe, refactorable.
- No YAML sprawl: YAML is config, not code. Business logic in YAML = untestable, untyped, duplicated.
Anti-patterns
- ❌ 100-line GHA YAML that installs deps, runs lint, runs tests, builds, deploys — all in YAML steps
- ❌ Copying the same setup-node + pnpm-install block across 20 workflow files
- ❌ Building a
build-windows-personal.ymlthat uses choco, cargo, bun directly in workflow steps instead of wrapping in Dagger - ❌ Using
uses: actions/cache@v4for caching — Dagger has its own layer cache viadag.cacheVolume()
The screenpipe GHA workflow lesson
The build-windows-personal.yml created for chirag127/screenpipe failed because LLVM version was wrong in the YAML steps. Had this been a Dagger module, the LLVM setup would be in TypeScript with proper version detection — not brittle choco pin. Every YAML failure is a reminder to move logic to Dagger.
Where Dagger modules live
Fleet-wide reusable modules: chirag127/workflows/dagger/<class>/src/index.ts
Classes:
astro-site— lint + typecheck + test + build + CF deployastro-api— lint + typecheck + buildastro-pwa— full CI + PWA manifest checkmdbook— mdbook build + link testbrowser-ext— WXT + web-ext manifest lintvsc-ext— lint + typecheck + build + vsce packageuserscript— syntax + metadata validationnpm-pkg— lint + typecheck + test + build + publish
Exception: GH-integrated workflows
Keep native YAML for: ossf/scorecard, CodeQL, actions/deploy-pages@v4 (OIDC), Dependabot config. These integrate with GitHub Security tab dashboards — Dagger cannot replicate that.
Cross-refs
pipeline-stack-2026-07-01— the locked stack (pnpm + MegaLinter + Dagger TS)dagger-confirmed-2026-07-02— re-grill that confirmed Dagger after debatereusable-workflows-layered-2026-07-02— how Dagger + reusable GHA workflows compose