Skip to content

fix(app): permission prompt remains stuck after approving child session request #26907

Closed as not planned

Description

@donicrosby

Description

When a child session (subagent) triggers a permission request in the Web UI, approving it via "Allow once" or "Allow always" can leave the permission prompt visible in the composer even after the server has accepted the response.

The server returns 200 true for the permission reply, and subsequent GET /permission calls return an empty array [], confirming the permission was processed. However, the Web UI composer still renders the stale permission prompt until another sync event arrives or the page is refreshed.

Steps to Reproduce

  1. Start OpenCode with Web UI (opencode serve and opencode attach, or dev mode).
  2. Create a session and trigger a subagent or background task that requires a permission (e.g., a bash command with permission: { bash: "ask" }).
  3. In the parent session composer, observe the permission prompt for the child session.
  4. Click "Allow once".
  5. Observe that the permission prompt remains visible in the composer, even though the subagent proceeds.

Expected Behavior

The permission prompt should be removed from the composer immediately after the server confirms the response.

Actual Behavior

The permission prompt persists in the Web UI composer, creating a stale UI state that may confuse users.

Environment

  • OpenCode version: latest (observed during development)
  • Browser: Chrome (via Chrome DevTools MCP during reproduction)
  • OS: Linux

Related

This is a client-side UI state issue. The backend processes the permission correctly, but the frontend sync cache does not remove the accepted permission from the local store after a successful response.

Proposed Fix

After sdk.client.permission.respond() succeeds, optimistically remove the matching permission from the local sync cache (sync.set("permission", sessionID, ...)) so the composer re-renders without the stale prompt.

This aligns the UI state with the confirmed server response without waiting for the next sync event.

Activity

  1. Brendonovich commented on May 13, 2026

    @Brendonovich
    Member

    This is supposed to be handled by processing the permission.replied event from the backend, is it not being received or processed in your case?

  2. donicrosby commented on May 14, 2026

    @donicrosby
    Author

    It is not causing the TUI and Webapp to constantly ask for permission even thought it's already been granted.

  3. MingyooLee commented on May 26, 2026

    @MingyooLee

    This is supposed to be handled by processing the permission.replied event from the backend, is it not being received or processed in your case?

    Yes, the backend does publish permission.replied, and the app reducer already handles it.

    The part that was missing was on the Web/Desktop approval path. After clicking approve, the UI was relying on that live event as the only thing that clears the already-rendered local permission prompt. In the nested child-session case, that prompt can come from local sync/list state, while the event may be delayed, missed during reconnect/bootstrap timing, or ignored if the child directory store is not mounted yet. Then the server has accepted the reply, but the composer can still keep showing the stale prompt until a later refresh reconciles it.

    #28651 keeps the existing permission.replied handling, but also clears the matching local permission after permission.reply({ requestID }) succeeds. It also moves the Web/Desktop path off the deprecated session-scoped permission.respond call and onto the request-scoped reply endpoint, which matches the TUI/ACP/run paths.

  4. stefan123t commented on May 31, 2026

    @stefan123t

    I have witnessed the same symptoms, i.e. repeatedly asking for Permissions required. I could only select Allow Always, which gave me the choice of Confirm. It would immediately return me to the same Permissions required dialog. I could select (n)either Allow Once or Reject and it would return me immediately to the dialog, i.e. no change.

    I started an opencode session in a folder ~/project/opencode
    Later I restarted it in the parent folder ~/project
    This is where the trouble started, because the current folder is now outside / the parent folder is external to the root folder of the continued session.

    Opencode suggested me I should set/add "external_directory": "allow" in the ~/.config/opencode/opencode.jsonc but that defeats the directory permissions purpose.

    I hope this report can help to reproduce and fix the issue also on your side ?

  5. github-actions commented on Jul 31, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions