Skip to content

Consider adding a setting which causes backticks and shell() calls to execute during --dry-run #3592

Open

Description

@casey

Apropos of #3586.

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:

foo bar=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.

Activity

  1. hiSandog commented on Jul 16, 2026

    @hiSandog

    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.

  2. cyann commented on Sep 24, 2026

    @cyann

    Maybe a new --wet-run that would evaluate shell() and backticks when setting variables?

  3. pygarap commented on Oct 15, 2026

    @pygarap

    @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.

  4. casey commented on Oct 17, 2026

    @casey
    OwnerAuthor

    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 setting
    set dry-run := "all"
    # skip only recipes, run backticks, `shell()`, and `dotenv-command`
    set dry-run := "recipes"

    What do you guys think?

  5. pygarap commented on Oct 17, 2026

    @pygarap

    @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.

  6. casey commented on Oct 17, 2026

    @casey
    OwnerAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions