[FEATURE] Action buttons the agent can emit, bound to a command that runs in the session VM without a model turn
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
When an agent finishes a piece of work, it frequently arrives at a state where the reasoning is already done and the exact command is already known — it just needs a human to say "yes, do it". Right now every way of getting that "yes" costs a full model round trip, even though nothing needs to be inferred.
Concretely, in my repos and the template that feeds them /finalize runs a whole land-prep sequence (vet, merge the base, sweep working artifacts, flip the PR to ready, reconcile the squash message, attest) and then stops so I can copy the proposed squash title/body into GitHub's merge box and click merge. The agent already composed that message, already knows the PR number, and could run:
gh pr merge 63 --squash --subject "$(cat …)" --body-file …
Getting me to authorize that one command costs:
AskUserQuestion— renders chips and blocks for my answer, then the model has to wake up and act on it. A round trip's latency and tokens for a decision that was already made. (It's also unreliable in web/remote sessions — the pending prompt is re-emitted on wake and answers to superseded prompts are lost, #72704 — which is why my repo routes around it with numbered prose.)- Me typing "merge" — same round trip, plus I have to compose the message, and the agent has to re-derive what I meant.
- Permission prompts — these do run without a model turn, but they only fire when the agent itself decides to call a tool. They can't be used to hand a decision over and then end the turn; there's no way for the agent to say "here are the two things I could do next, pick one" and go idle.
The asymmetry is the point: a button whose action is a script executed in the session's VM costs essentially nothing to press. A question whose answer routes back through the model costs a turn.
Proposed Solution
A tool the agent can call to emit one or more labelled action buttons into the transcript, each bound at emit time to a concrete command (or a prepared tool call). Pressing one makes the harness execute that bound action in the session's environment. No inference happens on press.
Sketch:
ActionButtons({
prompt: "Attested green against main @ 8903396. Merge?",
actions: [
{
label: "Merge with this squash message",
run: "gh pr merge 63 --squash --subject \"$(cat tmp/squash-title.txt)\" --body-file tmp/squash-body.txt",
// or: { tool: "Bash", input: {...} } — a prepared tool call rather than a string
},
{ label: "Re-run the vet suite", run: "./scripts/vet.sh" }
],
expires: "turn" | "session"
})
Behavior I'd want:
- The bound command is fixed when the button is emitted and displayed in full on the button (or on expand), so what I press is what runs — a press can't be redirected by anything that arrives later.
- Execution goes through the same permission model as if the agent had made the call itself; a button is a way to defer who decides, not a way to escape the sandbox or the allowlist.
- The result is surfaced as a tool result the agent sees on its next turn, if there is one. If the session has already ended, the command still ran and the output is in the transcript — that's the whole value.
- Buttons expire with the turn or the session, and a pressed button is marked as such so it can't be double-fired.
- The agent can end its turn after emitting them. Today a pending
AskUserQuestionpins the session as "working" while it waits; a button lets the session go idle and still be actionable.
Alternative Solutions
AskUserQuestion— the right shape, the wrong economics: it returns an answer to the model rather than executing anything, so the cheap case (a decision already reduced to one command) pays the same as the expensive one.- An Artifact page with a real button — genuinely possible today: published HTML with a runtime capability writing to its database, plus a session watch to wake the agent when it changes. But the button lives on a page I have to open rather than in the chat, it still wakes the model to do the actual work, and it's a lot of machinery to replace one click.
- Auto-approval /
--dangerously-skip-permissions— removes the human rather than making the human cheap. The thing I want is the opposite: keep the gesture, drop the round trip. - #84375 (one-click activation for suggested replies) is adjacent but different — that's still a reply that wakes the model. This asks for a press that runs a command and doesn't.
Priority
Medium - Would be very helpful
Feature Category
Interactive mode (TUI)
Use Case Example
- I run
/finalize and mergeon a branch. The skill vets, mergesmainin cleanly, sweeps its working artifacts, flips the PR to ready, and posts an attestation. - My skill's gate says the run was uneventful — nothing failed, nothing was rewritten, the base didn't move — so the agent is authorized to merge. But for the cases where the gate doesn't hold (a conflict it resolved, a squash message it had to rewrite, an unanswered review thread), it must stop and hand the decision back.
- Today that stop is: a written report, then I read it, then I go to GitHub, copy the squash message out of a PR comment, and click merge. Or I type "ok merge" and pay for another turn.
- With this feature, the stand-down report ends with two buttons — "Merge with this squash message" and "Show me the diff first" — the first bound to the exact
gh pr mergeinvocation the agent already assembled. - I press it from my phone an hour later. The merge runs in the VM. No model turn, no tokens, no waiting for a session to wake.
The general shape recurs well beyond merging: dispatch the expensive CI bucket, deploy the branch that's now green, re-run the flaky job, apply the patch the agent already wrote to a file. In all of them the agent's judgment is finished and only the authorization is outstanding.
Additional Context
The distinction worth designing around is who does the work after the click. AskUserQuestion answers "what should I think about next?" and necessarily costs a turn. This asks for "run the thing you already decided on", which costs a subprocess. Treating them as one primitive is what makes cheap approvals expensive.
---
_Generated by Claude Code_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗