From cdbbac45d8c334c4a69f8f4f286b41e5a4e024bc Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 30 Jul 2026 13:23:42 -0400 Subject: [PATCH 1/2] docs(agent): require user approval for suggestions --- crates/quarry-server/resources/agent-docs.md | 13 +++++++++++++ crates/quarry-server/resources/prompt.md | 10 ++++++++++ crates/quarry-server/resources/quarry.SKILL.md | 17 ++++++++++++++++- crates/quarry-server/src/agent_prompt.rs | 17 +++++++++++++++++ .../quarry-server/tests/rest_agent_discovery.rs | 5 +++++ crates/quarry-server/tests/rest_onboarding.rs | 7 +++++++ 6 files changed, 68 insertions(+), 1 deletion(-) diff --git a/crates/quarry-server/resources/agent-docs.md b/crates/quarry-server/resources/agent-docs.md index 9d08b60..ded3f7b 100644 --- a/crates/quarry-server/resources/agent-docs.md +++ b/crates/quarry-server/resources/agent-docs.md @@ -320,6 +320,15 @@ operation. Do not send it. Read generated conflict items through `GET /review` and resolve them with the explicit conflict operations above. The legacy `comment.resolve` / `comment.delete` operations remain available for dismissal. +Creating a suggestion does not authorize deciding it. Never accept or reject +your own suggestion unless the user explicitly asks you to do so after the +suggestion exists. An earlier request to review, propose, or change content is +not that permission. After creating suggestions, wait for the user to review +them. Do not use edit operations, a whole-document PUT, or a sync operation to +apply or bypass a pending suggestion. The review is complete only when no open +suggestions remain and the user either decided them or explicitly asked you to +decide them. + A full review as one transaction: ```json @@ -633,6 +642,10 @@ Then report the evidence to the user. Do not keep retrying destructive writes. that scoped change; apply it, reply, and resolve the thread. - Prefer comments and suggestions for review requests, requested proposals, and unsolicited recommendations. +- Never decide a suggestion that you authored unless the user explicitly asks + you to do so after the suggestion exists. +- Do not use an edit, whole-document PUT, or sync operation to apply or bypass + a pending suggestion. - Never substitute a promise-to-edit reply for an authorized edit. - Re-read both `/blocks` and `/review` after any event; re-read `/blocks` after any stale write. diff --git a/crates/quarry-server/resources/prompt.md b/crates/quarry-server/resources/prompt.md index b7bef46..a01bcd9 100644 --- a/crates/quarry-server/resources/prompt.md +++ b/crates/quarry-server/resources/prompt.md @@ -19,6 +19,16 @@ quarry open "/absolute/path/to/file.md" When reviewing substantive changes to an existing Markdown document, first open it in Quarry and use suggestions for proposals or unsolicited changes. Apply a direct edit only when the user asks for that concrete change. +### Human approval for suggestions + +Creating a suggestion does not authorize accepting or rejecting it. + +- Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists. +- After you create suggestions, stop and wait for the user to review them. +- A request to review, propose, or change content does not authorize you to decide a suggestion later. The user must give that instruction after the suggestion exists. +- Do not use a direct edit, whole-document PUT, or sync operation to apply or bypass a pending suggestion. +- The review is complete only when no open suggestions remain and the user either decided them or explicitly asked you to decide them. + When the review process is complete, sync the content from Quarry back to the file on disk. ### Using Quarry diff --git a/crates/quarry-server/resources/quarry.SKILL.md b/crates/quarry-server/resources/quarry.SKILL.md index cec93a6..bb8770e 100644 --- a/crates/quarry-server/resources/quarry.SKILL.md +++ b/crates/quarry-server/resources/quarry.SKILL.md @@ -50,6 +50,20 @@ operation families share the same transaction envelope. To author or restructure a whole document, prefer the Markdown `PUT` (see Whole-Document Markdown Writes) over hand-assembling block ops. +## Suggestion Decisions + +Creating a suggestion does not authorize deciding it. + +- Never accept or reject your own suggestion unless the user explicitly asks + you to do so after the suggestion exists. +- After creating suggestions, wait for the user to review them. +- Do not treat an earlier request to review, propose, or change content as + permission to decide a later suggestion. +- Do not use edit operations, a whole-document `PUT`, or a sync operation to + apply or bypass a pending suggestion. +- Treat the review as complete only when no open suggestions remain and the + user either decided them or explicitly asked you to decide them. + ## Locator URLs And Auth Library locator URL format: @@ -341,7 +355,8 @@ action. To clear a review queue: decide suggestions (`suggestion.accept` / `suggestion.reject`), apply comment-requested prose changes with edit ops, resolve handled comments, then verify `GET $DOC/review` returns empty -`comments` and `suggestions`. +`comments` and `suggestions`. Decide a suggestion that you authored only after +the user gives an explicit instruction for that suggestion. ## Events diff --git a/crates/quarry-server/src/agent_prompt.rs b/crates/quarry-server/src/agent_prompt.rs index 6665236..63fca2d 100644 --- a/crates/quarry-server/src/agent_prompt.rs +++ b/crates/quarry-server/src/agent_prompt.rs @@ -129,6 +129,7 @@ Document path: {document_path} 6. Work only within the user's authorization. A task to review or leave feedback, comments, or suggestions authorizes review operations only; it does not authorize direct content edits. A request to change document content authorizes direct edits only within the requested scope. If no concrete Quarry task exists, wait. + Creating a suggestion does not authorize deciding it. Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists. An earlier request to review, propose, or change content is not that permission. After creating suggestions, wait for the user to review them. Do not use a direct edit or whole-document PUT to apply or bypass a pending suggestion. For surgical edits and review operations, POST {document_api}/transactions with headers Content-Type: application/json and X-Agent-Id: , and body {{"client_tx_id":"","base_clock":"","actor":{{"kind":"agent","id":"","label":""}},"ops":[...]}}. Public ops: {transaction_operations}. To author or restructure the whole document, instead PUT {document_api} with a plain Markdown body and headers Content-Type: text/markdown, If-Match: "", X-Agent-Id: , and X-Quarry-Transaction-Actor: — concurrent edits diff3-merge rather than being overwritten (details in the skill). A 200 response is not enough: inspect changed and conflicts. If conflicts is non-zero, re-read GET {document_api}/blocks and GET {document_api}/review, incorporate any canonical edits that should survive, and only then re-PUT the reconciled Markdown with the fresh clock. Do not blindly resend the old file. @@ -316,6 +317,22 @@ mod tests { assert!(!prompt.contains("further instructions")); } + #[test] + fn self_authored_suggestions_require_a_later_user_decision() { + let prompt = library_prompt(); + + assert!(prompt.contains("Creating a suggestion does not authorize deciding it")); + assert!(prompt.contains( + "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" + )); + assert!(prompt.contains( + "An earlier request to review, propose, or change content is not that permission" + )); + assert!(prompt.contains( + "Do not use a direct edit or whole-document PUT to apply or bypass a pending suggestion" + )); + } + #[test] fn trailing_origin_slash_is_normalized() { let prompt = agent_prompt( diff --git a/crates/quarry-server/tests/rest_agent_discovery.rs b/crates/quarry-server/tests/rest_agent_discovery.rs index a02d9a2..2bbb401 100644 --- a/crates/quarry-server/tests/rest_agent_discovery.rs +++ b/crates/quarry-server/tests/rest_agent_discovery.rs @@ -157,6 +157,11 @@ async fn agent_discovery_endpoints_expose_skill_docs_and_metadata() -> anyhow::R "A task to review or leave feedback, comments, or suggestions authorizes review operations only" )); assert!(surface.contains("it does not authorize direct content edits")); + assert!(surface.contains("Creating a suggestion does not authorize deciding it")); + assert!(surface.contains( + "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" + )); + assert!(surface.contains("apply or bypass a pending suggestion")); assert!(surface.contains("If no concrete Quarry task exists")); } assert!(!skill.contains("Wait for the user's instruction")); diff --git a/crates/quarry-server/tests/rest_onboarding.rs b/crates/quarry-server/tests/rest_onboarding.rs index cfdf132..21ad0c1 100644 --- a/crates/quarry-server/tests/rest_onboarding.rs +++ b/crates/quarry-server/tests/rest_onboarding.rs @@ -95,6 +95,13 @@ async fn prompt_document_teaches_the_review_workflow() { assert!(body.contains("quarry open")); assert!(body.contains("### Share a newly written document")); assert!(body.contains("### Editing existing documents")); + assert!(body.contains("### Human approval for suggestions")); + assert!(body.contains( + "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" + )); + assert!(body.contains( + "Do not use a direct edit, whole-document PUT, or sync operation to apply or bypass a pending suggestion" + )); assert!(body.contains("sync the content from Quarry back to the file on disk")); assert!(body.contains("creates the shared document")); assert!(body.contains("Instructions given before the document opens remain valid")); From 7fc5b200a08c646bd09b9f1622672f90c6d21b1e Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 30 Jul 2026 13:40:57 -0400 Subject: [PATCH 2/2] docs(agent): simplify suggestion guidance --- crates/quarry-server/resources/agent-docs.md | 13 ----------- crates/quarry-server/resources/prompt.md | 12 +--------- .../quarry-server/resources/quarry.SKILL.md | 22 ++++--------------- crates/quarry-server/src/agent_prompt.rs | 17 -------------- .../tests/rest_agent_discovery.rs | 6 +---- crates/quarry-server/tests/rest_onboarding.rs | 8 +------ 6 files changed, 7 insertions(+), 71 deletions(-) diff --git a/crates/quarry-server/resources/agent-docs.md b/crates/quarry-server/resources/agent-docs.md index ded3f7b..9d08b60 100644 --- a/crates/quarry-server/resources/agent-docs.md +++ b/crates/quarry-server/resources/agent-docs.md @@ -320,15 +320,6 @@ operation. Do not send it. Read generated conflict items through `GET /review` and resolve them with the explicit conflict operations above. The legacy `comment.resolve` / `comment.delete` operations remain available for dismissal. -Creating a suggestion does not authorize deciding it. Never accept or reject -your own suggestion unless the user explicitly asks you to do so after the -suggestion exists. An earlier request to review, propose, or change content is -not that permission. After creating suggestions, wait for the user to review -them. Do not use edit operations, a whole-document PUT, or a sync operation to -apply or bypass a pending suggestion. The review is complete only when no open -suggestions remain and the user either decided them or explicitly asked you to -decide them. - A full review as one transaction: ```json @@ -642,10 +633,6 @@ Then report the evidence to the user. Do not keep retrying destructive writes. that scoped change; apply it, reply, and resolve the thread. - Prefer comments and suggestions for review requests, requested proposals, and unsolicited recommendations. -- Never decide a suggestion that you authored unless the user explicitly asks - you to do so after the suggestion exists. -- Do not use an edit, whole-document PUT, or sync operation to apply or bypass - a pending suggestion. - Never substitute a promise-to-edit reply for an authorized edit. - Re-read both `/blocks` and `/review` after any event; re-read `/blocks` after any stale write. diff --git a/crates/quarry-server/resources/prompt.md b/crates/quarry-server/resources/prompt.md index a01bcd9..8262ed4 100644 --- a/crates/quarry-server/resources/prompt.md +++ b/crates/quarry-server/resources/prompt.md @@ -17,17 +17,7 @@ quarry open "/absolute/path/to/file.md" ### Editing existing documents -When reviewing substantive changes to an existing Markdown document, first open it in Quarry and use suggestions for proposals or unsolicited changes. Apply a direct edit only when the user asks for that concrete change. - -### Human approval for suggestions - -Creating a suggestion does not authorize accepting or rejecting it. - -- Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists. -- After you create suggestions, stop and wait for the user to review them. -- A request to review, propose, or change content does not authorize you to decide a suggestion later. The user must give that instruction after the suggestion exists. -- Do not use a direct edit, whole-document PUT, or sync operation to apply or bypass a pending suggestion. -- The review is complete only when no open suggestions remain and the user either decided them or explicitly asked you to decide them. +When reviewing substantive changes to an existing Markdown document, first open it in Quarry and use suggestions for proposals or unsolicited changes. Apply a direct edit only when the user asks for that concrete change. Leave suggestions for the user to accept or reject. When the review process is complete, sync the content from Quarry back to the file on disk. diff --git a/crates/quarry-server/resources/quarry.SKILL.md b/crates/quarry-server/resources/quarry.SKILL.md index bb8770e..b818674 100644 --- a/crates/quarry-server/resources/quarry.SKILL.md +++ b/crates/quarry-server/resources/quarry.SKILL.md @@ -45,25 +45,12 @@ A concrete imperative Quarry comment such as “Add this section,” “Change t wording,” or “Remove this block” is a direct-edit instruction for that scoped change; do the work, reply to the comment, and resolve the addressed thread. Do not respond only with a promise or proposal. Unsolicited changes, and changes -the user explicitly asks to review before applying, stay as suggestions. Both -operation families share the same transaction envelope. To author or +the user explicitly asks to review before applying, stay as suggestions. +Leave suggestions for the user to accept or reject. +Both operation families share the same transaction envelope. To author or restructure a whole document, prefer the Markdown `PUT` (see Whole-Document Markdown Writes) over hand-assembling block ops. -## Suggestion Decisions - -Creating a suggestion does not authorize deciding it. - -- Never accept or reject your own suggestion unless the user explicitly asks - you to do so after the suggestion exists. -- After creating suggestions, wait for the user to review them. -- Do not treat an earlier request to review, propose, or change content as - permission to decide a later suggestion. -- Do not use edit operations, a whole-document `PUT`, or a sync operation to - apply or bypass a pending suggestion. -- Treat the review as complete only when no open suggestions remain and the - user either decided them or explicitly asked you to decide them. - ## Locator URLs And Auth Library locator URL format: @@ -355,8 +342,7 @@ action. To clear a review queue: decide suggestions (`suggestion.accept` / `suggestion.reject`), apply comment-requested prose changes with edit ops, resolve handled comments, then verify `GET $DOC/review` returns empty -`comments` and `suggestions`. Decide a suggestion that you authored only after -the user gives an explicit instruction for that suggestion. +`comments` and `suggestions`. ## Events diff --git a/crates/quarry-server/src/agent_prompt.rs b/crates/quarry-server/src/agent_prompt.rs index 63fca2d..6665236 100644 --- a/crates/quarry-server/src/agent_prompt.rs +++ b/crates/quarry-server/src/agent_prompt.rs @@ -129,7 +129,6 @@ Document path: {document_path} 6. Work only within the user's authorization. A task to review or leave feedback, comments, or suggestions authorizes review operations only; it does not authorize direct content edits. A request to change document content authorizes direct edits only within the requested scope. If no concrete Quarry task exists, wait. - Creating a suggestion does not authorize deciding it. Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists. An earlier request to review, propose, or change content is not that permission. After creating suggestions, wait for the user to review them. Do not use a direct edit or whole-document PUT to apply or bypass a pending suggestion. For surgical edits and review operations, POST {document_api}/transactions with headers Content-Type: application/json and X-Agent-Id: , and body {{"client_tx_id":"","base_clock":"","actor":{{"kind":"agent","id":"","label":""}},"ops":[...]}}. Public ops: {transaction_operations}. To author or restructure the whole document, instead PUT {document_api} with a plain Markdown body and headers Content-Type: text/markdown, If-Match: "", X-Agent-Id: , and X-Quarry-Transaction-Actor: — concurrent edits diff3-merge rather than being overwritten (details in the skill). A 200 response is not enough: inspect changed and conflicts. If conflicts is non-zero, re-read GET {document_api}/blocks and GET {document_api}/review, incorporate any canonical edits that should survive, and only then re-PUT the reconciled Markdown with the fresh clock. Do not blindly resend the old file. @@ -317,22 +316,6 @@ mod tests { assert!(!prompt.contains("further instructions")); } - #[test] - fn self_authored_suggestions_require_a_later_user_decision() { - let prompt = library_prompt(); - - assert!(prompt.contains("Creating a suggestion does not authorize deciding it")); - assert!(prompt.contains( - "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" - )); - assert!(prompt.contains( - "An earlier request to review, propose, or change content is not that permission" - )); - assert!(prompt.contains( - "Do not use a direct edit or whole-document PUT to apply or bypass a pending suggestion" - )); - } - #[test] fn trailing_origin_slash_is_normalized() { let prompt = agent_prompt( diff --git a/crates/quarry-server/tests/rest_agent_discovery.rs b/crates/quarry-server/tests/rest_agent_discovery.rs index 2bbb401..0840257 100644 --- a/crates/quarry-server/tests/rest_agent_discovery.rs +++ b/crates/quarry-server/tests/rest_agent_discovery.rs @@ -157,13 +157,9 @@ async fn agent_discovery_endpoints_expose_skill_docs_and_metadata() -> anyhow::R "A task to review or leave feedback, comments, or suggestions authorizes review operations only" )); assert!(surface.contains("it does not authorize direct content edits")); - assert!(surface.contains("Creating a suggestion does not authorize deciding it")); - assert!(surface.contains( - "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" - )); - assert!(surface.contains("apply or bypass a pending suggestion")); assert!(surface.contains("If no concrete Quarry task exists")); } + assert!(skill.contains("Leave suggestions for the user to accept or reject")); assert!(!skill.contains("Wait for the user's instruction")); assert!(!docs.contains("instruction in the same request")); assert!(docs.contains("/v1/tmp/documents/$SECRET")); diff --git a/crates/quarry-server/tests/rest_onboarding.rs b/crates/quarry-server/tests/rest_onboarding.rs index 21ad0c1..f00bc44 100644 --- a/crates/quarry-server/tests/rest_onboarding.rs +++ b/crates/quarry-server/tests/rest_onboarding.rs @@ -95,13 +95,7 @@ async fn prompt_document_teaches_the_review_workflow() { assert!(body.contains("quarry open")); assert!(body.contains("### Share a newly written document")); assert!(body.contains("### Editing existing documents")); - assert!(body.contains("### Human approval for suggestions")); - assert!(body.contains( - "Never accept or reject your own suggestion unless the user explicitly asks you to do so after the suggestion exists" - )); - assert!(body.contains( - "Do not use a direct edit, whole-document PUT, or sync operation to apply or bypass a pending suggestion" - )); + assert!(body.contains("Leave suggestions for the user to accept or reject")); assert!(body.contains("sync the content from Quarry back to the file on disk")); assert!(body.contains("creates the shared document")); assert!(body.contains("Instructions given before the document opens remain valid"));