Skip to content

Comments

fix: filter question tool and auto-approve permissions in non-interactive mode#14607

Open
radical-beard wants to merge 2 commits intoanomalyco:devfrom
radical-beard:fix/non-interactive-permissions
Open

fix: filter question tool and auto-approve permissions in non-interactive mode#14607
radical-beard wants to merge 2 commits intoanomalyco:devfrom
radical-beard:fix/non-interactive-permissions

Conversation

@radical-beard
Copy link

@radical-beard radical-beard commented Feb 21, 2026

Issue for this PR

Closes #11899
Closes #13851

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

opencode run has two compounding bugs that make it unusable for automation:

Bug 1 — Question tool hangs (#11899): run.ts sets question: deny on the session, but this never reaches the LLM tool-filtering layer. LLM.resolveTools() only checks agent-level permissions, and the build agent explicitly sets question: "allow". The question tool also calls Question.ask() directly without going through ctx.ask(), so the session deny rule is never evaluated. Result: model calls question tool → Question.ask() returns a Promise waiting for Question.reply() which never comes → process hangs.

Bug 2 — Permission blocking (#13851): The permission.asked event handler in run.ts auto-rejects all permission requests. Any tool with "ask" permission (file writes in certain directories, .env reads, external directory access) fails immediately. The model gets errors, retries a few times, gives up. Users see: "starts loop, runs ls, exits."

Fix 1 (3 files):

  • llm.ts: Added permission field to StreamInput. resolveTools() now merges session permissions with agent permissions, so question: deny from the session actually removes the question tool from the tool list.
  • prompt.ts: Passes session.permission through to the LLM layer.
  • question.ts: Added ctx.ask() call before Question.ask(). If denied, returns a message ("Make your best judgment and proceed") instead of hanging.

Fix 2 (1 file):

  • run.ts: Changed the permission.asked handler reply from "reject" to "once" (auto-approve). This only affects "ask" rules — explicit "deny" rules throw DeniedError before the event handler is ever reached, so they're unaffected. Added --no-auto-approve flag for CI environments that want the old strict behavior.

I understand why these changes work: the permission system uses findLast() semantics (last matching rule wins). Session permissions appended after agent permissions override them. The disabled() function checks for deny + wildcard pattern * to filter tools pre-LLM. The event handler only sees "ask" rules because "deny" rules short-circuit with DeniedError in PermissionNext.ask().

How did you verify your code works?

  • Typecheck passes across all 12 packages
  • All 1136 existing tests pass (0 failures)
  • Manual testing with opencode run "Create a file called test.txt with 'hello world'" --format json

Screenshots / recordings

N/A — CLI-only change

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…ractive mode

The question tool bypassed the permission pipeline by calling Question.ask()
directly without going through ctx.ask(). Combined with LLM.resolveTools()
only consulting agent-level permissions (where the build agent explicitly
allows question), this caused opencode run to hang indefinitely when the
model invoked the question tool (anomalyco#11899).

Three changes fix this:

1. LLM.resolveTools() now accepts session-level permissions and merges them
   with agent permissions when computing disabled tools, so session rules
   like question:deny actually filter the tool from the tool list.

2. SessionPrompt passes the session's permission ruleset through to the
   LLM layer via the new StreamInput.permission field.

3. The question tool now calls ctx.ask() before Question.ask(), so even if
   the tool isn't filtered out, the permission pipeline is consulted. On
   denial, it returns a helpful message instead of hanging.

Refs anomalyco#11899

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added needs:compliance This means the issue will auto-close after 2 hours. needs:issue labels Feb 21, 2026
@github-actions
Copy link
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link
Contributor

The following comment was made by an LLM, it may be inaccurate:

Found potential related PRs:

  1. fix(run): disable question tool in non-interactive mode #11895 - "fix(run): disable question tool in non-interactive mode"

    • Related to the same issue of question tool in non-interactive mode
  2. fix(run): prevent subagent question tool hang in non-interactive mode #13974 - "fix(run): prevent subagent question tool hang in non-interactive mode"

    • Directly addresses the question tool hang problem that this PR fixes
  3. fix(github): auto-deny permissions and emit events in non-interactive mode #6832 - "fix(github): auto-deny permissions and emit events in non-interactive mode"

    • Related to permission handling in non-interactive mode

These PRs appear to be addressing the same core issues (question tool hangs and permission system blocking operations in non-interactive/automation scenarios). You should review them to ensure this PR doesn't duplicate work or conflict with previous attempts to fix these issues.

@github-actions github-actions bot removed needs:issue needs:compliance This means the issue will auto-close after 2 hours. labels Feb 21, 2026
@github-actions
Copy link
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

The permission.asked event handler in run.ts auto-rejected all permission
requests, causing any tool requiring "ask" permission (like file writes in
certain directories) to fail. Users reported that opencode run would start
a loop, run ls, then exit without doing useful work (anomalyco#13851).

Explicit "deny" rules still throw DeniedError before reaching the event
handler, so changing the default reply from "reject" to "once" is safe --
it only affects "ask" rules that need interactive confirmation.

A --no-auto-approve flag is added for CI environments where users want
strict permission checking (original reject behavior).

Refs anomalyco#13851

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@radical-beard radical-beard force-pushed the fix/non-interactive-permissions branch from 55a8f1c to 4802c33 Compare February 21, 2026 23:15
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.

Unable to use opencode cli in a non-interactive pipeline opencode run hangs when model attempts to use question tool

1 participant