Skip to content

feat(module): generate CLI 1.0 modules in the SDK - #27

Draft
TomChv wants to merge 2 commits into
feat/module-gen-dangfrom
feat/module-gen-cutover
Draft

feat(module): generate CLI 1.0 modules in the SDK#27
TomChv wants to merge 2 commits into
feat/module-gen-dangfrom
feat/module-gen-cutover

Conversation

@TomChv

@TomChv TomChv commented Aug 11, 2026

Copy link
Copy Markdown
Member

Mod.generate now generates dagger-module.toml modules here instead of routing
through the engine's built-in TypeScript runtime. dagger.json modules keep
delegating: that runtime regenerates everything at call time regardless, so
generating them here would only leave a second, differently-versioned copy of
the same files on disk.

Dependency-closure staging is kept for both paths — a dependent's schema can
only be loaded once its local deps' generated files exist, which is true no
matter who does the generating.

No .gitignore or .gitattributes is written. The engine appends to both around
codegen, but for a workspace module the ignore list reduces to
node_modules/.pnpm-store, which is the user's business rather than codegen's.

The new check asserts the tree contract rather than one marker file, because
that contract is enforced somewhere else entirely: the runtime does no codegen
for these modules, so a missing piece surfaces as a module that won't load at
dagger call time, long after generate ran.

Signed-off-by: Tom Chauveau tom@dagger.io


Stack created with GitHub Stacks CLIGive Feedback 💬

TomChv added 2 commits August 11, 2026 15:35
Mod.generate now generates dagger-module.toml modules here instead of routing
through the engine's built-in TypeScript runtime. dagger.json modules keep
delegating: that runtime regenerates everything at call time regardless, so
generating them here would only leave a second, differently-versioned copy of
the same files on disk.

Dependency-closure staging is kept for both paths — a dependent's schema can
only be loaded once its local deps' generated files exist, which is true no
matter who does the generating.

No .gitignore or .gitattributes is written. The engine appends to both around
codegen, but for a workspace module the ignore list reduces to
node_modules/.pnpm-store, which is the user's business rather than codegen's.

The new check asserts the tree contract rather than one marker file, because
that contract is enforced somewhere else entirely: the runtime does no codegen
for these modules, so a missing piece surfaces as a module that won't load at
`dagger call` time, long after generate ran.

Signed-off-by: Tom Chauveau <tom@dagger.io>
generateAllModule carried its own copy of the staging-and-generate logic, so
the cutover reached `mod generate` but not `dagger generate` — the command
users actually run. It kept generating every module with the engine's runtime.
The e2e missed it because generate-all only asserted that files appeared, which
the engine path also produces.

Sharing the routing surfaced two things the old copy had been hiding.

The staging cannot simply be reused: the engine generates a local dependency by
running its SDK's @generate rollup with that dependency as cwd, so generate-all
already runs inside another module's staging. Calling Mod.generate from it
stages a second time, against a re-anchored workspace where the paths no longer
resolve. Hence generateStaged: the routing half, without the staging.

And staging a module's generated files with fork.withDirectory replaced its
whole source directory — the polyfill documents it as "add or replace", so
everything not regenerated, including the module's own config and src, was
expressed as deleted. Applying to disk hid this; staging into a workspace did
not, and the next module's dependency resolution found the dependency's config
gone. Now staged as a diff over the module's existing tree.

The diff is measured against the unstaged workspace on purpose. Measuring
against the staged one reports a module's own output as already present —
which it is, if the engine generated it moments earlier while staging it for a
dependent — and emits an empty changeset.

Signed-off-by: Tom Chauveau <tom@dagger.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant