yeah, I was scratching my head about this for a while as well. At first, I created all the per-step dagger functions (build, test, lint, oci-build, oci-push, etc.), binding them to respective BB CI jobs. That was a PAIN, because I had to use 2 repository providers: BitBucket (because my current project is hosted in BB) and GitHub (because Dagger only allows fetching modules from GH 🙄 ). That was inconvenient, so I tried storing modules locally, basically a copy of the same dagger code in every repo of the project. Talk about DRY coding.... a maintenance hell.
Eventually, I ended up using a Wolfi module exposing *Container to the dagger CLI that I can use to spin up custom containers and pass them instructions I'd otherwise pass using Golang (module code). e.g.
: "Run SAST scans"
out_file="trivy-report.out"
cmd="trivy fs -c trivy.yaml --output ${out_file} --exit-code 0 ./"
dagger -m github.com/shykes/daggerverse/wolfi call container \
from --address aquasec/trivy \
with-directory --path /target/ --directory ./ \
with-workdir --path /target/ \
with-exec --skip-entrypoint --args sh,-c,"${cmd}" \
file --path ./${out_file} --output ./
binding each action to a respective BB CI job. This way I can maintain BB CI visualisation and have reusable, though sometimes terribly long, dagger CLI commands to launch my CI jobs. However, this means that each BB CI job, running in isolation, has to download and install and start dagger engine separately, adding 1-2 minutes of overhead, which is very inconvenient (dagger does not provide an OCI image and I haven't made mine yet).
Also, this approach prevents me from having a master CI job, allowing me/developers to run the whole pipeline locally. But that's a tradeoff I can live with. And there's the caveat of passing []string values as CSV, introducing issues like https://github.com/dagger/dagger/issues/7678.