You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We're trying to publish a small, versioned Pkl package (attached as a GitHub release
asset, mirroring how hk publishes its own Builtins.pkl) that exposes one reusable Config.Step for other repos to drop into their own hooks { ["commit-msg"] { steps { ... } } } block — the same way those repos already consume hk's own builtins:
We hit a Module version conflict error the moment a consumer's own pinned hk package
version differs from the version our package's Config.Step value was built against, and
couldn't find documentation describing whether this is expected/by-design, or whether
there's a recommended pattern to avoid it. Filing this to ask for guidance, with the
reproduction steps and variants we tried below.
Note the consumer is pinned to hk@1.45.0; the package was built against hk@1.46.0.
What happens
–– Pkl Error ––
Module version conflict: Expected value of type `hk.Config#Step` defined in module
`package://github.com/jdx/hk/releases/download/v1.45.0/hk@1.45.0#/Config.pkl`, but got
type `hk.Config#Step` defined in module
`package://github.com/jdx/hk/releases/download/v1.46.0/hk@1.46.0#/Config.pkl`.
steps: Mapping<String, Config.Step> = new {
^^^^^^^^^^^
["example-check"] = ExampleBuiltins.commit_verify
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is reproducible 100% of the time whenever the package's pinned hk version and the
consumer's pinned hk version differ, and disappears entirely the moment both pin the
exact same version.
Variants we tried
We assumed the PklProject.dependencies + @hk/... alias was the cause and tried
removing it, in case a raw inline import behaves differently:
Variant A — package declares dependencies.hk, imports via @hk/Config.pkl alias.
Requires pkl project resolve to generate a committed PklProject.deps.json lockfile.
Result: Module version conflict as shown above.
Variant B — package declares no dependencies at all, imports hk's Config.pkl via the
full inline package://github.com/jdx/hk/releases/download/v1.46.0/hk@1.46.0#/Config.pkl
URL directly (no alias, no lockfile).pkl project package succeeds fine without ever
running pkl project resolve. Result: identicalModule version conflict error,
word-for-word, the moment the consumer's hk version differs.
So the dependency-declaration/lockfile mechanism appears to be unrelated to the
conflict — it's strictly about the resolved module identity baked into the type at the
point the package's .pkl source was authored, regardless of how that import is spelled.
Variant C — package exports a plain String instead of a typed Config.Step,
consumer wraps it themselves:
This works regardless of version mismatch (confirmed against hk 1.45.0 and 1.46.0
side-by-side), since no typed hk.Config#Step value crosses the package boundary. The
cost: every consumer has to write the new Config.Step { check = ... } wrapper at every
call site, which loses the nice ["x"] = Builtins.y-style ergonomics hk's own builtins
have, and that cost compounds as a package publishes more than one Step.
A related, possibly-relevant data point: version-mismatch panic on hk install/hk check
Separately (same investigation, different root cause — flagging since it's adjacent): if
a repo's own .config/hk/config.pkl does amends ".../hk@1.46.0#/Config.pkl" but the installed/runninghk binary is a different version (e.g. 1.48.0, via a mise bump), hk check/hk install panics rather than producing a clean diagnostic:
thread 'main' (62318829) panicked at src/settings.rs:101:30:
Failed to load configuration: Failed to read config file: .config/hk/config.pkl
Caused by:
Failed to evaluate Pkl config at .config/hk/config.pkl
Error output:
Import not found: /var/folders/.../pklr-pkg-1/@hk/Config.pkl
Location:
src/config.rs:614:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
We confirmed this reproduces even with zero custom Pkl files present (deleted every
non-hk-authored .pkl file in the repo and it still panicked identically), so it's
purely about the running binary version vs. the config's pinned amends version, not
about anything we'd written. Running the exact matching hk binary version resolves it
immediately. This felt like it might be the same underlying mechanism as the Module version conflict issue above (a version pin not reconciling cleanly), so
including it here in case it's useful triage context — happy to file it separately if
that's preferred.
Question for maintainers
Is there a recommended, documented pattern for third parties to publish reusable Config.Step values (not a whole hooks {} config, just individual Steps meant to be
merged into a consumer's own, separately-pinned config) without coupling consumers to
the exact hk package version the publishing package happens to be built against? We
found one community example
(joevin-slq-docto/remote-hk-hooks)
but on inspection it amendsConfig.pkl directly and declares its own full hooks {}
block — i.e. it's designed to be adopted as someone's entire config (or amends-chained),
not imported piecemeal alongside an existing one, so it doesn't appear to hit (or solve)
this specific problem.
If Variant C (plain string / function, consumer constructs the typed Step themselves)
is the intended/recommended pattern for this use case, documenting it explicitly (e.g. on
the Pkl introduction or builtins pages) would have saved us a fair amount of
trial and error — happy to contribute that doc if useful.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
We're trying to publish a small, versioned Pkl package (attached as a GitHub release
asset, mirroring how
hkpublishes its ownBuiltins.pkl) that exposes one reusableConfig.Stepfor other repos to drop into their ownhooks { ["commit-msg"] { steps { ... } } }block — the same way those repos already consumehk's own builtins:We hit a
Module version conflicterror the moment a consumer's own pinnedhkpackageversion differs from the version our package's
Config.Stepvalue was built against, andcouldn't find documentation describing whether this is expected/by-design, or whether
there's a recommended pattern to avoid it. Filing this to ask for guidance, with the
reproduction steps and variants we tried below.
Environment
pkl0.31.1hk1.46.0 / 1.48.0 (both tested, see below)What we're trying to do
Publish a small package, e.g.:
A consumer repo (with its own, separately pinned
.config/hk/config.pkl) imports thisand merges the value into their own
hooksblock:Note the consumer is pinned to
hk@1.45.0; the package was built againsthk@1.46.0.What happens
This is reproducible 100% of the time whenever the package's pinned
hkversion and theconsumer's pinned
hkversion differ, and disappears entirely the moment both pin theexact same version.
Variants we tried
We assumed the
PklProject.dependencies+@hk/...alias was the cause and triedremoving it, in case a raw inline import behaves differently:
Variant A — package declares
dependencies.hk, imports via@hk/Config.pklalias.Requires
pkl project resolveto generate a committedPklProject.deps.jsonlockfile.Result:
Module version conflictas shown above.Variant B — package declares no dependencies at all, imports hk's
Config.pklvia thefull inline
package://github.com/jdx/hk/releases/download/v1.46.0/hk@1.46.0#/Config.pklURL directly (no alias, no lockfile).
pkl project packagesucceeds fine without everrunning
pkl project resolve. Result: identicalModule version conflicterror,word-for-word, the moment the consumer's hk version differs.
So the dependency-declaration/lockfile mechanism appears to be unrelated to the
conflict — it's strictly about the resolved module identity baked into the type at the
point the package's
.pklsource was authored, regardless of how that import is spelled.Variant C — package exports a plain
Stringinstead of a typedConfig.Step,consumer wraps it themselves:
This works regardless of version mismatch (confirmed against hk 1.45.0 and 1.46.0
side-by-side), since no typed
hk.Config#Stepvalue crosses the package boundary. Thecost: every consumer has to write the
new Config.Step { check = ... }wrapper at everycall site, which loses the nice
["x"] = Builtins.y-style ergonomics hk's own builtinshave, and that cost compounds as a package publishes more than one Step.
A related, possibly-relevant data point: version-mismatch panic on
hk install/hk checkSeparately (same investigation, different root cause — flagging since it's adjacent): if
a repo's own
.config/hk/config.pkldoesamends ".../hk@1.46.0#/Config.pkl"but theinstalled/running
hkbinary is a different version (e.g. 1.48.0, via amisebump),hk check/hk installpanics rather than producing a clean diagnostic:We confirmed this reproduces even with zero custom Pkl files present (deleted every
non-
hk-authored.pklfile in the repo and it still panicked identically), so it'spurely about the running binary version vs. the config's pinned
amendsversion, notabout anything we'd written. Running the exact matching
hkbinary version resolves itimmediately. This felt like it might be the same underlying mechanism as the
Module version conflictissue above (a version pin not reconciling cleanly), soincluding it here in case it's useful triage context — happy to file it separately if
that's preferred.
Question for maintainers
Is there a recommended, documented pattern for third parties to publish reusable
Config.Stepvalues (not a wholehooks {}config, just individual Steps meant to bemerged into a consumer's own, separately-pinned config) without coupling consumers to
the exact
hkpackage version the publishing package happens to be built against? Wefound one community example
(joevin-slq-docto/remote-hk-hooks)
but on inspection it
amendsConfig.pkldirectly and declares its own fullhooks {}block — i.e. it's designed to be adopted as someone's entire config (or
amends-chained),not imported piecemeal alongside an existing one, so it doesn't appear to hit (or solve)
this specific problem.
If Variant C (plain string / function, consumer constructs the typed
Stepthemselves)is the intended/recommended pattern for this use case, documenting it explicitly (e.g. on
the Pkl introduction or
builtins pages) would have saved us a fair amount of
trial and error — happy to contribute that doc if useful.
All reactions