## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - People can save follow-up messages while an agent runs. > - Stop preserves those messages and stops the active execution. > - The queue removed its delivery controls when that execution ended. > - Native admission also refused an explicit resend of older queued input. > - This change adds Send for a stopped queue and records fresh board intent. > - The saved message can continue through normal cleanup and admission checks. ## Linked Issues or Issue Description **What happened?** A person queued a message with a screenshot while an agent was starting. Steering was not yet available. They stopped the run. The message remained visible, but no control could send it. Native queue delivery also rejected this transition. **Expected behavior** A stopped queue offers Send. The click preserves message IDs, content, attachments and original authors. It starts at most one eligible continuation. Stop remains effective until the person gives new direction. **Steps to reproduce** 1. Start a native task and queue a second message. 2. Stop the active run before it consumes that message. 3. Open the task after cleanup. Observe the saved message with no send control. Refs #16965 for the queue-control change and #15015 for stopped conversation recovery. No open repair for this exact transition was found. ## What Changed - Show Send for a saved deferred queue with no active run. - Accept the existing board queue action for a stopped native target. Keep live native interruption restricted. - Use the server-recorded click time to authorize older native messages. Reject stale, malformed and wrong-actor intents. - Reuse normal queue dispatch, revision checks, cleanup proofs and execution admission, including a failed native predecessor after a verified Send. - Ignore a fully committed, successful recovered export when admitting a fresh message, while retaining the wait for results still committing. - Honor an applied `/new` conversation boundary while retaining native execution holds until the existing stop and cleanup checks verify them. Workspace holds also survive reset. Check the newest failed or cancelled native execution even when older recovery actions exist. - Keep native automatic delivery separate from the explicit Send action. Update execution and access documentation. ## Verification - Meaningful regressions failed before the fixes: stopped queues lacked Send, native admission refused fresh intent, cleanup and dispatch receipts were missing, deferred rows disappeared, live plan Interrupt rejected its own receipt, and Agent Chat `/new` inherited an old non-workspace execution hold. - Six assembled-wakeup cases fail before the reset cleanup fix. All 11 reset/history cases pass after it: live processes, missing identity, quarantined cleanup, remote leases and live controllers remain held; verified cleanup proceeds and retires the hold. Two more cases fail before the fallback fix and pass after it: Send verifies a stopped or live native predecessor despite a later reset receipt and no recovery record. - **525 server tests pass** across seven queue admission, route, dispatch, envelope, provenance, blocker and conversation files. **343 queue/thread UI tests** also pass. Server/UI TypeScript, token and map guards pass. The final scoped server typecheck also builds native Runner successfully. - The latest regressions prove that completed recovered exports permit fresh input, and clearing conversation history still requires old native stop and cleanup verification; an unsafe workspace still blocks after `/new`; failed native Send reaches actual continuation dispatch with the original queued comment. A result still being committed remains deferred. History plus a newer Stop cannot hide a missing process/controller/lease receipt. - The real Chromium Stop/Send journey passes on current head `75fa5e7222c59f43ff7ac326e81093bc9da28330`: queue a follow-up, Stop, reload, explicitly Send, then verify exactly one useful response and no live run. Earlier browser journeys cover legacy Interrupt, interruption during a write and Stop followed by a new direction. These use an isolated app/database and controlled ACP fixture, not an external AI account or a staging deployment. - Negative cases retain actor, company, issue, assignee, queue and cancellation-receipt bindings; cleanup/process/workspace/controller holds; approvals; pause and budget gates. Typed responses keep their original resolver and immutable result. - Full local recursive typecheck stopped in unchanged Rust Runner compilation with ENOSPC, so the chained full tests/build did not run. All hosted CI gates pass on final commit `75fa5e7222c59f43ff7ac326e81093bc9da28330`, including typecheck, tests, build and E2E. Apex review on that commit is 5/5, with no unresolved findings. Earlier unrelated CI failures involved PostgreSQL fixture-cleanup deadlock and an unchanged decision-expiry deadline assertion; the latter's 20 cases pass locally without source changes. No assertions or limits were weakened. Local resource cleanup was limited to this task's verified completed test processes and rebuildable npm caches. ## Risks - Send can authorize a new turn for a saved message after Stop. A Send click must be newer than the stopped execution; a live plan Interrupt is bound to the cancellation receipt produced by that same click. It does not imply that cleanup finished or that an external action is safe to replay. - The existing endpoint and intent format are reused. No schema or credential change is required. Live native steering and legacy interruption keep their existing paths. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, repository inspection, tool use and code execution. The session does not expose the exact serving model ID or context window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
8.1 KiB
Steering and queued messages — agent access
Product map: Steering and queued messages.
Feature ID: steering.
Review date: 2026-10-12. Source commit: 58e16dbddfc9c8d0cf60867f9d9847f0feda055b.
Native REST transport reconciled in this change; see the
shared transport contract.
This is a source-reviewed baseline of representative operations and known gaps. Each capability needs operation-level review before its entire scope can be qualified. No live agent execution is claimed. Follow the map contract for format, permission checks, evidence and maintenance.
queue
Capability ID: steering/queue.
Review: baseline.
API: present — representative operation IDs:
GET /api/issues/{id}/queued-comments.
Agent access: partial — REST / native call_api for visible queue; server-owned queue
admission.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user.
Compact task run reads retain wakeupRequestId and queuedCommentSourceWakeIds
to identify consumed input queues, including coalesced requests. These receipt
fields follow the existing task/run read checks and grant no queue mutation authority.
The UI can place a queued turn's starting input in history without recording consumption. Drain release and expiry only reconsider existing queued runs under normal admission authority. They grant no new agent control or replay authority.
Accepted deferred requests remain pending while their recipient agent is paused. Resume uses the normal admission checks. This grants no new pause, resume, queue mutation, or execution authority to an agent.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Agents can read eligible queue state; sending/steering the person's queued messages requires separate authority.
edit-order-discard
Capability ID: steering/edit-order-discard.
Review: baseline.
API: present — representative operation IDs:
PATCH /api/issues/{id}/queued-comments/{commentId}.PUT /api/issues/{id}/queued-comments/order.DELETE /api/issues/{id}/queued-comments/{commentId}.
Agent access: restricted — Board-user queue mutation API.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: No agent user-message edit/reorder/discard path; explicit delegated-user policy needed before granting one.
steer
Capability ID: steering/steer.
Review: baseline.
API: present — representative operation IDs:
POST /api/issues/{id}/queued-comments/{commentId}/steer.
Agent access: restricted — Board-user execution control API; agent receives eligible
new run/wake.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Steering requires a board user at the HTTP route. Native call_api
preserves this denial and cannot impersonate the steering user.
interrupt
Capability ID: steering/interrupt.
Review: baseline.
API: present — representative operation IDs:
POST /api/issues/{id}/queued-comments/interrupt.POST /api/heartbeat-runs/{runId}/cancel.
Agent access: restricted — Board-user interruption/cancel API.
Policy: Queue inspection follows task visibility; queued user-message mutation and run
cancellation require a board actor/user. The same queue endpoint accepts an explicit Send for a stopped native queue. It records fresh board intent, retains original comment authors, and keeps execution cleanup and admission gates. Agent Chat /new also retains native process, controller, workspace and lease checks before subsequent messages execute. It does not grant agents the ability to send saved user messages or interrupt live native turns.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Explicit operator action is distinct from an agent yielding/blocking its own turn.
stop-and-pause
Capability ID: steering/stop-and-pause.
Review: baseline.
API: present — representative operation IDs:
POST /api/issues/{id}/tree-holds.POST /api/agents/{id}/pause.
Agent access: restricted — Board control APIs; agent paperclip_finish/paperclip_block
for its own turn.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user. A saved pre-Stop message does not authorize automatic resumption. A later authorized user message may continue with retained input after current cleanup, ownership, and budget gates pass.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — assert the documented agent denial with an owned test fixture;
verify any listed agent request/result path separately. A delegated operation needs its
own policy and access review.
Gaps: Task-tree/agent pause and confirmed stop need policy-preserving authority; no generic agent management path.
drafts
Capability ID: steering/drafts.
Review: baseline.
API: not-applicable — No shared server draft resource for this presentation state;
cross-client drafts would be a deliberate new capability.
Agent access: not-applicable — Browser-local task composer draft / submission state.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — use the product recipe for the local/developer surface. Verify
listed shared-resource reads separately; local presentation alone is not agent API
evidence.
Gaps: No shared server draft resource for this presentation state; cross-client drafts would be a deliberate new capability.
approval-queue
Capability ID: steering/approval-queue.
Review: baseline.
API: present — representative operation IDs:
GET /api/issues/{id}/interactions.GET /api/issues/{id}/queued-comments.
Agent access: partial — Agent can inspect authorized persisted interactions; server
continuation/queue delivery.
Policy: Queue inspection follows task visibility; queued user-message mutation and run cancellation require a board actor/user.
Evidence: source-only — implementation at
the reviewed commit above.
Verification: not-run — exercise a listed permitted operation with actual agent
credentials/run context; inspect its result and applicable persistence/attribution.
Assert the relevant denied actor, owner, company or mode from Policy. Review the
remaining operations before qualifying the whole capability.
Gaps: Resolving as a human and controlling queued wakes is separate from seeing the approval response.