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
{{ message }}
Repository navigation
Consider adding a setting which causes backticks and shell() calls to execute during --dry-run #3592
Currently, --dry-run causes just to skip running recipes, backticks, and shell() calls. Backticks and shell calls evaluate to a string containing the command. This can cause problems when the these values are used in other expressions, for example, bool() which can error on unexpected input, halting the run.
For example, running foo in this justfile will fail during --dry-run:
foobar=bool(`echo 1`):
Since the backtick will evaluate to the string:
"`echo 1`"
Which is an error to pass to bool.
We could introduce a setting which caused backticks and shell() calls to run, even during --dry-run, so avoid this issue. It would have to be opt-in, since users may be relying on --dry-run not running such commands.
This feels perhaps a little too niche to be worth it, but I wanted to create this issue to collect feedback.
Executing substitutions during a dry run fixes type errors but weakens the strongest and most useful guarantee of --dry-run: no command side effects. Could a typed “unknown/dry-run value” propagate through expressions instead, or could validation defer operations such as bool() when their input comes from a skipped command? If an execution setting is added, naming it explicitly as an unsafe/evaluating dry run and listing which commands may run would prevent surprising automation behavior.
@casey What do you think about adding --wet-run to execute all top-level shell() calls and backticks outside recipes, while changing --dry-run to skip their execution and substitute default values matching their expected types, such as false for booleans and [] for lists?
This would allow --dry-run to work without executing shell commands or failing on errors such as:
error: call to function `bool` failed: `shell()` is not a valid boolean string
This would also be particularly useful for coding agents, which often run recipes in dry-run mode to inspect commands before executing them.
The goal is to make --dry-run reliable even when recipes depend on shell expressions, while keeping --wet-run available when those expressions need to be evaluated.
I'm thinking about adding this as a setting, see #3754. My thinking is that a setting affects the current module, and a module author knows whether or not backticks, shell(), and dotenv-command are safe to run during dry runs, and if they're necessary, i.e., if the dry run will fail if downstream uses don't get the evaluated uses. And, if they are safe to run and necessary, it's probably more convenient to always run them during dry runs, rather than require a flag being passed.
The PR I opened has two possible setting values:
# skip everything, current settingsetdry-run:="all"# skip only recipes, run backticks, `shell()`, and `dotenv-command`setdry-run:="recipes"
@casey That would be awesome for my use case! Configuring set dry-run := "recipes" once in the module would be especially useful for coding agents, since they could continue using --dry-run with the necessary shell expressions evaluated automatically.
I would also suggest that set dry-run := "all" skip the execution of backticks, shell(), and dotenv-command without causing evaluation errors. Instead, skipped expressions should substitute default values matching their expected types, such as false for booleans and [] for lists.
This would make both modes reliable while preserving the guarantee that dry-run := "all" never executes shell commands.
I would also suggest that set dry-run := "all" skip the execution of backticks, shell(), and dotenv-command without causing evaluation errors. Instead, skipped expressions should substitute default values matching their expected types, such as false for booleans and [] for lists.
This is not generally possible. Just doesn't have types, so we have no way of knowing what value we should substituted. I'm actually unsure how hard we should try to make --dry-run without set dry-run work. It's tempting to try to figure out what would paper over errors, but it's often actually better to get a good error as early as possible.
Activity
hiSandog commentedon Jul 16, 2026
Executing substitutions during a dry run fixes type errors but weakens the strongest and most useful guarantee of
--dry-run: no command side effects. Could a typed “unknown/dry-run value” propagate through expressions instead, or could validation defer operations such asbool()when their input comes from a skipped command? If an execution setting is added, naming it explicitly as an unsafe/evaluating dry run and listing which commands may run would prevent surprising automation behavior.cyann commentedon Sep 24, 2026
Maybe a new
--wet-runthat would evaluateshell()and backticks when setting variables?pygarap commentedon Oct 15, 2026
@casey What do you think about adding
--wet-runto execute all top-levelshell()calls and backticks outside recipes, while changing--dry-runto skip their execution and substitute default values matching their expected types, such asfalsefor booleans and[]for lists?This would allow
--dry-runto work without executing shell commands or failing on errors such as:This would also be particularly useful for coding agents, which often run recipes in dry-run mode to inspect commands before executing them.
The goal is to make
--dry-runreliable even when recipes depend on shell expressions, while keeping--wet-runavailable when those expressions need to be evaluated.casey commentedon Oct 17, 2026
I'm thinking about adding this as a setting, see #3754. My thinking is that a setting affects the current module, and a module author knows whether or not backticks,
shell(), anddotenv-commandare safe to run during dry runs, and if they're necessary, i.e., if the dry run will fail if downstream uses don't get the evaluated uses. And, if they are safe to run and necessary, it's probably more convenient to always run them during dry runs, rather than require a flag being passed.The PR I opened has two possible setting values:
What do you guys think?
pygarap commentedon Oct 17, 2026
@casey That would be awesome for my use case! Configuring
set dry-run := "recipes"once in the module would be especially useful for coding agents, since they could continue using--dry-runwith the necessary shell expressions evaluated automatically.I would also suggest that
set dry-run := "all"skip the execution of backticks,shell(), anddotenv-commandwithout causing evaluation errors. Instead, skipped expressions should substitute default values matching their expected types, such asfalsefor booleans and[]for lists.This would make both modes reliable while preserving the guarantee that
dry-run := "all"never executes shell commands.casey commentedon Oct 17, 2026
This is not generally possible. Just doesn't have types, so we have no way of knowing what value we should substituted. I'm actually unsure how hard we should try to make
--dry-runwithoutset dry-runwork. It's tempting to try to figure out what would paper over errors, but it's often actually better to get a good error as early as possible.