Skip to content

Remove approval prompt from dotnet tool exec - running dnx is implicit approval#52956

Merged
marcpopMSFT merged 6 commits intorelease/10.0.3xxfrom
copilot/enable-non-interactive-mode
Mar 4, 2026
Merged

Remove approval prompt from dotnet tool exec - running dnx is implicit approval#52956
marcpopMSFT merged 6 commits intorelease/10.0.3xxfrom
copilot/enable-non-interactive-mode

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 10, 2026

Remove approval prompt from dotnet tool exec - running dnx is implicit approval

dotnet tool exec (dnx) previously prompted users to confirm tool downloads, blocking LLMs, scripts, and automation. This PR removes the approval prompt entirely - running dnx is now treated as implicit approval.

Changes

Removed approval check

  • Deleted UserAgreedToRunFromSource() method that prompted for confirmation
  • Removed the interactive prompt logic that asked users to confirm tool download
  • Removed unused ERROR_CANCELLED constant and _interactive field
  • Removed unused resource strings: ToolDownloadConfirmationPrompt, ToolDownloadCanceled, ToolDownloadNeedsConfirmation
  • Updated all xlf translation files to remove these unused strings
  • Hidden --yes option from help output (option still works for backward compatibility)
  • Tools are now downloaded immediately if not already cached, without any prompts
// Before: prompted for approval
if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource))
{
    // Show error and exit
}

// After: no prompt, just download
// Tool is downloaded directly if not cached
toolPackage = _toolPackageDownloader.InstallPackage(...)

Rationale

When a user runs dotnet tool exec <package>, they are explicitly requesting to execute that package - this is the approval. The previous confirmation prompt:

  • Blocked non-interactive scenarios (LLMs, scripts, CI)
  • Provided no security benefit (user already made the decision by running the command)
  • Created unnecessary friction

This aligns with the philosophy of tools like npx where running the command implies consent to download and execute the requested package.

Help Output

The --yes option is now hidden from help since it's no longer needed, but remains functional for backward compatibility:

Before:

Options:
  --version <VERSION>  The version of the tool package to install.
  -y, --yes           Accept all confirmation prompts using "yes."
  --interactive       Allows the command to stop and wait for user input...

After:

Options:
  --version <VERSION>  The version of the tool package to install.
  --allow-roll-forward Allow a .NET tool to roll forward to newer versions...
  --interactive       Allows the command to stop and wait for user input...
Original prompt

This section details on the original issue you should resolve

<issue_title>Enable first-class non-interactive mode for the CLI</issue_title>
<issue_description>I'm a fan of dnx but have found that there are some usability issues with LLMs. The basic problem is that it requires an interative response, which causes a non-interactive user to just hang. I have noticed this a couple times recently. However, I was writing a skill that uses a tool and wanted to use dnx. However, using dnx is challenging. We need good guidance for this and to consider product changes. For now I'm saying, always use dnx -y dotnet-inspect -- [args].

There are two cases where an LLM might hit an interactive prompt:

  • First install
  • New version available

The second point is the most challenging. A session could be moving forward using a tool and then a new version is published to nuget.org, dnx notices this, and then blocks the LLM (or other tool) with an interactive prompt. This also means that dnx isn't a great choice for scripts, as-is.

Here's what I see.

DNX:

Image

NPM:

Image

This is from npm exec help:

  If any requested packages are not present in the local project
  dependencies, then a prompt is printed, which can be suppressed by
  providing either --yes or --no. When standard input is not a TTY or a CI
  environment is detected, --yes is assumed. The requested packages are
  installed to a folder in the npm cache, which is added to the PATH
  environment variable in the executed process.

I asked Copilot to thoroughly test this:

Image

I don't think that stdin is excellent solution. It's a pattern to enable. I'd like to see the dnx offer the same model as npx and also offer an ENV variable to make a whole session safe. That would mean install the package if not available and DON'T install a new package if one is available unless asked to.

Side note: We should make it easy to clear the dnx cache. This made testing a bit awkward.

I sometimes see the first-run experience in CP-CLI/CC. This is harmful, in the sense that it is wasted tokens and the person we wanted to see the first-run experience doesn't. Assuming we a DOTNET_INTERACTIVE=false, then I'd skip the first-run message as well. There may be other experiences we need to consider. That's why the title is about the scenario not dnx in particular.</issue_description>

<agent_instructions>Can you remove the requirement in dotnet tool exec that we request permission when we are running in non-interactive mode only? That would automatically approve in those situations.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@baronfel > dnx interactive prompts

We actually are free to remove the interactive yes/no prompt - we just haven't kicked off that agent run yet. We should just do that.

dnx cache clear

This is just the nuget cache - users are free to clear it at their whim via dotnet nuget locals global-packages --clear.

first-run experience showing

Agreed, we have all the puzzle pieces in place to prevent this too. The LLM heuristic we have is currently only being applied to telemetry reporting, but it makes perfect sense to make it one more input into the "should we be emitting first-use data" calculations.

@richlander Sounds great.

The more we can elevate high value commands to high-value CLI commands, the better. Clearly, the nuget cache commands are an advanced scenario as they are currently exposed.

It would be great if there was a way to get more information about dnx tools, just like the dotnet tool commands. Dnx to me means high convenience not mysterious.</comment_new>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Enable first-class non-interactive mode for the CLI Auto-approve tool installation in non-interactive mode for dotnet tool exec Feb 10, 2026
Copilot AI requested a review from marcpopMSFT February 10, 2026 22:23
@baronfel
Copy link
Copy Markdown
Member

@copilot the entire "check for approval" concept is unnecessary. The fix here should be to remove the entire "prompt" check - the usage of dnx is the approval.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 11, 2026

@copilot the entire "check for approval" concept is unnecessary. The fix here should be to remove the entire "prompt" check - the usage of dnx is the approval.

Agreed - I've removed the entire approval check. Running dnx is now implicit approval to download and execute the tool. Changes in commit 0624225.

Copilot AI changed the title Auto-approve tool installation in non-interactive mode for dotnet tool exec Remove approval prompt from dotnet tool exec - running dnx is implicit approval Feb 11, 2026
Copilot AI requested a review from baronfel February 11, 2026 18:04
Copy link
Copy Markdown
Member

@dsplaisted dsplaisted left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with this, but AFAIK npm does prompt you when in interactive mode. I'm not sure everyone was fully agreed to remove the prompt entirely.

{
if (_interactive)
{
Reporter.Error.WriteLine(CliCommandStrings.ToolDownloadCanceled.Red().Bold());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Also remove the CliCommandStrings that have been removed from the resources. You'll probably need to do a build to update the xlf files too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the unused resource strings (ToolDownloadConfirmationPrompt, ToolDownloadCanceled, ToolDownloadNeedsConfirmation) and updated all xlf files using /t:UpdateXlf. Changes in commit 4744ace.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 13, 2026

I'm OK with this, but AFAIK npm does prompt you when in interactive mode. I'm not sure everyone was fully agreed to remove the prompt entirely.

You're right that npm does prompt in interactive mode. However, @baronfel's guidance was that for dnx, the act of running the command itself is the approval - similar to how dotnet tool run works for manifest-based tools. The rationale is that dotnet tool exec <package> is an explicit request to execute that specific package, so an additional confirmation adds friction without security benefit.

If the team prefers npm's behavior (prompt in interactive, auto-accept in non-interactive), I can restore the prompt logic but fix it to properly detect non-interactive scenarios. Let me know which approach you'd prefer.

@dsplaisted
Copy link
Copy Markdown
Member

@copilot My comments about the design were for @baronfel, not for you :-)

@baronfel baronfel marked this pull request as ready for review February 17, 2026 21:18
Copilot AI review requested due to automatic review settings February 17, 2026 21:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Removes the interactive approval prompt from dotnet tool exec (dnx), treating invocation as implicit consent to download and run the tool package.

Changes:

  • Removed the confirmation/approval flow (and related error paths) from tool execution when the tool package isn’t already cached.
  • Deleted now-unused localized resource strings for the tool-download prompt/cancel messaging.
  • Updated XLF localization files to remove the deleted tool-download strings.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
src/Cli/dotnet/Commands/Tool/Execute/ToolExecuteCommand.cs Removes the interactive approval prompt and downloads the tool package immediately when missing.
src/Cli/dotnet/Commands/CliCommandStrings.resx Removes the tool-download confirmation/cancel resource strings no longer referenced.
src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).
src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf Removes tool-download trans-units; also includes unintended confirmation-prompt translation resets (needs fix).

Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Введите "{0}", чтобы указать "да", и "{1}", чтобы указать "нет".</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">请键入 '{0}' 以表示是或键入 '{1}' 以表示否。</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 101 to 105
if (!_toolPackageDownloader.TryGetDownloadedTool(packageId, bestVersion, targetFramework: null, verbosity: _verbosity, out var toolPackage))
{
if (!UserAgreedToRunFromSource(packageId, bestVersion, packageSource))
{
if (_interactive)
{
Reporter.Error.WriteLine(CliCommandStrings.ToolDownloadCanceled.Red().Bold());
return ERROR_CANCELLED;
}
else
{
Reporter.Error.WriteLine(CliCommandStrings.ToolDownloadNeedsConfirmation.Red().Bold());
return 1;
}
}

// We've already determined which source we will use and displayed that in a confirmation message to the user.
// We've already determined which source we will use and will use it to download the package.
// So set the package location here to override the source feeds to just the source we already resolved to.
// This does mean that we won't work with feeds that have a primary package but where the RID-specific packages are on
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change removes the explicit confirmation step before downloading a one-shot tool, but existing dotnet tool exec/dnx end-to-end tests appear to always pass --yes. To validate the new implicit-approval behavior, please add/update at least one test to run dotnet tool exec <package> without --yes (both TTY and non-interactive if feasible) and assert it still downloads/executes successfully.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Tapez « {0} » pour Oui ou « {1} » pour non.</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">はいの場合は「{0}」、いいえの場合は「{1}」と入力してください。</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">請輸入 '{0}' 表示是或 '{1}' 表示否。</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Geben Sie "{0}" für Ja oder "{1}" für Nein ein.</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Escriba "{0}" para sí o "{1}" para no.</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Digita '{0}' per sì o '{1}' per no.</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Comment on lines 316 to 320
<trans-unit id="ConfirmationPromptInvalidChoiceMessage">
<source>Please type '{0}' for yes or '{1}' for no.</source>
<target state="translated">Wpisz „{0}”, aby dla tak lub „{1}” dla nie.</target>
<target state="new">Please type '{0}' for yes or '{1}' for no.</target>
<note />
</trans-unit>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localized targets for ConfirmationPromptInvalidChoiceMessage (and the related yes/no key strings immediately below) were reset to English with state="new". These resources are still used by InteractiveConsole.Confirm, so this introduces a localization regression and may also change accepted input keys in localized prompts. Please restore the previous translations/target states for these confirmation prompt entries while keeping only the tool-download trans-units removed.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@marcpopMSFT marcpopMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and confirmed no approval required.

@richlander
Copy link
Copy Markdown
Member

Glad to see this fix rolling out.

Copilot AI and others added 5 commits February 27, 2026 10:46
Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
… logic

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
@marcpopMSFT marcpopMSFT force-pushed the copilot/enable-non-interactive-mode branch from 4744ace to a73677d Compare February 27, 2026 18:46
@marcpopMSFT
Copy link
Copy Markdown
Member

@copilot The help still shows --yes. We don't want to remove the option as we don't want to break folks but we want to remove it from help since it's not needed anymore. I think you want to add a parameter to CreateYesOption that lets us create it hidden for the execute command.

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 3, 2026

@copilot The help still shows --yes. We don't want to remove the option as we don't want to break folks but we want to remove it from help since it's not needed anymore. I think you want to add a para...

Added hidden parameter to CreateYesOption() and set it to true for tool exec. The --yes option is now hidden from help but still works for backward compatibility. Changes in commit 21302b0.

Help output change:

BEFORE:
  --version <VERSION>  The version of the tool package to install.
  -y, --yes           Accept all confirmation prompts using "yes."
  --interactive       Allows the command to stop and wait for user input...

AFTER:
  --version <VERSION>  The version of the tool package to install.
  --allow-roll-forward Allow a .NET tool to roll forward to newer versions...
  --interactive       Allows the command to stop and wait for user input...

The --yes flag still functions correctly but is no longer shown since it's not needed.

@marcpopMSFT
Copy link
Copy Markdown
Member

Latest change matches what I requested. I confirmed that the help no longer specifies --yes but the command doesn't break if it's included.

@marcpopMSFT marcpopMSFT merged commit b967128 into release/10.0.3xx Mar 4, 2026
24 checks passed
@marcpopMSFT marcpopMSFT deleted the copilot/enable-non-interactive-mode branch March 4, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants