#daggernauts
1 messages Β· Page 2 of 1
go mod replace definitely needs to go, and yeah go mod init could maybe be automated for you; it makes sense for your Dagger Go code to have its own module as a sane default, so you don't pollute your project's dependencies with Dagger dependencies. I just had to fix that recently in Booklit: https://github.com/vito/booklit/issues/55
Aside from that though, I think it's a safe assumption that you'll have the Go tooling around if you're planning to write Go code, at least until we wrap the full dev environment (like doing dev out of dagger shell).
In general we need to figure out how to handle dependencies of the generated code, which is what the go mod replace thing is revealing. Same is true of github.com/Khan/genqlient/graphql, it just happens to be a stable published one so it works, but we're not pinning its version it at all.
Yes, I feel like we can do both:
- If the dev has their native language toolchain on the host, they can use it seamlessly
- But if they don't, everything works out of the box. This could help make Dagger more approachable. Some devops people may be taking their first step into Go, Python or JS dev via Dagger, and the easier we make it for them, the better
What's the story behind the go mod replace? I see the comment but don't fully understand it
Side quest: I'm going to try taking all those go mod commands and shove them into dagger mod init
In a very clean and elegant way (just kidding it will be fugly)
This friday 9am pacific weβll be developing our first Zenith module togetherβ¦ Join us if youβre not afraid of rough edges π https://discord.gg/WPUxZybU?event=1141890044869750875
Update: those separate go mod commands are no longer necessary; dagger mod init will bootstrap a go.mod for you instead and go mod tidy it throughout the codegen process. Instructions have been updated: https://github.com/shykes/dagger/tree/zenith-functions/zenith#creating-your-first-module
This flow is a bit brittle, so please don't be afraid to try out some esoteric scenarios and let me know how it goes. π
fyi: starting on a somewhat hefty merge now that https://github.com/dagger/dagger/pull/5764 has landed. Going with a merge instead of a rebase for now, don't want to hide away botched merge conflict resolutions in the history.
@warped canyon not sure if you already have one, but next step for me is a "main" module with two "utility" module depedendecies. One in github and one in gitlab! π
Trying out a module, need some help
Do we have a preference on what to call module repos? I'm writing a Git utility module (theoretically Daggerverse itself will use it, but right now it's just so I can test it at all). Should we have a convention like gitutil-dagger? dagger-gitutil? dag-gitutil? If we're using repo URIs as our canonical name for modules, length will matter
A low-hanging fruit for the first module-a-thon (better name needed?). I think it would be helpful to ship a binary release ahead of time, so that writing a module doesn't require building zenith, or even checking out the dagger repo at all.
dagger mod extend π§΅
pro-tip for testing your module: dagger query supports a --doc flag
@warped canyon I'm trying to extend the container type but getting weird errors when querying my module
Got my first module to work!
Feature request: dagger --mod <URL> so that I can do dagger -m git://.... query without having to git clone anything
My first Zenith module π https://github.com/shykes/daggerverse/tree/main/ttlsh
It extends the Container core type with a ttlpush function, which publishes it to ttl.sh, a throaway registry without any credentials required
Example query:
query test {
container {
from(address: "alpine") {
ttlpush(repo: "solotest", tag: "latest")
}
}
}
- Development time: 30mn, including first setup.
- Line count: 20 lines (will be 15 soon)
@thorn moat since bug reports and feature requests are starting to pile up, how do you recommend we go about organizing them? We could just do github, but feels a bit heavyweight given the pace. Linear is closed... Maybe a special discord forum for zenith help? wdyt?
heh i was just wondering the same. a forum SGTM.
trying now
what's the difference? @sharp zealot
oh, does that create the test.gql?
The graphql document can contain multiple named queries. Then you can specify the one you want to run (in this case: "test")
I think when there's only one query in the doc, you can omit the name. So: dagger query --doc test.gql
Ah yes, the Graphql lingo https://www.apollographql.com/blog/graphql/basics/the-anatomy-of-a-graphql-query/
I like your description better. Will make an issue or PR to make this one clearer:
uhhhhh @sharp zealot
dagger q -m "git://github.com/shykes/daggerverse?ref=main&subpath=ttlsh" << EOF
query test {
container {
from(address: "alpine") {
ttlpush(repo: "solotest", tag: "latest")
}
}
}
EOF
that works! π€―
Should we .gitignore dagger.gen.go?
NodeJS isn't happy with us using the word Function π
/sdk/nodejs/sdk/nodejs/api/client.gen.ts
3851:30 error Don't use `Function` as a type. The `Function` type accepts any function-like value.
It provides no type safety when calling the function, which can be a common source of bugs.
It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.
If you are expecting the function to accept certain arguments, you should explicitly define the function shape @typescript-eslint/ban-types
Fn? DaggerFunction?
Func is probably fine too, I think that's mostly a Go thing and it's OK with it as long as it's capitalized
Fun π
i am extremely impressed
- I'm renaming dagger mod extend to dagger mod use but lemme know if anyone disagrees. use feels a lot more obvious to me; extend feels like a holdover from the 'extensions' terminology. Also down for import or something but it sounds a bit dry, and possibly has more language keyword conflicts.
I agree with ditching extend. i vote for whatever word scores most familiarity points in focus groups π
works for me!
use is fine with me
PSA: I've gone ahead and changed module refs to look like Go module refs: github.com/foo/bar/subpath@version. dagger mod use now accepts any git ref as the version and will resolve it to a commit before placing it in dagger.json. There are many reasons this might not be the final format we land on, but for now it looks pretty and at least leans on an existing familiar syntax.
Some open questions:
- Right now it only supports
github.com/. This is because it's impossible to know where the repo URL ends and the subpath begins. Most repo URLs are username/reponame, but some of them can be arbitrarily nested (e.g. GitLab). Go went to great lengths to solve this problem, but it works by requiring the vendor to co-operate. (If you view the source of https://github.com/vito/booklit you'll see a special<meta name="go-import" ...>tag) - Do we want to support HTTP source code tarball module references or any other format? Or do we want to be "pure git"? There's kind of a beauty in making this open-ended, since anything that can produce a
dagger.Directorycan be a valid module ref, and theoretically Daggerverse can proxy any of that just as easily as it can proxy Git. - Right now all the Git stuff happens by running the
alpine/gitimage in as part ofdagger mod use, which is a hard dependency on an external party. We should rein that in somehow.
Challenges not unique to this format that might be nice to resolve:
- It's impossible to know whether the user has specified a commit, a tag, or a branch. Right now it just blindly resolves whatever ref you gave it to a commit, but it would be nice to preserve tags. I suppose it could parse semver, with an optional prefix, to detect that. Have to keep in mind the difference between
github.com/kpenfound/daggerverse/foo/bar@v1.2.3andgithub.com/kpenfound/daggerverse/foo/bar@foo/bar/v1.2.3though (assuming path-prefixed tags in a monorepo scheme like the one we use indagger/daggerfor SDKs).
Bikeshedding module ref URLs
@thorn moat I have dagger mod sync running infinitely on latest right now trying to codegen github.com/kpenfound/dagger-modules/golang
in my greetings-api project I have the zenith module as a subdirectory of the project it does ci for. With the earlier build of zenith I would use root: "../". Is that still the way today, or is there another way to load the parent dir when I call Host().Directory(".")
It's all via workdir now. So either change the actual workdir of the dagger CLI, or use dagger --workdir (I think)
noice echo '{greetings{unitTest}}' | dagger query -m ./ci
so my two modules are working together nicely now (until I have to codegen again)
github.com/kpenfound/dagger-modules/golang: generic golang module to provide a base image, build/test/lint helpersgithub.com/kpenfound/greetings-api/ci: my greetings-api ci module. Combines the golang module with my project specific settings
Nice, I will try using one of your modules in one of mine today, see what happens
@warped canyon Are you OK to run the module dev "workshop" tomorrow? I'm thinking there are a few details that are worth preparing today, like pre-building the zenith binary and adding that to the README so we all save setup time tomorrow. I'm available to work on it with you this afternoon. Should free up dev time for @thorn moat
Any requests for a zenith module? π
I'm making a basic "dagger-dev" one now
@warped canyon once I get a basic standalone version to work, I'll try swapping in your golang module
I'm stuck on a cryptic error while developing my 2nd module, if anyone is around to help me out?
Here's a fun one: I'm trying to daggerize ./hack/make engine:build (a dagger function to build dagger from source), but that command itself wraps dagger... π
Yeah sounds great! Let me know what you need
Not sure, whatever would make it as easy as possible for first-timers to go from zero to a working module π
At some point I'll hand you the mic and we'll all follow your instructions.
If those are "checkout the repo, follow the readme, raise your hand if you're stuck" that's perfectly fine
OK, I might have bitten off more than I can chew with this dagger-dev module...
Cool. If we're providing a zenith binary (and an engine image??) we should be able to get people started without checking anything out, and just run 100% from scratch
I can help out if you'd like. Just about to eat dinner over here
It's OK, I can use it as my own project for the workshop tomorrow π
That would be ideal but I don't think we have that ready. Let's see how it goes tomorrow with a full checkout, and we can iterate from there for the next one
should I push updates here? https://github.com/shykes/dagger/tree/zenith-functions/zenith#project-zenith (or fork + PR)
A portable devkit for CI/CD pipelines. Contribute to shykes/dagger development by creating an account on GitHub.
the main thing I'd update is instructions to create a module in your own repo rather than as a subdirectory in zenith, and maybe touch on dagger mod use with the golang module?
You can just push directly - with a heads up here + be careful not to break the build of course π
Yeah that sounds great
Maybe also mention the cold fusion thing? π
OMG it works! I added ExperimentalPrivilegedNesting and I have zenith module wrapping hack/make wrapping dagger, and it all just works π
OK nevermind. It does successfully run dagger-in-dagger, but then I get weird errors about missing files
That's really strange...
So is my module, to be honest π
Let me share that with you
(would be cool if somehow you could go from a dagger cloud run page, to the daggerverse link of the corresponding module... but I digress π
Oh wait let me try and share a copy-pasteable query π
Is this part supposed to be only mounting internal/mage? https://github.com/shykes/daggerverse/blob/main/dagger-dev/main.go#L46
ohh I see
echo '{ dagger_dev { source(version: "0.8.4") { daggerHack(version: "0.8.4", args: ["docs:lint"]) { id } } } }' | dagger query -m 'git://github.com/shykes/daggerverse?ref=main&subpath=dagger-dev'
uuuuuh.... @thorn moat π
Am I allowed to share the link to my module on your RIDICULOUS daggerverse demo?
Or would that spoil the surprise?
because it works FYI
eh go for it
whee our little index is growing
In case it's easy to scrape: I added comments to the module type, to describe the module itself
the web UI supposedly grabs the module description and shows it, but I didn't know where it would be even coming from. Module struct type makes sense! I'm guessing it's just not being collected by the codegen yet
This isn't doing the thing on my end π€ Cannot query field "dagger_dev" on type "Query"
@thorn moat on latest should I be using
git://github.com/shykes/daggerverse?ref=main&subpath=dagger-dev
or
github.com/shykes/daggerverse/dagger-dev
with -m
I tried daggerDev too, no luck
It's funny, I ran ./hack/dev on the zenith-functions branch an got a running dagger-engine.dev container, but my dagger CLI is broken and quite a bit smaller than if I build the binary with go build π€
the one I built with go build actually runs fine, but he other one spits out
Yup, that's been happening on my end too. As a workaround I've been doing ./hack/dev followed by go build -o bin/dagger ./cmd/dagger
It's like the go build is getting cut off mid stream in the ./hack/dev case
or something
oh I didn't catch that
would make sense
also if you're using goenv, that is temporarily unsupported
Out of curiosity, does the zenith call get recorded? I can't make it unfortunately, but would love to catch-up later π
I'd love to do that! Do you know a good way to record Discord calls? I think we've been trying something, but it's flaky.
I think audio is pretty solved on Discord, but video...
Everyone says, get an extra machine with OBS istalled π
Oh yeah I suppose it's not super trivial π€ yeah I don't have any particular knowledge of it...
found the issue with -m <ref>, fixing!
We'll try! If we can't we'll be hanging out in this channel A LOT so come by any time and someone will want to chat about modules! π
@warped canyon @sharp zealot pushed, this should ... well it doesn't work, but it does something now: echo '{ dagger_dev { source(version: "0.8.4") { daggerHack(version: "0.8.4", args: ["docs:lint"]) { id } } } }' | dagger query -m github.com/shykes/daggerverse/dagger-dev
What error do you see?
/tmp/buildkit-mount2577139352/.markdownlint.yaml: no such file or directory
Yup that's the same one I get
But separately, can't get dagger query -m github.com/shykes/daggerverse/dagger-dev to work (getting the 'Cannot query field' error)
here's my full command with dagger built from the latest commit echo '{ dagger_dev { source(version: "0.8.4") { daggerHack(version: "0.8.4", args: ["docs:lint"]) { id } } } }' | dagger query -m 'github.com/shykes/daggerverse/dagger-dev'
Have you pulled?
Yeah, I pulled + ran hack/dev but might have messed up. Can dagger version give me the build commit or something?
dagger version
dagger devel (b39ac77b8) darwin/arm64
which dagger
/Users/kylepenfound/scratch/zenith/bin/dagger
interesting, I get dagger devel () linux/amd64, maybe because that's the ./hack/dev version?
same
oh right, I'm doing my own go build
I think maybe it's my module build logic that causes the error
quick sidebar: dagger_dev should probably be normalized to daggerDev right? not sure where that isn't happening. is what what you set as the module name?
i noticed it also accepts foo-bar which just detonates the GraphQL schema
This is the problem: https://github.com/shykes/daggerverse/blob/main/dagger-dev/main.go#L46-L50
Basically I'm trying to decouple our magefile code from the target source code. Which is annoyingly hard to do
I'm curious about the multiple git clones, since source in DaggerHack isn't used
they're both used normally
I decouple the magefile version from the dagger source version. So you can build version X with magefile version Y
ah I see, so you'd probably want env := hackEnv(version, source)
My first approach was to go build internal/mage/ into a binary, but go won't allow it because it's a non-main package
Yes thank you. Got mixed up
So now I'm trying to mount both in the same container, and go run one against the other. But I may be in a situation where my workdir needs to be two things at once
this would be super messy, but you could have
sourceA(blahOpts{ Include: []string{"internal/mage"})
sourceB(blahOpts{ Exclude: []string{"internal/mage"})
and drop them on top of eachother
and then less reliant on mage to do the workdir thing properly
The workdir thing actually seems ok because I can do this locally. I'll try some more things
You know I feel like it's easier to shift gears, instead of wrapping hack/make etc, I might just implement a simple go build for now, and gradually move the low-level functions right into the module
basically port hack/make to zenith, instead of wrapping it
I kind of want to take arguments to my moduleβs top-level fieldβ¦ is that possible?
eg. { dagger(version: β0.8.5β) { cli { export(path: β./daggerβ) } } }
seems like it could be possible someday - there's already a toplevel struct, just begging for some fields π€
failing that, you could always add a constructor + type of your own
if I make ModuleName a function instead of a struct type, will it somehow work? one can dream π
https://daggerverse.fly.dev/ less ugly index
just extend it right off of Query π§
the earlier/simpler version rendered better on mobile fyi
oh yeah good call, i'll do a quick pass, definitely need some @media in here
i tried it once on mobile and the module page looked pretty bad too
you made me go check if that was possible π
i mean, theoretically...
we just don't have a Query type (it's fused with Client)
kind of calls for a fly module doesnβt it π
I think we should consider making that the default behavior of the top-level struct (merge it into query instead of namespacing it). Weβll need to handle conflicts, but we already need to do that anyway with core type extensions
wdyt @warped canyon ?
I can already tell Iβm going to want that kind of control
Yeah if the top level thing from your module is a function that has 0 params and returns your module's struct, it would look exactly the same as it is today. So nothing is getting lost there. Only gaining the ability to pass params and potentially return core types to chain from there
is there any way to use dagger as service?
We are developing a cloud service fittingly called Dagger Cloud. May I ask what features and use case you are looking for?
it's simple...we dont want to setup docker for 10 machine and docker swarm on it to connet and drive devops workflow to build, test and deploy code...we just need dagger as service to directly connect it and use it...this is one of the use case...and which can be auto scaled also...and we should be able to connect our machines with it also to save money like github self hosted runner...this can be win for startups...
we just need to connect machines with that service and rest of the things will be handled by dagger service to use mac machine's CPU & GPU
That makes a lot of sense, @whole maple. While we don't have a hosted service for the compute, we do integrate with compute hosted by CIs, such as runners managed by GitLab, GitHub, CircleCI, and others. Is that something that could work for you?
sorry, I'm a complete idiot when it comes to discord. Is 9am call happening right now somehow, somewhere?
Starting a thread about how type extensions, since that was a big topic in the call today
I'm glad you made it! Thanks for your feedback and ideas.
@sharp zealot btw, I don't know if you noticed this "fine print" easter egg π - it's handy if you want to load a module up into the Apollo explorer, I used it for debugging things while building Daggerverse
@thorn moat resuming zenith hacking for my last few hours before the week-end...
to answer your earlier question on dagger query -m: I am on the latest version of the branch (I think)
do ya have a command I can try to run?
echo '{host{directory(path:"."){goTest(args:["./..."]) {stdout }}}}' | dagger query -m 'github.com/kpenfound/dagger-modules/golang'
hold on, let me move this to #1151970583723126844
What's the easiest way to setup a zenith nightly build?
as a starting point...taking a look
I mean... if it could be using a dagger module, that would feel extra 
noticing Mage syntax
func (Dagger) Publish(ctx context.Context, version string) error {
err := Engine{}.Publish(ctx, version)
if err != nil {
return err
}
err = Cli{}.Publish(ctx, version)
related to module namespacing
It worked @warped canyon ! https://alpha.dagger.cloud/runs/e1fb237a-639b-4035-9769-609c4808cd08
Have a great week-end everyone. Fantastic progress this week, I am very excited for what we'll build next week π
π
Where is the list of dagger types like Container that the gen can generate ?
I think all core types? π€·π»ββοΈ
@muted plank Yeah I don't know of any limitation, one bug though is that you have to refer to any 'extended' types from your module's entrypoint type, otherwise the codegen won't pick it up. (It sounds confusing because it is confusing. π )
So a workaround is like this:
type MyModule struct {}
// this won't be picked up on its own
func (m *Container) MyContainerMethod(ctx context.Context) (string, error) {
return "xyz", nil
}
// workaround - note the Container return type:
func (m *MyModule) Foo(ctx context.Context) (*Container, error) {
return nil, fmt.Errorf("ignore me")
}
I see. I was wondering what are types that cannot be translated to some kind of "CLI syntax". I realize that graphQL must have the same problem. So any types that is not graphql serializable must be a problem. The obvious examples i am thinking of are "chan", or io.Reader, etc. these were types libchan could serialize in the old days (and I have been punting on a libchan v2 using HTTP3 forever but that's another story). Note that I cannot think of a good usecase now.
π just pushed the first module https://github.com/aweris/daggerverse/blob/main/gh. echo '{gh{run(version: "v2.34.0", args:["repo", "view", "dagger/dagger", "--json", "id,name,nameWithOwner,url,defaultBranchRef"], token: "'"$GITHUB_TOKEN"'")}}' | dagger query . I needed this while working on gale module.
nice! wanna add it to https://daggerverse.fly.dev/ ?
Sure, I'll make some update later today, than I can add daggerverse
Working on getting this one in shape. Similar to what you built @spiral whale in that it installs a CLI, the AWS Copilot CLI for deploying to ECS (not sure how many folks use it, but looked interesting).
https://github.com/jpadams/dagger-module-awscopilot
The thing is, once you actually run it, it wants to do a docker build of a Dockefile and such to deploy to ECS...I hacked this together really quick last night and was following a getting started example for inspiration, but maybe I can deploy an image from a registry vs doing a dind build (which I couldn't quite get to work). Will take a look in the light of day π
I used passed AWS creds as env vars like this to my test function as plain strings that I then turnded into secrets. Better way?
echo "{awscopilot{test(awsid: \"$AWS_ACCESS_KEY_ID\", awssecret: \"$AWS_SECRET_ACCESS_KEY\", awsregion: \"us-west-2\")}}" | dagger query
func (m *Awscopilot) Test(ctx context.Context, awsid string, awssecret string, awsregion string) (string, error) {
...
WithSecretVariable("AWS_ACCESS_KEY_ID", dag.SetSecret("awsid", awsid)).
WithSecretVariable("AWS_SECRET_ACCESS_KEY", dag.SetSecret("awssecret", awssecret)).
WithEnvVariable("AWS_REGION", awsregion).
...
Develop, Release and Operate Container Apps on AWS.
Working on getting this one in shape
@thorn moat We weren't able to use *Secret for our secrets and send them through the dagger cli, so both Ali and I used string and then set the secret within. Any idea how hard it would be to enable secrets from the start?
I also ran into wanting content from a directory outside of my project root.
I also ran into trouble trying to run a dind service container (might be doing that wrong).
Also wanted dagger shell a lot to try my new CLI in a container with my creds and project loaded π
@wintry prism I recommend posting discrete questions & issues on #1151970583723126844
Otherwise high probability it will get lost in the noise
I was refered to zenith via this github question I had: https://github.com/dagger/dagger/issues/5784
is there a page explaining what zenith is? or a github repo or something with an explaintion of what the project is about?
I found this video, from the first few mins it seems like the opposite of what I was asking about: https://www.youtube.com/watch?v=Pt_AsbQilAM. I want to write an internal tool with the SDK not a DSL. I just want to use it for generic cli tool use cases not just CI/CD
In this demo, Solomon Hykes, Erik Sipsma, and Alex Suraci introduce Project Zenith. They discuss the concept of reusable environments and demonstrate its implementation in real-world scenarios. With Project Zenith, developers can leverage standardized entrypoints, rich data-driven environments, and language-agnostic APIs, enabling seamless colla...
Hi @rustic river , i answered in that forum post. Short version is that Zenith is relevant to your use case, but it is not a requirement. It will just be an additional improvement when it ships. Embedding Dagger in your custom CLI is supported today and will continue to be supported after Zenith ships
Did ayone else encounter this? #1153454775627681804
echo "{container{from(address: \"alpine\"){trivyScan}}}" | dagger query -m github.com/jpadams/dagger-module-trivy
@spiral whale leveled up! 
By the many swords of Zenith!
echo '{ dagger { engine(version: "0.8.7") { cli(operatingSystem: "darwin", arch: "amd64") { export(path: "/tmp/dagger-darwin") } } } }' | dagger query -m github.com/shykes/daggerverse/dagger
π
If you have a zenith build of dagger, this should work out of the box
My dream would be to add enough to this module, to be able to build and release a working binary release of zenith, using zenith - and for everyone here to be able to get the latest version of zenith, using zenith π
So I've been playing about making a module - I found a kind of interesting thing with overriding native types to allow chaining.
It's kinda weird to pass parameters to the overridden methods of core types - e.g. if I want to pick a version of the software (e.g. a version of hugo, for the module I'm working on).
I guess the way to do it might be something like the Container.DockerBuild implementation (https://pkg.go.dev/dagger.io/dagger#Directory.DockerBuild), and pass some config struct to each call in that module. But it does feel a bit bulky if you were to call multiple module functions in a chain - e.g. HugoBuild, HugoLint, you'd have to pass that same config everywhere.
The chaining feels so nice though. Without it, you'd create a HugoBuilder object, and then use that, which gives you a nice place to chuck various configuration parameters. Obviously this breaks chaining though.
Out of curiosity - would it be possible to do something similar to With to allow keeping chaining without needing to directly modify methods on Container? You could potentially have something like this: https://gist.github.com/jedevc/ec3e37b0afffa472f8a7570fd6ef139e (I have no idea how the typing of something like this would shake out though). As a nice bonus, you then don't end up having potential clashes when extending core types.
This is in theory possible, but would require basically support for remote callbacks. I think we have the plumbing for it with IDs, but there are probably a lot of details to get right in order for this to work. I love the idea though.
As a user though, I still like regular chaining better π
@deft rain in your example, Sample embeds Directory. If that's the crucial part, should we consider one day making struct embed a feature of our type system?
eg. dir.AsSample(version: "latest").DoThing(param: "foo").WithExec([]string{"echo", "foo"}).Stdout(ctx) ?
Ah, that wasn't really the essential part to me - it was more about wondering how we could do the typing of something like that, e.g. how does the implementation of With in my example know that Sample can be chained onto Directory properly (as opposed to Container, or any other core type)
Buuut, I really like that example. Seems to solve scoping and parameterisation as well.
Yeah I appreciate the practicality of With as a stopgap, but compared to chaining, it just feels harder - like I have to translate it in my head, whereas chaining just makes sense immediately
With feels like "meta-chaining" if that makes sense
Agreed, I think I prefer the more explicit struct embedding you suggested, I think that's a better way of trying to work out my pre-coffee module problems.
I was really excited for a moment here, but this is just using Goβs built-in cross compilation support. Unfortunately the βreal dealβ is probably contrary to Appleβs terms of service.
the With pattern actually already works if you're using codegen'd APIs from a dependent module, since they don't have the ctx argument or error return value: https://github.com/vito/bass/blob/5572c132452d5893c9dbbdb5cb3e55ce97c4763c/ci/ci.go#L106-L107
Update: as of the latest push (https://github.com/dagger/dagger/pull/5757/commits/73aff3c57263a505f5548d51a1f3e25614bf612b) functions no longer require a ctx argument and error return value.
So these should all work:
func() X<- return a value with noerror, likeContainerfunc()<- weird to do, but still works, returnsVoidfunc() error<- less weird (side effectful), returnsVoidfunc() (X, error)<- same as today but withoutctxfunc(context.Context) error<- etc...
Update as of the latest push https
Did anyone else feel the need for this? π https://discord.com/channels/707636530424053791/1153780921573593148
Hurray!
FYI @thorn moat I merged @deft rain 's "PR on the PR" as-is: https://github.com/shykes/dagger/pull/123
somehow got back on goenv
thanks for the heads up! I took a look and it LGTM, I've added it to the list of things to backfill a test for
I passed on to @jedevc the advice you gave me which is: just push to the branch as-is, with a heads up, long-running dev branches are an exception (and we should try to merge soon-ish)
You're right @sharp zealot, your helloWorld is :chef's kiss:
{
β β β "helloWorld": {
β β β "withGreeting": {
β β β "withName": {
β β β "message": "you're the best!, jeremy!"
β β β }
β β β }
β β β }
β β β }
Some "genera" or "families" of modules are starting to emerge.
Uses container image with CLI already inside. Provides interface to that CLI.
closely related to
Installs a CLI in a container. Provides interface to that CLI.
optionally using
Takes in one or more secrets to drive a CLI or API calls.
etc
I figure if we have really solid examples for the major kinds, it will be easy for folks to make more.
Mixing and matching best practices
which we're still discovering
@thorn moat I'm trying to make my 'dagger' module into something actually useful... I started lifting chunks of internal/mage but there's so much... The most useful thing I can think of, is getting us to a binary release of zenith itself... in other words building & publishing a CLI+engine container combo. Does that feel feasible to you? Any pointers on where to look in the dagger repo? cc @chrome pilot
This is my module so far: https://github.com/shykes/daggerverse/blob/main/dagger/main.go
I think you can find a partially implemented version under ci/ on the PR
awesome - also noooo I just spent 2 hours doing the same thing this morning π
OK maybe not that long
finally, the initial gale module is up (https://github.com/aweris/daggerverse/blob/main/gale). It needs to work on module and gale site but it's good enough for now. π
export GITHUB_TOKEN=$(gh auth token)
echo '{
gale {
repo(name: "aweris/gale") {
withWorkflowsDir(dir: "ci/workflows"){
list(token: "'"$GITHUB_TOKEN"'")
workflow(name: "ci/workflows/lint.yaml") {
withJob(name: "golangci-lint") {
withDebug{
run(token: "'"$GITHUB_TOKEN"'")
}
}
}
}
}
}
}' | dagger query -m github.com/aweris/daggerverse/gale@main
woop, published my hugo module π https://daggerverse.fly.dev/mod/github.com/jedevc/daggerverse/hugo@43859b8da41b56ec3ed67830e4328056647d5768
@kind carbon Iβll be home in 10mn, want to catch up on zenith before your day ends?
@thorn moat @chrome pilot @deft rain youβre welcome to join of course
Yeah, let's go π
joining now
@deft rain leveled up!! 
how can I get this goodness!?
use it while it's hot! https://daggerverse.fly.dev/mod/github.com/samalba/inline-python-mod
Feature request: dagger query -q for a quiet mode, that prints only the result of my query. It can get pretty hard to spot with all the TUI output
--focus should do the trick
used to be the default, but found it was hiding errors too often, needs fine-tuning
if everything disappeared at the end, it would be OK - I think that's how it worked before?
@mossy hazel you have a downstream π https://daggerverse.fly.dev/mod/github.com/shykes/daggerverse/myip
can someone try this?
echo '{myip{ip}}' | dagger query -m github.com/shykes/daggerverse/myip
I have an "empty" dir called sandbox with just a .envrc in it to run these π
{
β β "myip": {
β β "ip": "97.115.90.190\n"
β β }
β β }
@sharp zealot π
yay π
Imagine once we have dagger do π
dagger do -m github.com/shykes/daggerverse/myip ip ?
maybe do is not the right verb
maybe just dagger -m like python -m
we need the namespace though, to avoid conflict between the module's functions, and the other subcommands of dagger
coukd be dagger run MODULE FUNCTION ...
dagger run github.com/shykes/daggerverse/myip ip
dagger trust github.com/shykes/daggerverse
dagger run myip ip
dagger run helloworld ...
if no conflicts can make shorter
this would not work well with single-module repos
touche
But I would love to find a way to shorten things eventually
I think for now having the URL in there every time is fine, if we get something consistent and reliable
shorter and well-trusted seem important, so we don't get a curl | bash type problem with untrusted content
shorter and well-trusted are separate problems though
curl --trust hack.ru
curl index.html
--> shorter but doesn't actually help with trust
https://github.com/shykes/daggerverse/pull/1 <-- removes the newline at the end of the ip
When you publish after that PR is merged, you'll get a new entry in the daggerverse, right?
Nice π thanks, merged
All by commit
Yes correct
re-publishing now
@thorn moat I think soon we'll be ready for a "latest events" feed, and a separate list of modules
Slowly but surely, frequently updated modules are drowning out "older" modules
Oh wait daggerverse renders the README? love it
@mossy hazel has joined the modulators! 
There's a whole separate rabbit hole around how to identify newer/older modules since they're all git commits, which aren't statically comparable. Would be nice if the main page just showed the latest version of each. I have an idea, but it'll take some schema tweaks
I think my module was the first one with a README.md (after @thorn moat ) π
The README will probably compete with docs attached to the module's entrypoint type, once that's implemented. Could make sense to keep both, since the README often has higher-level info
Isn't that where copying the Go model leads us to using git tags + semver?
@thorn moat BTW my function comments don't show in daggerverse module docs anymore
@thorn moat where would I implement dropping a README.md file during dagger mod init?
@mossy hazel new version with the python code stored in a .py file instead of embedded in a string in go π https://daggerverse.fly.dev/mod/github.com/shykes/daggerverse/myip@146c4b753668823024b9a2d611eb35a6ef0c4965
Feature request @mossy hazel any chance you could take the python code as a File ?
that would remove 3 lines of error checking from my code π
func (m *Myip) IP(ctx context.Context) (string, error) {
code, err := m.Code().Contents(ctx)
if err != nil {
return code, err
}
return dag.InlinePython().WithPackage("requests").Code(code).Stdout(ctx)
}
func (m *Myip) Code() *File {
return dag.Host().File("myip.py")
}
I guess we can simply add a function with a different signature and support both
Yeah, the difference right now is no one is bothering to tag + version modules since it's all prospective. pkg.go.dev only tracks semver tagged things, so it doesn't have this challenge
have an example? I see one here: https://daggerverse.fly.dev/mod/github.com/shykes/daggerverse/myip@146c4b753668823024b9a2d611eb35a6ef0c4965
also that ip function is a good example of something we'll want cache busting for!
Mm nevermind seems to work. i think itβs just the comment from top-level type thatβs missing
oops! yes π
but how?
I think I found it: ./cmd/dagger/module.go
I canβt inject cache busting in @mossy hazel βs function without forking it
putting on my v2 IDs hat, I think we'll need a way to declare resolvers/functions as 'impure' / 'tainted', and those ones won't be cached, and any objects returned by them will be 'tainted'. not 100% sure though. Erik mentioned something similar (some way to mark a function as 'no cache')
Scary Movie 3 Hat gets bigger
Re: dagger do vs other verb. What if there were several verbs to make a query, and each verb corresponds to a UI paradigm?
--> dagger shell [-m MOD] FUNCTION [opts] ...: function must return a container, spawn an interactive shell
--> dagger print [-m MOD] FUNCTION [opts]: call function and simply print the output, with various formatting options. Minimize other output (TUI etc)
--> dagger download [-m MOD] FUNCTION [opts]: call function and download the result to the local filesystem - might be a directory, file, container...
--> dagger dodagger run [-m MOD] FUNCTION [opts]... call function and focus on what it actually does: stream logs, emphasize errors etc. (btw I agree dagger run would be better than do for this...)
π - that's roughly what I had in mind too. What's nice is the same function can have different verbs applied to it. Container can be debugged (shell) or exported (download) etc.
yeah feels elegant to me
btw shell could work with Directory by mounting it into a default container π
Iβm going to call it now, this is a Docker moment in the making
fyi @chrome pilot π
Error: failed to run codegen: template: module:56:3: executing "module" at <ModuleMainSrc>: error calling ModuleMainSrc: json: unsupported value: encountered a cycle via *dagger.TypeDefInput
π
This is very much related to the Grand Adventure I mentioned yesterday, working on a fix! Haven't seen this particular error though.
it might actually be a genuine cycle
or at least something stupid on my end, made hard to debug by confusing codegen error
This happened in the middle of splitting one custom type into two, so there might be some entanglement
@thorn moat I ripped off parts of your ci/ directory hope you don't mind
Trying to get us closer to a zenith module that can ship zenith itself
Erik wrote all that, but I'm sure he doesn't mind π
@thorn moat what do you think will be faster:
- Setting up a bootleg release from the branch
- Merging xrc2 with an experimental flag and doing a real release
I think 1. There's still some things up in the air (extending core types, some schema changes), and at least 1 is guaranteed dogfooding experience
Bootleg it is
@thorn moat, I'm looking at the new TypeDef (input) way of adding the functions. I think you mentioned something yesterday that you want to refactor something around this. Can you clarify what's your backlog of core changes? I'm looking especially for anything that would affect the Python implementation.
refactoring away from complex input types
For all the folks that were hounding me in DMs about this π
dagger query -m github.com/jpadams/dagger-module-trivy << EOF
{ container { from(address: "alpine") { trivyScan }}}
EOF
We use Trivy (via a GitHub action) to scan in our CI today, so I'll be excited to get it into our future version that uses your Dagger module @sharp zealot π (once the features are more fleshed out. Will ping the nice folks at Aqua to see if they can direct me or want to lead on that π )
@warped canyon , that demo was awesome. I have Argo mostly working at https://argocd.inlets.tutes.ai but I think I have to edit my configmap because of the TLS redirects....
testing in production
Look forward to watching the video when available! Darn these 4am streams π
Sorry about that! Hopefully soon there will be dagger/zenith events all over the world for you to join π
@grizzled basin may I ask where in the world you're based?
Just pushed this: https://daggerverse.fly.dev/mod/github.com/kpenfound/dagger-modules/secretsmanager@00fe44e3cbaec78bddbd8af5dd81e633274d1c9b
it's currently panicking in the aws library but i'll figure it out π
A dagger module for Vault would be super cool
Auckland New Zealand. It's 10:22am now
@thorn moat just in case you're there, we're trying to pick the safest route through the release spaghetti π
- Option 1: do a "regular" release to the real registry.dagger.io (probably involves pushing a semver tag to the main repo?)
- Option 2: parametrize the engine registry, and push a release on a different registry (may require forking the code to make
registry.dagger.ioparametrizable - Option 3: somehow ship the output of
./hack/dev
Option 2 seems simplest and safest to me
I can hop on in a bit, walking the πΆ
FYI we're live-streaming in #911305510882513037, trying to release zenith with zenith π
Yay I got my first module into the daggerverse, its completely useless but I am excited to change that soon. π
Nice!
Nicely done, I added the Module Builder badge to your profile ππ₯
We successfully shipped a working zenith build with zenith! Awesome collab session with @wintry prism @ember walrus @thorn moat and special guest @latent trellis β€οΈ
Do you plan to publish binaries and the image somewhere?
Amazing! So excited to see it.
Yes, still have to figure out whereβ¦ Maybe docker hub if I manage to log back in π
I'm excited about inline python. I think @mossy hazel is my new best friend.
Itβs pretty fun π By the way you donβt have to keep the python code in a Go string like I did in the demo. You can have your functions read from a python file at runtime and send that (modules have access to their source directory)
One thing I haven't seen discussed here is Gerrit/Zuul-CI it seems to me that dagger would be killer for toolchains like that, where people typically do trunk-based development on projects with cross-repo dependencies.
Does anyone know what I'm talking about?
@hoary geyser speaking of Gerrit - when learning Go years ago I wrote a simple, specialised Gerrit CI tool - just follows the even stream and then builds the (Apache Maven) projects it sees - I've since changed that to switch that to using Dagger to build the maven project, using a hard-coded/standard Dagger pipeline which is all inside the CI tool - which, hopefully with Zenith - I can just replace that with "detech if theres dagger, run it"
@hoary geyser have been meaning to setup a simple local gerrit-in-docker instance to use to make a small demo video, I just havn't had the time yet.
Interesting. I was thinking particularly about the code review aspect of Gerrit, where a commit is tested, reviewed and amended .
Dagger would speed up the execution of the tests and CI between amends. In the case of zuul-ci they typically use Ansible to run the steps and process the results.
That's what I'm now using it for - we used to have jenkins doing builds, but we moved all our stuff to Azure Devops and kinda lost the gerrit connection/builds - so adapted my old project to use gerrit - really solves one of the issues I had with poisoned repos, sort of. Using the persisent cache is wonders. https://github.com/talios/gowest is my repo - tho I've not pushed the dagger stuff yet
I watch for the patchset updates, or new revs and clone, then call the pipeline build - really need to add some docs to that repo. It really was something to learn Go with.
Good night Mark, you're amazing.
Try pulling if you haven't, I forget when I last pushed but there were a bunch of fixes
You'll also need to dagger mod sync everywhere
actually at least one of the problems seems to be introduced by the last commit
(but another appears when I rollback by 1-2 commits)
On the latest commit I get unknown object against the latest shykes/daggerverse/dagger
dagger mod sync returns:
Error: failed to run codegen: template: module:56:3: executing "module" at <ModuleMainSrc>: error calling ModuleMainSrc: expected named type, got *types.Slice
(I guess that one is the real error π )
from typing import Annotated
from dagger.ext import function
@function
def hello(name: Annotated[str, "The name of the person to say hello to."]) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
$ echo '{ helloWorld { hello(name: "from Python") }}' | dagger query -m zenith/hello --focus
β query [1.20s]
β {
β "helloWorld": {
β "hello": "Hello, from Python!"
β }
β }
WARNING: Using development engine; skipping version compatibility check.
WARNING: Using development engine; skipping version compatibility check.
β’ Engine: afebe977b8ed (version devel ())
β§ 2.52s β 22 β
7
fix pushed!
thank you π
hmmm....still getting errors with latest on
echo '{container{from(address: "alpine"){trivyScan}}}' | dagger query -m github.com/jpadams/dagger-module-trivy
β½ init
β β [0.21s] connect
β β£ [0.00s] starting engine
β β£ [0.21s] starting session
β β !!! STARTING SESSION
β β !!! STARTING SESSION sha256:94a50fccc5bd0d0f980dd7657c6545315605c52e5f175a77ea53656381
β β 41426e
β β Failed to connect; retrying... name:"error" value:"make request: Post \"http://dagger/
β β query\": rpc error: code = Unknown desc = failed to verify client: client ID \"a418ku2
β β mhv2j9ts8it2a06i5m\" not registered"
β β OK!
[1.96s] ERROR dagger query -m github.com/jpadams/dagger-module-trivy
β£ [1.96s] loading module
β [0.44s] ERROR exec /runtime
β unknown object
Error: failed to load module: failed to install module: input:1: git.commit.tree.directory.asModule failed to call module to get functions: failed to get function output directory: process "/runtime" did not complete successfully: exit code: 2
maybe have to mod sync?
did that, yeah π€
oh, but I need to release that new mod sync'd to daggerverse
let me try again locally
I get more errors locally including a dump on the schema or something that I've seen in the past.
I still need to update Daggerverse for this change, but yeah, all modules will need to be synced + re-added. I might just purge the DB π’
The error I got above was from my local, though
Will that be a possible thing, or something that we'll need to forbid?
it's possible for now, still debating the topic
The chaining feels nice for sure. If I didn't extend Container with the trivyScan, then I'd just make a scan function that took the container as an arg?
Personally I think a convenience for converting core types to custom specialized types (Container.AsX) would replace the need for full blown monkeypatching
also makes discovery easier. as<autocomplete>
When building a module, i was curious - has anyone thought about writing tests? Writing ci pipeline tests would be so cool imo (especially for writing reusable components).
I briefly did an experiment where a module came with its own tests, which was also helpful as an example: https://github.com/vito/daggerverse/blob/main/nix/nix.go#L46
@sharp zealot also make sure you pull again, there was another bug affecting shykes/dagger π
speaking of tests, it would be nice if every module had a test entrypoint, so I could just try running every module in the daggerverse as I'm making changes
I can do part of that now, but knowing what to run as a smoke-test requires module-specific knowledge
hehe you read my mind - i was imagining running the tests for a module on submission to daggerverse π
I'm still kind of curious to see if monkey-patching even becomes an issue... there's something kind of novel with the way modules and namespacing works right now. The only way you can run into conflicts is by directly depending on two modules that try to implement the same thing. Transitive dependencies aren't an issue at all, which is distinct from e.g. Ruby, which was a total wild-west
anecdotally - i found myself prefixing all my functions with the name of the module, or at least including it in there. Writing a function like InstallNpmDependencies (in an npm module) or HugoBuild (in a hugo module).
if we saw everyone doing that, i think it would make sense to enforce something like that explicitly, either with required name prefixes or using the .AsX
oh yeah, if someone adds a method just called 'Build' when really it's provider-specific, that's totally evil
yeah that pattern seemed intuitive for me with the Golang module too
I'm operating under the assumption that all developers are good and kind
and if they're not, no one should use their modules π
(I need caffeine...)
@thorn moat you're much more trusting than me π
there's a layer of sarcasm there. π My only point is that there's a balance to strike between what's enforced by patterns/convention and what's enforced by distrustful mechanisms
sometimes the arrow does go in the other direction though, e.g. if the mechanism prefixes all types/methods with the module name, the convention would become that people do short module names like Hugo or Go
yeah that pattern seemed intuitive for
I briefly did an experiment where a
Tried out an embedding pattern with Go: https://github.com/vito/dagger-gitutil/blob/main/main.go - interestingly, methods defined on GitUtil are also available through GitRepo in the API, so it works exactly how Go embedding works
@thorn moat, heads up, I'm going to push py mvp support.
looking forward to having more than one language in our cross-language module ecosystem π€©
No codegen yet. Just tested a simple function, will add more support as I go along.
No codegen means that it won't pick up new stuff from dependencies. You'd have to reach for the lower lever query builder for that.
It also means there's no dagger mod sync pre-req after changes.
I'm going to try publishing a simple python module to daggerverse to act as a template for others also.
sweet, I'll let you know when it's updated to the new API
it'll probably just fail until then
The first Python module: https://github.com/helderco/daggerverse/tree/main/hello-world
it's not quite published yet, but this is what I had in mind for general secrets interface:
func (v *Vault) Auth *Vault
func (v *Vault) GetSecret (string, error)
func (v *Vault) PutSecret (*Vault, error)
func (c *Container) WithVaultSecret (*Container, error)
(same in the AWS Secrets Manager module)
People seem to put their dagger modules into a single daggerverse repo at this point. Is that considered the best practice right now? Or it's just until Zenith is released?
I'd imagine testing and releasing modules is a bit more challenging this way.
That's what a few of us have been playing with but I wouldn't call it a best practice yet. Still tons of unknowns. I'd say do what feels right to you for your dev flow!
I'm in the one repo per module camp @latent trellis . Partially for reasons and partially to play the other side.
I may be jumping ahead, but how do you plan to release individual modules that way?
There are experiments happening around the repos structure for Zenith modules. A couple of popular patterns are: https://github.com/shykes/daggerverse https://github.com/kpenfound/dagger-modules wi...
I'd release it here: https://daggerverse.fly.dev/
@sharp zealot re: running codegen on-the-fly... One option: when ExperimentalPrivilegedNesting is true, we also mount a dagger CLI in to the container at /bin/dagger (
) . That way the runtime can literally just run dagger mod sync before building. Have we thought about something like this before? Having an automatically guaranteed-compatible dagger binary around for nesting seems like it could be useful, but I don't have a concrete in mind. The other option I was considering was to add codegen logic to the shim, which is doable but will take some elbow grease / hackery to tell the shim to do its thing.
Definitely seems useful in general. Like if you can use registry.dagger.io/dagger:v0.9.0 as your CI executor in the future
short of having a cli-only image
i'm sure there's some other nice things that come with the 
Oh you mean just having the CLI image available in the engine image?
Different topic, it's a prerequisite though. I'm talking about having Dagger automatically mount the CLI in for any WIthExecs that enable netsing
visible on light mode π
I think we even used to have the dagger CLI baked into the image and download it from the container in the SDK, but maybe we stopped doing that because it'd be awkward supporting all the different host-side platforms
But in this case it just has to be the same platform as the image
Could the codegen logic be in the runtime container?
Since eventually it will be SDK-specific anyway
Re: shipping dagger binary:
- Love the idea of shipping a
daggerbinary by default, in general - In the context of using that for codegen: assume that CLI syntax will change (
dagger mod syncmight not be a valid command in the future) so not sure if you want to depend on that CLI syntax for lower-level features
Oh yeah, I like that this gets us closer to pointing to an external SDK [possibly a module, modulo bootstrapping]
On the plus side, this is all running the same version, so we'd only have to adjust the syntax to match. (I don't think the dagger mod sync would end up anywhere permanent at the moment, but if it did, that's absolutely a problem)
I find it helpful to imagine everything Go-specific (or Python-specific etc) eventually bundled together in a module - ie. SDK-as-module
I could do the dagger mod sync thing as a shortcut for now (it took approx. 1 minute to implement), and we can move it into the runtime once we figure out what that looks like? Just trying to get Daggerverse updated ASAP without losing all the past stuff
("once we figure out what that looks like" could mean Monday)
It works! Just ran dagger mod use github.com/shykes/daggerverse/datetime@d16ecd28b133b2b0b0a8ed866fa0bc196fcc7427 π - transitive dependencies also worked. Nice to confirm we can move this responsibility to the runtime.
https://daggerverse.fly.dev/ updated! Watching it slowly index everything again now. That poor Firecracker VM. π
Yeah sounds great
Should we move to a beefier machine?
I think it's OK for now, it's just because I had to deploy the engine which blew away the cache. Maybe I should sign it up for Cloud? π
Yes you should!
done
Missing function argument description π https://daggerverse.fly.dev/mod/github.com/helderco/daggerverse/hello-world@15fd914516e6aac4ae1aa8d4430e9e1a4f185fe9
Did we reach a general recommendation from this morning for how to handle the case where caching swallows the output after first run for things like Solomons python datetime demo?
For now, each module is responsible for its own caching behavior. Sometimes that means allowing the caller to configure the caching behavior, with a custom argument.
For example, for my datetime module, instead of calling code(code: "import datetime; blbla") I would want to call code(cache: false, code: "import datetime; ")
PS that is a feature request @mossy hazel π
Under the hood, the way you disable cache is that you pass an input to WithExec (usually an environment variable) that changes each time you want caching disabled. We call that pattern "cache busting"
If you want caching to be disabled every time, you pass a random value
If you want it to be disabled once a week, you pass the current time, truncated to the beginning of the week
That's the pattern @thorn moat was alluding to
Then eventually we'll figure out how to incorporate this into the core API (but that will take more time)
This is great, thanks a lot for the info and pointers. I need to read up a bit more on how caching works in general.
and we really need a comprehensive guide of Dagger cachingβ¦
Since caching is at the function level, the cache: true would itself end up being cached, so the function needs to take a cache-buster directly atm
Done with my meetings for the day, I get 20mn of Daggerverse fun before school pickup π
@warped canyon I removed ./bin before running ./hack/dev, didn't run into the "killed" issue so far
(this is on the latest commit)
My mistake
So more like:
code(code: "....", cacheKey: "XXXX")
Yep. Tempting to put cache key generation into a module but ... it'd be cached
I guess you could always give it the current time + an interval to truncate
Does this mean there's no way for a function to decide that its own exec will never be cached?
I think I now understand what @kind carbon was saying π
Yeah - that's why we need some sort of explicit opt-out
(sorry for pinging you helder, please go back to bed π
You can sleep soundly knowing that you were right, as always
@thorn moat what if we added a core random call?
Then engine could trace back any dependencies on those values, and invalidate cache
... but if it's my function calling that random value dynamically, I guess it's still the same problem - I'll never get the chance to call it, I get cached before that
@thorn moat I have the latest commit, and dagger mod init still creates dagger.gen.go and querybuilder/, normal?
yeah - I haven't changed codegen yet, and it might still generate all that anyway just for local editing
so the main difference would be just adding them to a .gitignore
https://github.com/samalba/inline-python-mod/pull/1 -> indeed that gets cached (does not work)
then I don't see a workaround currently for bypassing the cache given functions are cached, maybe we could implement a "noCache" like in my example, but as a builtin, that bypasses the caching of the function and inject a llb.IgnoreCache (not sure of the name) so the cache would be disabled for all underlying operations
Only workaround is what @thorn moat suggested, take a cacheKey argument and I have to pass a random value
Better than the alternative which is for me to inject a random comment in my python code π
yes but good luck setting a random key from gql
yeah, I personally don't care about that because I'm calling your module from another module π But you're right that's not great
Ooooohhhh my own module will be cached too....
So I have to take a random cache key also don't I.... all the way back to the graphql client ...
I update the PR if you want to try: https://github.com/samalba/inline-python-mod/pull/1 - but still not convinced how to use it properly
at least it would work from the client side (not from another module), as soon as we have the query builder from native languages
btw, what if functions were not cached at all (by design)? The module output: go binary binary (or python pyc files) can be cached, but why the run? I think it causes more issues that it should. I guess it'd be slightly slower because of the grpc roundtrips, but given the buidlkit ops remain cached, I guess it would be more than acceptable without the side effects.
to cache or not to cache [by default], that is the question
What if the cache key is a Secret 
I was thinking about this morning's discussion of the Python SDK size wrt inline Python
There is a tiny Python runtime called Micropython which is popular in the IoT scene. Well, the PyScript project has recently looked into it because they run Python in the browser:
https://pyscript.net/tech-preview/micropython/about.html
I wonder if this may be a tactic for "bootstrapping" the python runtime for modules?
(possibly @mossy hazel or @kind carbon have already considered this...)
Another angle is Nuitka
https://www.nuitka.net/
the gentleman's python compiler.
With the Python compiler Nuitka you create protected binaries out of your Python source code.
Another possible "sqlite swiss army knife" is Simon's sqlite-utils which makes it easy to move data in and out of sqlite files https://sqlite-utils.datasette.io/en/stable/cli.html#cli-extract
How are modules intended to work/plugin with existing pipelines? watching the recent demo I didn't really see that mentioned, I suppose that falls into the dagger mod get calls? which somehow installs the module into my local pipeline project?
There's certainly optimizations that can be made to make python bootstrapping faster but I think any runtime that's temporary or different from the final one where user code will be run in will take longer to run. I do have some optimizations in mind but I'm focused on unlocking the base features first before improving performance.
I think the idea is that everything becomes a module. so you'd migrate your existing pipelines to a module, or multiple ones. If you want to mix anyway, you just need to start the Dagger Engine session with dagger listen but you'll still need to run codegen to get the extended API from the module you're depending on in the SDK's client, otherwise you'll need to drop to lower level API (GraphQL) calls. Using the underlying query builder is easier.
But you make a good point, we probably need to make this interop easy for folks that already have big pipelines and need to transition/experiment more gradually. However, it's good to remember that the existing pipeline code should remain mostly the same, just needs to be wrapped in a module function, while removing some boilerplate that's no longer needed for bootstrapping.
@kind carbon What's the easy way to get the Python linter happy when it's just formatting issues? https://github.com/dagger/dagger/actions/runs/6300990957/job/17105027698?pr=5757#step:4:706
@ember walrus I figured out why that Dagger Cloud visualization looked funny on the Zenith runs. It was a dagger listen session, and we made a bunch of runs from the browser, all in the same session π
Ohhh! That makes a lot of sense.
If we want to trigger runs or re-runs from a GUI, we have to figure out that flow for visualization based on one session. That is, what is the event?
The reliance on code-gen somewhat worries me here - esp. for say the Java SDK - which uses a precompiled sdk jar from Maven Central, adding in full code-gen would be somewhat messy, you'd almost have to have an entirely separate project just for the build (which almost defeats the purpose of a clean reusable module).
Maybe - I should look at building the zenith fork and experimenting.
@kind carbon has joined the league! 
@ocean escarp ππ
Hello everyone !
I just cloned the Zenith version of Dagger, I'll try to port some FluentCI pipelines (which are mainly written in TypeScript) into a Dagger module, but what if I want to write a module in Javascript/Typescript?
Exciting! NodeJS SDK has not been ported to Zenith yet, but @kind carbon started working on the Python port, and that will surely accelerate the development of more SDKs over the next few weeks.
Correct! The Go SDK is privileged since it's the same language as the CLI/Engine, but it's also harder to see the line. Through Python it should be much clearer on what's needed to make it work.
The reliance on code gen somewhat
I wanted to play with the zenith build but my company man-in-the-middle proxy striked again π
β [0.58s] ERROR exec go build -o /runtime -ldflags -s -d -w .
β go: downloading github.com/Khan/genqlient v0.6.0
β go: downloading github.com/99designs/gqlgen v0.17.31
β go: downloading golang.org/x/sync v0.3.0
β dagger.gen.go:15:2: github.com/Khan/genqlient@v0.6.0: Get "https://proxy.golang.org/github.com/%21khan/genqlie
β nt/@v/v0.6.0.zip": tls: failed to verify certificate: x509: certificate signed by unknown authority
β internal/querybuilder/marshal.go:11:2: github.com/99designs/gqlgen@v0.17.31: Get "https://proxy.golang.org/git
β hub.com/99designs/gqlgen/@v/v0.17.31.zip": tls: failed to verify certificate: x509: certificate signed by unkn
β own authority
β internal/querybuilder/marshal.go:12:2: golang.org/x/sync@v0.3.0: Get "https://proxy.golang.org/golang.org/x/sy
β nc/@v/v0.3.0.zip": tls: failed to verify certificate: x509: certificate signed by unknown authority
β»
I already has to manually patch internal/mage/util/util.go in order to handle that additional root CA in the ./hack/make commands
looks like we should expose that as a CLI flag?
I don't know how frequently this case occurs but it would be nice to be able to specify some additional CA certificates to inject into the base image
my patch (internal/mage/util/util.go) is quite ugly but does the job when building the CLI, engine and SDKs
func goBase(c *dagger.Client) *dagger.Container {
repo := RepositoryGoCodeOnly(c)
customCA := `-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIJANu+mC2Jt3uTMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYD
/// ...
pB5iDj2mUZH1T8lzYtuZy0ZPirxmtsk3135+CKNa2OCAhhFjE0xd
-----END CERTIFICATE-----`
return c.Container().
From(fmt.Sprintf("golang:%s-alpine%s", golangVersion, alpineVersion)).
// ...
WithNewFile("/etc/ssl/certs/customCA.pem", dagger.ContainerWithNewFileOpts{
Contents: customCA,
}).
WithExec([]string{"update-ca-certificates"}).
// ...
}
@sharp zealot suggested that I start by writing a Zenith module before trying my hand at an SDK. So I'd like to create a module that builds and deploys a NextJS app to kubernetes (possibly using a k8s module that already exists?) I already have a working Dagger pipeline(s) for this.
Are there some links to docs or videos about how to get up and running?
In https://daggerverse.fly.dev, follow the link "what's a module?".
@thorn moat, are you working on putting the codegen in the runtime yet?
@kind carbon yeah, I'm spiking on module-izing the Go SDK at the moment, it's going well but there are definitely fun bootstrapping problems to sort out
let me push what I have to a branch
I'm trying to suss out whether we can land this pre-merge, because right now the on-the-fly dagger mod sync is super hacky (I've had to add a bogus cache-buster)
Yeah, that approach seems ideal, but I've been wondering if it's too soon (without a stable release) because of a possible chicken & egg situation.
Was just about to ask about how you connect with mod sync for example π
by 'that approach' you mean on-the-fly codegen, or modular-izing SDKs?
Putting it in a module
yeah, the nice thing is we at least have a comfortable way out: once you bootstrap a pre-built image with the /runtime entrypoint, theoretically you just push that to registry.dagger.io, and have sdk: go mean registry.dagger.io/sdk/go or something
Because that gives you the higher level client. The current runtimes use the core functions which are a bit harder to work with.
I ended up going down this route because otherwise it's really hard to get just the codegen code and the SDK code into goRuntime(); they're split across the codebase, and in separate Go modules
And there's stuff like progSock and buildkit client that I don't know how to get from generator.Generate
to answer this, it's regular old Dagger-in-Dagger, and the nice thing is it's already running against the correct "module schema view" with all the dependencies loaded, so it literally just needs to fetch the schema => codegen
that's how the current hacky dagger mod sync-in-goruntime approach works, I think this modularized flow can work the same way but not sure yet
I'm going to take a moment to analyze your changes and see how it can work for Python. Brb with questions π
Sounds good! I'll let you know when it actually works. π
"regular old dagger-in-dagger" made me laugh. 10 years later Docker-in-docker is still a nightmare. We basically just solved nesting on day one.
Anything fun cooking in the daggerverse today? Me I'm trying to polish my new supergit module, hoping to help @vivid hatch and @visual blaze solve their git LFS problem with that
Also would love to get that nightly build going, so we can simplify the README (download a binary instead of building from source)
Yay!!! πͺπͺπͺ
I also would love a volunteer to work on dagger do, I think we could ship a simple version VERY EASILY, there is no need to introspect the graphql schema - just build a query
I think the function caching issue may be more urgent than I initially thought...
FYI @thorn moat @chrome pilot @kind carbon π I know you guys are busy with other things, just want to make sure it's on your radar.
@kind carbon Just successfully bootstrapped, tests all pass. π€― Now to kick the tires and clean things up / make sense of how this all works... I'll push the code as-is if you want to see how it works in the meantime.
This is SDK-as-module?
yup
Awesome! π Yes please push. Not entirely clear on that first bootstrap yet.
@kind carbon here you go (this is the only commit since last time): https://github.com/vito/dagger/commit/3e0c29950275c6936e8e2506a5b5d8bd2735c129
Yes, please!!!!!
I'm probably missing something obvious, but I give up at this point. :/
I'll give it a try again tomorrow.
@latent trellis what's the symptom? I can try to reproduce
Error: make request: input:5: Cannot query field "bats" on type "Directory".
It doesn't show up here either: https://daggerverse.fly.dev/mod/github.com/sagikazarmark/daggerverse/bats@6ac2eba8e4d4854e432154da50a926e485d161c8
I reference the Directory type as an argument and a return type
Tried to follow these examples:
How do you test modules anyway? I just checked out my repo into the zenith directory π
You have a few options
echo <GRAPHQLQUERY> | dagger query [-m MODULE]
dagger query [-m MODULE] --doc PATH/TO/GRAPHQLDOC.gql
dagger listen [-m MODULE] --allow-corsthen point a graphql web client at it π I'm looking at your module from an interactive graphql sandbox right now
dagger listen --focus=false --allow-cors -m github.com/sagikazarmark/daggerverse/bats
That does seem a bit cumbersome while you are developing modules. It means you have to push every change you want to test
But then you need to manually set the env vars from .envrc?
Personally my setup is:
- Initial setup:
- Develop all my modules in ~/dev/shykes/daggerverse`
- I have the special "use zenith version of dagger" envrc file in ~/dev/shykes/daggerverse/.envrc`
- Module dev loop:
- CD to my module of choice, write code, run
dagger queryordagger listen - rinse repeat
exploring your module
Makes sense
Does this work for you as well?
package main
import (
"context"
)
type Bats struct{}
func (m *Bats) Bats(ctx context.Context, dir *Directory, args []string) (*Container, error) {
return run(dir, args), nil
}
func (m *Bats) Foo(ctx context.Context) (*Directory, error) {
return nil, nil
}
func (dir *Directory) Bats(ctx context.Context, args []string) (*Container, error) {
return run(dir, args), nil
}
func run(dir *Directory, args []string) *Container {
return image().
WithMountedDirectory("/src", dir).
WithWorkdir("/src").
WithExec(args)
}
func image() *Container {
return dag.
Container().
From("bats/bats:v1.10.0")
}
Here is the code
HEADS UP, I pushed a stopgap to disable excessive memoization of function calls, by injecting a cachebuster at runtime exec. It seems to work, and it's a very small patch, but I won't claim to fully understand the codebase I patched, so it's possible that I broke something horribly.
When you read this, could you please try pulling the latest version, and testing it?
Thank you!
The commit for reference: https://github.com/shykes/dagger/commit/d07fbb4a35de48350715a2c16c2b97fe2a9a03fb
I'm going to take this on today.
As you've started a quick fix I'll do dagger do first, but I can take on the caching issue afterwards. I'm taking a step back from python to avoid crossing wires with @thorn moat and let him focus on finishing the refactoring around codegen-in-runtime that's essential for non-Go SDKs.
Will Go SDK modules always require the package to be main?
I would say we're still in the baking phase, so any suggestions for DX improvements are worth making
It seems like the introspection, regardless of the package name, requires that we put our Dagger files in a dedicated directory? Perhaps this is the same across all SDK modules?
Today, I have makefiles and Dockerfiles intermixed with my code, does this mean I need to have a dedicated directory going forward?
disable crippling memoization Β· shykes/d...
you can have a dagger module anywhere, in a dedicated repo or embedded in your app repo. Dagger doesnβt care. Any files that are inside the moduleβs directory (marked by dagger.json) will be copied into the module build, and available to the moduleβs functions at runtime. Up to you if thatβs what you want or not
Heads up: MERGING! Not zenith-functions into main, sorry for the clickbait. π I'm merging the sdk-modules branch (https://discord.com/channels/707636530424053791/1156327297796800573) into zenith-functions. It seems solid enough to not be a branch-of-a-branch now.
This means anyone can build their own SDK externally - as a module! Here's the Go SDK's "runtime module" which implements the codegen and container building + running logic: https://github.com/shykes/dagger/blob/zenith-functions/sdk/go/runtime/main.go - and here's how it bootstraps (builds the runtime module image using its own module): https://github.com/shykes/dagger/blob/zenith-functions/sdk/go/cmd/bootstrap/main.go
This is very much an ad-hoc internal API at the moment, lots of bikeshedding to do. But the capability is there now. This replaces the hacky implementation of just-in-time codegen from before, where the hardcoded Go runtime ran a bind-mounted dagger mod sync, which became a problem because its cache never busted. Now the SDK's runtime just runs its own codegen.
You'll start seeing "sdkRuntime": "vito/dagger-sdk-go:multi@sha256:..." show up in your dagger.json files, since this works by having modules pin their runtime image at code generation time. The idea is this would eventually point to something on registry.dagger.io. π
You can change it to whatever you want, just be sure to remove the "sdk" field, since all it does is tell the CLI to sync to the current ref for that well-known name.
@thorn moat how should we change our mod dev workflows?
No change to workflow, you'll just notice that extra sdkRuntime field I mentioned on your next dagger mod sync
oh I see. so go gets resolved by mod init and never makes it into dagger.json?
Right now they're both there, so future mod syncs can bump the sdkRuntime to whatever the CLI points to for the configured sdk ("go")
Thinking about cache controls...
At first I was thinking: what if a function could have a companion "cache helper" function which takes the same arguments, and returns a string? Just before the engine calls the real function, it first calls the cache helper (always uncached), receives a fresh cache key, and adds it to the real function exec. "Always cache" can be implemented as a function that returns a constant cache key; "Never cache" helper returns a random value; "TTL" helper returns current time truncated in various ways; etc. Pretty neat.
But then I thought: gosh how will this cache helper function be registered? And writing two functions with exactly the same arguments seems repetitive and error-prone. How do I get this awesome pattern without making the DX worse?
And now I am thinking: what if instead of a helper function, we added a core function dag.CacheMe(key string) which any function could call at any time. Calling CacheMe results in the calling function being terminated (insert buildkit magic handwaving here), then called again with the same arguments, but this time with caching enabled, using the specified cache key as a cache buster....
This would actually solve a major problem that has plagued Dockerfiles since the dawn of time: caching of linux packages
For example, installing a Wolfi Linux package:
query {
wolfi {
container {
withPackage(name: "git") {
...
}
}
}
}
The withPackage function could:
- start by querying the wolfi repositories for the latest digest (or if not available, version number) of the specified package.
- call
CacheMe(packageDigest) - do the expensive work of downloading and installing the package
The example query would result in WithPackage being called twice in a row:
- First call, with random cache key: at step 2,
CacheMe()terminates the function - Second call, with package digest as cache key: either we get a cache hit (yay!) or we go all the way:
CacheMe()does not terminate the function, step 3 does the work. Next time we will get a hit!
Boom, distro-aware caching with minimal plumbing
This could also solve the caching issues which have plagued deployment functions:
- Do I always cache, and break rollback deployments? ("you have already deployed this version of the app in the past, so I will never deploy it again!")
- Or do I never cache, and add 3-30 seconds to every run?
Now we have an answer, if the deployment target has a way to query the current deployed state. I believe most modern services that you can send artifacts to, have a way of telling you the version or digest of what they've received. Assuming that, the deployment function can use the same pattern to query the deployment digest, call CacheMe(deploymentDigest) then continue to the usual deployment logic.
Functions that want to set their own TTL to 24h: dag.CacheMeTTL(1000 * 60 * 24) or dag.CacheMe(CacheMeOpts{TTL: 1000 * 60 * 24}) (just a convenience)
Okay, bats module works, do I get that module builder badge? π
Also, a question related to that same module: how do I "extend" a container encapsulated by a module?
In this specific scenario, the bats module uses a prebuilt image to run bats (a shell based testing framework). However, there may be dependencies I need to install into the image (eg. using apk or mounting binaries).
What's the best way to do that?
I could build my own API using With* style functions, but that would lead to duplicating parts of the Container API.
Any thoughts?
Ideally, I need to "inject" something between the final exec and the initialization of the container:
func (m *Bats) Bats(ctx context.Context, d *Directory, args []string) (*Container, error) {
ctr := dag.
Container().
From("bats/bats:v1.10.0")
// mount and install binaries here...from outside of the module?
ctr.Exec([]string{"bats"})
}
@thorn moat, have you tried making a function call via the API? With Function.call?
I tried this yesterday and it didn't seem to work, but I was in the thick of it and didn't make note of it. Guessing you're seeing the same?
Yes. There's no code using it. ParentName, Parent and Module are said to be internal, but when called via the API they're empty which makes the module register the functions instead of invoking one.
ha right - I kept getting a core.Module ID back instead of what I wanted
yeah, I think it just needs to be updated now that there are multiple objects exposed by a module, rather than a flat set of functions
ParentName shouldn't be needed at the API level, since the function already comes from an object type, so that should be known already
but you'll probably need a way to pass the Parent I suppose?
Module is probably also internal optimization, since it already has that (in ID form)
not sure if this helps you at all but I ended up just running a GraphQL query instead, which worked out much more nicely
oh is this for dagger do?
Yep π re: dagger do
Maybe core.Function should have a field for the parent object?
I think it makes sense to pass it at call time, in the spirit of the receiving object just being a special kind of argument
I meant when you register with dag.TypeDef().WithObject("MyModule").WithFunction("MyFunction"), a core.Function instance should know it's a part of the MyModule type.
Here you go ππ₯
I've started a little experiment with deno here https://github.com/shykes/dagger/pull/124 π§ͺ
Thanks π
fyi: I just got rid of WARNING: Using development engine; skipping version compatibility check. - it was starting to swarm the output. Disabled the call internally in a couple of places where it's guaranteed to be compatible (engine dialing itself), and then switched it to debug level for the remaining spots. Doesn't seem worth the noise with all the nesting.
The remaining calls are during on-the-fly codegen, where it makes sense to do a compatibilty check (SDK runtime could be out of date if you're not using an auto-synced one)
Function.call
Any thoughts on this? Iβm pretty sure customsing containers encapsulated in modules is going to be a common issue
Iβm going to give the With* pattern a try
if you check out https://daggerverse.fly.dev/mod/github.com/samalba/inline-python-mod it has a WithContainer function, I like that pattern but maybe there are others
Yeah makes sense. I was looking for a way to add βextensionsβ to an existing container, but thatβs probably more work than itβs worth.
Creating a new container from an existing base image is two lines of code
the nice thing is that you can choose your own adventure π
Yeah well I hope patterns will emerge at some point to help adoption in the community.
Sometimes I need to remind myself that Zenith is not even released yet but Iβm already talking about patterns and adoption πππ
@sharp zealot before I forget (flying out tonight btw βοΈ): I think we'll need to namespace types provided by modules. Something simple like ModuleName_TypeName should be fine, and impossible to fool since we normalize on CamelCase. Right now it's super natural to define a type like Foo thinking it lives purely within your module, but really it's just as global as Container. (There's an interesting follow-up that perhaps that should become ModuleName_Container, which ties back to wrapping, which ties back to whether we support monkey-patching, etc.)
@warped canyon btw, as a side effect of SDKs-as-modules you shouldn't be having any go issues anymore, if you want to go back to goenv
now the only go that ever runs is the one baked into the module
@thorn moat humble request: please read my cache control monologue so you can noodle on it on the flight ππ
re-read it this morning and still love it
really hoping itβs not fatally flawed
will do! I skimmed it this morning but haven't fully processed it yet, trying to put some finishing touches on the sdk-modules stuff before I take off. It's a red-eye flight though so no promises π
the gang solves cache invalidation
What if we shipped a stable release quickly (as in within the next few days) that only adds a hidden command:
dagger experimental zenith [-o PATH] [--arch amd64|arm64] [--os darwin|linux|windows] [--GIT_BRANCH] [--remote GIT_REMOTE]
Usage: Download a build of the "zenith" development branch of Dagger. This branch features a cross-language component system, new APIs, and new command-line UX. Learn more at ...
In practice we just need to hardcode a dagger pipeline that builds zenith.
This might be easier than maintaining a semi-official release infrastructure. Also less work for the infrastructure crew. We can piggy back on the infra we have.
My two cents
- If I demo zenith, it should be something easy for people to try. It took me some time to learn, but cloning a repo and running a custom build does not count as easy for a lot of people. Downloading a single binary and running a single command is the most effort a lot of people will do.
- Demonstrating something that already runs in CI (even if a PR) projects way more confidence and stability than a custom build I run locally.
So as soon as there is any kind of nightly build, I'm gonna switch all my dagger pipelines to Zenith.
I don't even care if it breaks from time to time: if I can pin to a single commit/version, I'm happy.
That...does not seem to work right now...
@latent trellis obviously we want to get this merged (behind an experimental flag) as soon as possible, so even a nightly build won't be necessary. We're just looking for short term stopgaps until then - probably 2 weeks max before we merge IMO
(ok maybe more because of upcoming travel)
or maybe less because of ambient awesomeness
Well, obviously timing depends on a lot of factors.
I just wanted to share some outside perspective. Like I'm demoing Dagger the week after next and if I tell people to run more than 2 commands, probably most of them won't. But if zenith is that close to being released, it probably doesn't make sense to start releasing nightly versions.
@thorn moat I'm getting error on dagger mod sync with latest commit
-cvs flag is missing
Oh oops
Need to fix the go sdk module, I removed that flag
I can fix once I'm waiting at the gate if you don't wanna try to solve the puzzle π
I'm also getting a super weird error where an apparently straightforward type somehow doesn't make it to the graphql schema? But doesn't seem related to the last commit
@thorn moat it's no rush, I'm winding down for now anyway
Do you have any hunch as to why this would not make it into the gql schema?
type RemoteTag struct {
Name string `json:"name"`
Commit string `json:"commit"`
}
I tried changing the name to 10 different hingd
Might need to define a function on it
If you liked it then you should have put a function on it
oh right!!!!
GG @sharp zealot, you just advanced to level 2!
Sorry, this request does not comply with MEE6 content policy. Modify it and try again.
@sharp zealot fixed the --vcs thing
@latent trellis perhaps you can grab your Zenith Dagger binary from here? https://github.com/jpadams/shykes-dagger-zenith-builder/releases
Zenith builds, courtesy of Zenith 
What do you think of this Dagger module structure (for Deno/NodeJS)?
If I've understood correctly, a Dagger module exports functions that will be imported and executed in Dagger by a runtime.
So my idea for Deno/NodeJS Dagger modules is to also write a GraphQL schema (whose resolvers are the module's functions) using https://nexusjs.org/, which will also be imported by the runtime.
In this way, the runtime will execute the module's GraphQL schema, which will then execute the module's functions.
Thanks Jeremy!
Would be nice if nightly tags were unique (eg. include a timestamp). π
Service port check does not seem to work locally for me from this build, but it seems to work in CI which is...weird:
Itβs true that in an earlier iteration of API βextensionsβ, SDKβs used to save the moduleβs GraphQL schema in a file in the runtime container, but in Zenith this evolved into simply the SDK querying special client API fields (should be used only by SDKs) to:
- Check if it needs o register functions or invoke one (registration == empty function name);
- Register functions, including arguments that they support and return types;
- Get the context for a function call (parent value and arguments);
- Return results back;
So the API server simply executes the runtimeβs entrypoint at appropriate times, but itβs these API fields that extend the overall API schema server-side when theyβre called.
@ocean escarp π
Not sure if you can share your Deno /NodeJS progress with us on the call π
Sorry, I had to leave to take my wife from work, maybe I'll share another time
See #1156953837064699975. Been working through some issues after latest pull, but I'm adding argument support. It can list and run top-level functions.
awesome. will play with it π
Iβm most impatient for directory arguments π
And directory/file returns? π
Via dagger download, sure
different verbs for different handling of the output π
Ah, but shouldn't we keep one new cli command for now? And if so, which kinds of arg types and return types should dagger call support?
I just assume call is a throaway prototype, we look at it together and decide together on that level of polish
so not really worried about what it does or doesnβt do
Iβm looking for the thread where we started listing possible verbs, but of course canβt find itβ¦
Yep, I'm thinking just ignore functions that don't match what's supported and expand over time.
yes but different verbs are not about supporting different function signatures theyβre about matching user intent. hold on let me find that thread
Iβm especially excited about dagger shell π
better than eg dagger call --shell I think
I did a zenith oopsie and I was super lost, so here's my story
I called an argument to one of my functions os string, which in codegen collided with the os package and failed to codegen.
The error just looked like this:
Error: failed to get codegen output entries: input:1: host.directory.asModule failed to call module to get functions: failed to get function output directory: process "go build -o /runtime -ldflags -s -d -w ." did not complete successfully: exit code: 1
but when I ran with --progress=plain I was able to see a bit more detail:
./dagger.gen.go:4375:8: os.Exit undefined (type string has no field or method Exit)
Renaming my argument from os to operatingSystem fixed it
Exactly the same reason this field is not called OS π https://github.com/shykes/daggerverse/blob/main/dagger/engine.go#L42
I figured as much lol
Here's that module I was talking about: https://daggerverse.fly.dev/mod/github.com/kpenfound/dagger-modules/zenith@14c975c71a32f872692018e143a20b1518edc84a
So now you can run:
echo '{ zenith { update(repo: "$DOCKERHUB_USERNAME", operatingSystem: "darwin") { export(path:"./daggerz")} }}' | dagger query -m github.com/kpenfound/dagger-modules/zenith
To get an updated zenith engine pushed to your dockerhub and an updated CLI dropped at ./daggerz. No ./hack/dev, no downloading from github, no quarantine dance
I am trying this time.Now()
oh yeah no more worring about docker rmi or docker pull either, it's versioned π
here's the versioning change https://github.com/shykes/daggerverse/pull/3
Oh, does that need to be merged for the above to work?
Nope, it's pointed to my fork right now. Modules π
oh replace $DOCKERHUB_USERNAME with your dockerhub username. Sorry, that's in the readme but I didn't put that here
lol, I set an env var
yeah my example was single quoted though π
I refuse to alter my workflow π
echo '{ zenith { update(repo: "'$DOCKERHUB_USERNAME'", operatingSystem: "darwin") { export(path:"./daggerz")} }}' | ~/dagger-z query -m github.com/kpenfound/dagger-modules/zenith
hmmm...we have ===, maybe I need triple quotes!
π how about swap the single quotes for doubles and escape the inner quotes
./daggerz version dagger v0.0.1696015539 (jeremyatdockerhub/dagger-zenith-engine) darwin/arm64
Success!
./daggerz query -m github.com/shykes/daggerverse/helloWorld<<EOF
{
helloWorld {
message
withName(name: "Mundo") {
withGreeting(greeting: "Bom dia") {
message
}
}
}
}
EOF
@warped canyon good compromise
is arch optional?
right now it uses runtime.GOARCH, so it'll always be whatever your arch is. I figured if we wanted to wrap more of the nightly build workflow that would be a different function
You would think so, but I think that would result in linux 100% of the time since it's running in a linux container
I didn't try it, but i'm pretty sure
Hmmm...what's up with dagger mod init right now?
What are you seeing? works on my machine
zenith-macos-arm64 β€ ~/daggerz mod init name=zenith-macos-arm64 sdk=go
β’ Engine: 3b64fe6a44e8 (version v0.0.1696015539)
β§ 4.54s β 8 β 1
Error: failed to get codegen output entries: input:1: host.directory.asModule failed to create module from config: failed to get runtime: failed to load sdk module: module "" has no SDKRuntime; you may need to run dagger mod sync
lol
need some better error messages and better flag input by me --name=
working with correct invocation
~/daggerz mod init --name=zenith-macos-arm64 --sdk=go
now trying
./daggerz mod use github.com/kpenfound/dagger-modules/zenith
WARNING: Dagger engine version (0.0.1696015539) is older than the SDK's required version (
0.8.7). Please update your Dagger CLI.
WARNING: Dagger engine version (0.0.1696015539) is older than the SDK's required version (
0.8.7). Please update your Dagger CLI.
WARNING: Dagger engine version (0.0.1696015539) is older than the SDK's required version (
0.8.7). Please update your Dagger CLI.
WARNING: Dagger engine version (0.0.1696015539) is older than the SDK's required version (
0.8.7). Please update your Dagger CLI.
WARNING: Dagger engine version (0.0.1696015539) is older than the SDK's required version (
0.8.7). Please update your Dagger CLI.
β’ Engine: 3b64fe6a44e8 (version v0.0.1696015539)
β§ 37.24s β 432 β
24
zenith-macos-arm64 β€ cat dagger.json
{
"name": "zenith-macos-arm64",
"sdk": "go",
"sdkRuntime": "vito/dagger-sdk-go:no-vcs-flag@sha256:0fcc9d2659cdd551acb7aaf25e77215e9687475eb89ec06cae989eaf332ee480",
"dependencies": [
"github.com/kpenfound/dagger-modules/zenith@14c975c71a32f872692018e143a20b1518edc84a"
]
}
seems okay
Yeah I think the warnings are a side effect of my module not building a dev engine, but it should be ok
yep. Gonna drop the arm64 from my mod name since the arch is handled by your mod
~/daggerz mod sync doesn't seem happy. Guess you can't use that?
I wanted the Intellisense for my VScode
It's because I renamed the module in the dagger.json only and missed a reference to the old name in a go.mod it seems.
Started over fresh and I'm π
Here's my first working Dagger Module in Deno, inspired by @kind carbon 's Python example
@sharp zealot it looks like https://github.com/shykes/daggerverse/commit/e5eee9dac12b45bbebd30027c461ac2b01bbb568 (October 3, 2023 15:52 UTC+1) broke https://github.com/jpadams/shykes-dagger-zenith-builder/actions/runs/6394835968 (October 3, 2023 16:04 UTC+1). I'll take a look at what changed when I have a chance.
Maybe this?
./engine.go:45:13: dag.Tailscale undefined (type *Client has no field or method Tailscale)
Perhaps the published version of daggerverse/dagger needs to dagger mod use https://daggerverse.fly.dev/mod/github.com/shykes/daggerverse/tailscale ?
Catching up... Yes it looks like I didn't push the new dagger.json. With all the generated files lying around, I end up doing git add *.go which is what caused this (feature request, it would be cool to no longer drop the generated files in the repo by default unless I explicitly ask for them)
also makes it hard to diff
@wintry prism let me move the code out, into a separate module
it's experimental anyway (and won't even work without a patch of the zenith build)
@wintry prism can you give @strong ingot, @deft rain and me admin access to that repo?
Starting a thread to prepare the technical side of the Paris hackathon and demos π
Invites sent!
We're en route to Devoxx Morocco, so our wifi might be a little spotty. Luckily found this hotspot on the way. Don't worry, our dromadaires can carry their weight in Zenith. Plenty for all.
CI is π Thank you!
@wintry prism now that we have admin access, we should be good, enjoy your vacation!
@ocean escarp I'm very curious to learn more about your experiments with a JS SDK π
I copied the node sdk to adapt it to deno, you can see my branch here https://github.com/tsirysndr/dagger/blob/zenith-functions/sdk/deno/ , I added the entrypoint for the runtime https://github.com/tsirysndr/dagger/blob/zenith-functions/sdk/deno/src/ext/cli.ts which will import the dagger module in typescript and execute the dagger functions.
Starting a thread for feedback on your Node/Go/Python modules @upbeat herald
That is awesome!
So this is basically a Deno SDK for Zenith @ocean escarp ? Any thoughts on the experience so far?
Yes, that's correct! It's been an interesting and fulfilling experience, the way you've thought about dagger modules is great!
I've seen that you use codegen in dagger modules in Go, in my case I didn't use codegen, when/for which language is it necessary?
It should be necessary for every SDK otherwise you can't use the high level (generated) client to talk to dependencies, having to revert to lower level GraphQL calls.
However, the way that's done is in flux. There's a recent change that makes SDKs as modules, declaring functions for making a runtime container and for codegen, but we need to improve on how that's implemented. Currently only working for Go.
small note on sdk-as-module: the init template should be sdk-specific also (or is it already?)
Not a part of the module yet, but yes that's the idea.
I believe this is the case already, since it happens as part of regular codegen
oh I see, only one codegen function, that checks if main.go exists or not?
yup, it generates it if there were no *.go files to begin with - https://github.com/shykes/dagger/blob/zenith-functions/sdk/go/codegen/generator/go/generator.go#L80-L88
@kind carbon any chance we could add arguments dagger call? π
I used it today and it works great btw
Yeah, I started working on that by the end of yesterday, I'll continue on it in a few minutes.
It would be really nice to have a common query notation for expressing a chain of function calls (with arguments), then standardize its use across several verbs in the CLI
Current state:
dagger call: function name as subcommand, space-separated (?), max depth 1, no argsdagger shell: raw graphql, any depth, any argsdagger serve: function chain as dot-separated chain, any depth, no args
The base for dagger call is going to be used for other verbs, including shell, which I planned on adding first. So the usage should be consistent whatever that'll look like.
@kind carbon yeah that's what I was thinking. But dagger serve (hackathon project by @thorn moat and @strong ingot ) has an alternative notation (dot-separate call chain) so at some point we need to agree on a design for that notation or we'll have parallel implementations
Same thing, yes.
Or, if we want we keep the alternative implementations going a bit longer, to experiment
The dotted notation was actually by first intent with dagger call. I gave the idea not knowing that's what was being used in serve. I pulled back from that idea though.
Things to agree on:
- Space-separated or dot-separated chains?
- How to encode arguments?
- other?
There was already a bit discussion about that in the prototype, let me pull the findings from @rocky harbor.
Yeah I remember that. Strong preference for space-separated in the first iteration unless it's specifically harder
And strong preference for implementing directory-type arguments first, our friend @wheat crypt is making his first module and it literally cannot work if he can't pass a local directory to it
We're trying manual stitching by copy-pasting the ID of a host.directory() query, but I don't know if that will work since IDs I believe are no longer reliably cross-session?
At the moment, top-level functions with directory arguments are the "fall off a cliff" point
Any idea on how to fix this? #1153780921573593148
Heads up meetup starts in 90mn, so if you have any improvements to the CLI experience that are worth showing, make sure to push them in the next 45mn and notify us here, otherwise we won't be able to show them today
404 for me
Oh, maybe we don't support returning []string ?
let me push the module for a repro
@thorn moat could you try this?
echo '{dagger{engine{versions}}}' | dagger query -m github.com/shykes/daggerverse/dagger
trying now (gotta do a quick hack/dev, zenith-functions i presume)
oh dear
something tells me this is not the goal
this was after a ton of cached vertices. not supporting []string seems like a good guess
I don't think that's the problem actually. In supergit I have a method that returns an array of struct, and it works fine
There are cached vertices but if you look at the output, there are recurring error messages too
More visible in progress=plain:
[snip]
: > in init
1: > in init
1: starting engine [0.00s]
1: starting session [0.16s]
1: [0.00s] Failed to connect; retrying... name:"error" value:"make request: Post \"http://dagger/query\": rpc error: code = Unknown desc = failed to verify client: client ID \"ayd8sb7yp9hq4bc4y9xo4nkm1\" not registered"
1: [0.16s] OK!
1: connect DONE
154: exec /runtime /bin/sh DONE
154: exec /runtime /bin/sh DONE
[snip]
besides the usual 'Failed to connect ... retry ... OK!' loop?
oh, yeah that's normal, we can tidy it up, but without revealing it the alternative was hanging for 5 mins
maybe we can stretch out the OK! to OOOOOOOOOOOOOOOOOOOOOOOOKAY! or something 
echo '{supergit{remote(url:"https://github.com/dagger/dagger"){tags{name}}}}' | dagger query -m github.com/shykes/daggerverse/supergit
@sharp zealot i think this might come down to a codegen bug we've been working around for a while, related to returning lists of objects. Here's the workaround:
funcs, _ := foo.Functions(ctx) // or any call that returns [Foo!]!
for _, function := range funcs {
// TODO: workaround bug in codegen
funcID, err := function.ID(ctx)
if err != nil {
return fmt.Errorf("failed to get function id: %w", err)
}
function = *dag.Function(funcID)
if err != nil {
return err
}
funcName, err := function.Name(ctx)
if err != nil {
return fmt.Errorf("failed to get function name: %w", err)
}
// ...
}
if you grep for 'workaround bug in codegen' you'll see it in a few spots π
Would that also explain error on returning []string ?
returning []string is fine, looking at the code yours is blowing up while building that slice up from a []*Tag: https://github.com/shykes/daggerverse/blob/aff33add463c122d2932fcef317d04d5e2ca317e/dagger/engine.go#L46
so that's where the workaround would need to be implemented
@thorn moat @rocky harbor sorry wrong thread earlier. I meant that importing multiple modules currently breaks
Ah right, yeah that's on the TODO list accumulated during the hackathon. I think the problem is just in the CLI so not too much to fix
I'm currently checking to see what we have left before we can press the merge button, was planning on making all those TODOs follow ups
i think there's some issue deep in module resolution too sadly π¦
i've been chasing after it all day, somehow we mix up the modules? and start assigning functions to the wrong ones.
solomon i think this might come down to
Oh interesting, I'm fairly certain it worked at some point on this branch...
yeah, me too π¦ if you have a moment, i could show in the audio channel? i'm kinda unsure how to keep debugging it
Does 20 mins from now work for you?
there now π
created a case where we expect to fail: https://github.com/jedevc/dagger/commit/d7263ea3f12247e2e4e10b338ab3f50c370c4ef5 (cc @rocky harbor @thorn moat) π’
@deft rain thanks! I'm writing up an integration test now, will use this as a reference
tl;dr - we attempt to load module bar and accidentally somehow load Foo in it (despite Foo being part of foo and not bar) - this seems to result in fun cases, like duplicate or non-existent schemas π
@thorn moat @deft rain looks like this may be one case where linting fails because we don't commit generated files: https://github.com/dagger/dagger/actions/runs/6471664732/job/17570586921?pr=5757#step:4:135
Is it the case that it's okay to commit those files, just not required? If so, I'll just do that. That seems like probably the desirable behavior in general anyways
It's OK to commit them, but they might get pruned back out and re-.gitignored next time you run dagger mod sync (it's pretty aggressive atm). Now I'm worried this will be a common thing for module devs that are using off-the-shelf linting setups. Committing code to get around that kind of defeats the point
Agreed, or just code analysis tools in general
It's weird too because if you just say 'oh linters should run go generate first' that's getting around something linters are often checking for too (forgetting to re-gen code)

When is this going work for real!? π
can we mitigate this once we switch our ci to use zenith? once that's done, we can just add the codegen before doing linting quite easily right π
it works for real, you just need to start your engine locally with DAGGER_SESSION_TOKEN=daggerverse ./bin/dagger listen --allow-cors --progress=plain
that playground connects to your local engine. @hallow gust is adding a friendly message to communicate that
trying now! Thanks @dense canyon !
linting with not-committed autogen code
Niiice
Interesing that I couldn't find my Trivy module on the list in the Playground...but it loads from https://daggerverse.fly.dev/mod/github.com/jpadams/dagger-module-trivy@5eb6c69ea7a110d25399beec6e1a979889b7261c
might be that the list has a limit
Actually it's here:
Just no title
fyi @hallow gust π
Hmm, I'll take a look, but it seems like it might be declared differently at first glance?
I'm travelling right now, will take a proper look in ~30min
It works fine though
I know what the issue is Juli. That module doesn't have a SubPath and we're assuming all of the have. It's a minor fix Jeremy, we'll fix it in a bit
Going to push a fix to fallback to the Path if Subpath is not available. Extracting the module from the URL seems a bit too much IMO. wdyt @dense canyon ?
it's tricky because the refs table in the DB doesn't actually store the module name. Maybe we could add it here? @thorn moat WDYT?
@dense canyon so is this because right now it's taking subPath and guessing that it matches the module name?
yes, pretty much since we don't have the module name in the DB
and we're using the subpath as the module name
maybe it should be using an API backed by (*dagdb.DB).All instead, which loads the "hydrated" Module struct, which has the name and various other info
at least until we put on our big boy pants and figure out how to model persistence, I like keeping refs as the source of truth with the smallest amount of info needed to bootstrap everything else
SGTM! does that mean that All will try to hydrate modules each time the endpoint is called?
All only returns already-loaded modules, so anything stuck loading will be excluded, and it won't force any loading
got it. I guess we can use that, yes
I won't make any changes now to avoid brining down daggerverse for a bit since deploying it has downtimes
multiple modules
linting woes
Found a blog post that feels like it was written for us https://xuorig.medium.com/on-graphql-schema-stitching-api-gateways-5dcb579fa90f (cc @rocky harbor)
I pushed my first module : https://daggerverse.fly.dev/mod/github.com/jcsirot/daggerverse/java
Setup a JDK & Maven dev environment
I managed to fix the readthedocs build (turns out the service itself made a backwards incompatible change a few days ago): https://github.com/dagger/dagger/pull/5757#issuecomment-1756247816
So I just went ahead and pressed the beautiful green merge button. Let me know if anything terrible happens! π π€
10 Authors! New record! 
Woooo! nice work π
@rocky harbor we should probably find somewhere to track the little collection of issues me and you stuck in the pr comments during the hackathon π
Yes! Eating lunch, was gonna convert those over right after π
Not sure if one gh issue vs. a bunch of little ones. Maybe I'll group where it makes sense
Did a quick conversion over to GH issues: https://github.com/dagger/dagger/labels/zenith
@rocky harbor Just remembered, we have a breaking Go SDK API change in Zenith: input types are still pointers. I can look into this now as it's causing errors against services-v2 post-merge: https://github.com/dagger/dagger/actions/runs/6475541276/job/17582713755?pr=5557 - I just need to find that change in the codegen and roll it back, since they don't need to be pointers anymore.
Good catch! That sounds perfect, thanks!
https://github.com/dagger/dagger/pull/5865 - waiting for CI, not sure if i need to regen anything else
Yay! cc @wintry prism
Canβt believe zenith actually got merged. Very exciting π
Now I need to understand how to modularize a SDK
That still needs work. It's a bit tied to Go atm.
FYI @vivid hatch @visual blaze
thanks for the ping !
We are migrating the prod to Zenith, then π₯³
congrats Dagger team for this leap forward !! π
@kind carbon @deft rain do you want to take advantage of time zone proximity and talk live about short term zenith work, while the hackathon feedback is still fresh?
To be clear itβs merged but still experimental π all commands are hidden etc. but no longer requires building from a branch
I guessed. it's fine with us, happy to beta test (at least on our open source repo) π
Sure, were you thinking in the audio channel?
yes, Iβm free starting in 15mn
in #911305510882513037 now π
Hey, Iβll be available in 1h 15m.
I've made an effort to try and grab all the issues/feature requests from #1151970583723126844, and put them into github so we're tracking everything.
I think the idea is to try and archive the #1151970583723126844 forum at some point soon (discussed with @sharp zealot this morning), since we've now merged to main. I've think I've grabbed all the things that are still issues, but if anyone notices some left, then let me know, or just open one on Github π
Thank you Justin! And yes, I think it's time to close that forum.
Just sent a patch to update zenith documentation ^^ https://github.com/dagger/dagger/pull/5873
Should we cut a patch release to get zenith into a stable build? π cc @strong ingot @thorn moat
Seems like we could, since there's a brief window before merging services v2 which is the real (π€) breaking change. I'll wait to merge until we decide
(PR just went green: https://github.com/dagger/dagger/pull/5557, just needs a β )
Yeah we definitely should. And I worry about merging a breaking change before we have a release plan ready (docs, comms etc). Otherwise we would have an unreleasable main, right?
@thorn moat any way we could merge services v2 behind a "feature flag" (not sure what that would mean in the context of API changes, possibly not worth it - but never hurts to ask)
that would be ideal right?
the plan is to add docs on top of 5557 so there's no window of time where it's undocumented - will be reviewing docs @ember walrus has been working on today
not really, since it changes the type of a common arg in the schema (Container.WithServiceBinding(Service)); it's a pretty fundamental breakage
OK I see. We also need additional communications to manage the breaking change right? Blog post, heads up on discord... Not huge amounts of work but still need to plan it.
Makes sense to me to decouple the two releases, then π
Yeah definitely
i think patch since it's mostly a trojan horse to get Zenith out there unannounced but ready for tinkerers. No idea what else is in the release though, maybe there are other things that bump it to minor
Can't hurt to double-check with @ember walrus and do a quick changelog read-through, but yeah unless I'm missing something, it's patch
Compose on Zenith π
oooo does this work by returning a Container that has services pre-bound? π€―
Yes! π
@sonic vessel you're going to love the upcoming dagger up command which will take your function and expose all its ports on the host. π
Basically dagger up + your compose module = a reimplementation of docker compose
Oh! With the power of https://github.com/dagger/dagger/pull/5557, right?? So excite to try it. π
Correct π
(not sure if the zenith part of that is also in 5557, or in a separate PR?)
there are no zenith-y bits in that PR, I just have a branch from the hackathon sitting around with dagger serve, loose plan is to revive it once dagger call is done-enough to copy over its syntax for calling the function
@thorn moat, I'm finishing off my day, I need a dagger.FunctionArg(argID) constructor for that bug or a fix for the loop if you can take it on.
Thank you @strong ingot !!! https://daggerverse.dev π
oh, yeah that's interesting, these things aren't even ID-able right now
i can do that along the way, i've memorized the boilerplate π
@rocky harbor, I sent the last prototype to https://github.com/dagger/dagger/pull/5878
the module SDK API (moduleRuntime, codegen) is overdue for a bikeshed btw, I
'd those functions in as needed and then flew off to Lisbon. π
Better naming suggestions welcome, or maybe even a chaining API if there's a nice way to refactor it that way
should probably get it how we want it before we want more folks implementing them
Why can't I open this on the corporate network? I don't have the same issue with dagger.io or the playground.
simplifications to runtime bootstrap
Progrock
Is it too early to ask about docs/snippets/cookbook/guides for Zenith/daggerverse?
Just a quick update on the CLI.
When does this land for the python sdk?
Oh is that a permanent home for it? I'm afraid mine isn't the only one blocking that provider.
nope, we'll eventually bring it to the same dagter.cloud hosting. Can't say when though
I wonder if there isnβt something else going on. Blocking a small but vanilla hosting provider at the IP level seems so ridiculous that Iβm having trouble believing thatβs really whatβs going onβ¦ Unless Fly has a major spam/IP reputation problem maybe.
If I remember correctly Fly itself resells Equinix Metal. I canβt imagine your employer blocks them too
@restive shore what happens if you nc -z daggerverse.dev 80?