Skip to content

hold has no approval dialog and held messages never expire #5

Description

@TheArctesian

Recorded in the README's "Differences from Claude Code".

Current behaviour

Setting OPENCODE_CROSS_SESSION_INBOUND=hold writes an incoming message to the receiver's inbox file. It is injected at the start of that session's next turn. That is all.

Claude Code's hold is richer:

  • It opens an approval dialog in the receiving session showing the sender and a preview, with Approve and Deny
  • An unanswered dialog expires after dialogExpiry, five minutes by default, and the message is dropped
  • The sender is told what happened: a notice when the message is held, and a follow-up when it is later delivered, denied, or expired
  • If the session's permission mode changes while messages are held, the rules are re-applied

So "hold" here means "wait for the next turn", not "wait for your approval". A user who never starts another turn in that session accumulates messages that are never seen and never expire, and the sender is told only that it was queued.

What is achievable

  • Approval dialog: plugins cannot open arbitrary prompt UI. The nearest primitives are the permission.ask hook and POST /tui/show-toast. A toast can notify but cannot collect Approve/Deny. Worth investigating whether a held message can be surfaced as a real permission request; if not, this part is not implementable as a plugin and should be documented rather than faked.
  • Expiry: straightforward. Stamp each held entry (already carries ts) and drop anything older than a configurable deadline on drain, defaulting to something long enough to be useful. Cheap, and removes the silent unbounded pile.
  • Sender notices: only possible with a return path. Today delivery is fire-and-forget over HTTP. Inbound refuse/hold are cooperative, not enforced by the receiver #3's receiver-owned socket would give the receiver a channel to report delivered/held/denied/expired back to the sender.

Suggested order

  1. Add expiry to held messages. Small, self-contained, no design questions.
  2. Fold sender-side outcome notices into Inbound refuse/hold are cooperative, not enforced by the receiver #3, since they need the same return channel.
  3. Investigate the approval dialog separately, and document it as not implementable if that is the answer.

Meanwhile

The README should say what hold actually does — waits for the next turn, no approval, no expiry — rather than leaving the Claude Code semantics implied.

Activity

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