Skip to content

write and edit cannot ask for a wider tier, and their refusal names no way out #2734

Closed

Description

@argszero

What is observed

The four tools that write — bash, pwsh, write, edit — sit under one sandbox tier and one set of writable roots. Only two of them can ask for a wider tier for one call.

A call to write or edit whose target lies outside every granted root is refused with a sentence that names the tier and the roots, and nothing else:

read-only sandbox: blocked file write to '/tmp/x/notes.md' — outside every root this tier grants (…)

The model is given no way to ask, and the sentence names no next step. The two shell tools say the opposite in the same situation — they refuse the command and then append retry this exact command once with sandbox_permissions + justification (available here: workspace-write, danger-full-access).

Why that is a problem

The model holds one body of knowledge about "what to do when the boundary stops me", and today that knowledge has two different answers depending on whether the call writes through a file tool or through a shell. A refusal with no exit invites the workaround instead of the question: echo the file from bash, which is the very tool that can ask — so the escalation moves from the front door to the side door, and the host is never told either way.

Consistency is not the aesthetic point. A call that can state why it needs a wider tier should be allowed to say so whether it writes bytes or runs a command, and the host should be the one deciding.

What the fix must satisfy

  1. The gate keys on the tools that consume the tier and the roots, not on the shell's names. One set, already named in the daemon (_ROOT_CONSUMING_TOOLS), is the thing that decides who may ask.
  2. The schemas advertise it. write and edit declare sandbox_permissions and justification with wording identical to the shell tools and an enum derived from the same single constant — not a second hand-copied list.
  3. The refusal says there is a way. A file refusal that has a wider tier available appends the same sentence the shell refusal appends, reusing with_retry_hint rather than writing a second phrasing; where no wider tier exists, nothing is appended.
  4. Nothing else moves. read, glob and grep stay outside the escalation surface (they consume no root, so there is nothing to widen), and the tier and the roots stay daemon-injected — a tool never chooses them.
  5. One call, then back. An approved escalation applies to that call alone; the next call is back at the session's default tier, and a refusal, an unanswered question or a timeout means the call does not run at all.

Acceptance

  • A write and an edit call carrying the pair and approved by the host run at the wider tier; the following call runs at the session default. Refused, unanswered and timed-out each leave the call unexecuted.
  • read, glob and grep carrying the pair ask nothing and behave as before.
  • All four writing tools declare both parameters identically, and the enum follows the one constant: changing that constant in a tool's own namespace changes that tool's schema, which a hand-copied literal cannot do.
  • A file refusal at read-only and at workspace-write carries the retry sentence naming the reachable tiers; at danger-full-access it carries none.
  • The existing escalation suite stays green, including the case that pins a tool without a tier cannot escalate.
  • CI green on all three platforms.

Activity

  1. argszero commented on Nov 6, 2026

    @argszero
    OwnerAuthor

    Handled by #2735

  2. argszero commented on Nov 6, 2026

    @argszero
    OwnerAuthor

    Correction to the last acceptance line, so a later reader does not read a pass into it.

    The acceptance asks for CI green on all three platforms. This repository's test workflow has two: .github/workflows/test.yml runs ubuntu-latest and windows-2025, and Agent.md states the same set. macOS appears only in .github/workflows/build-release.yml (macos-15), which is triggered by a tag and builds, signs and notarizes the package — it does not run this suite.

    So the readable criterion is: the two test legs green on the PR, plus the macOS leg green on the next tag build that ships this change. A cycle that reports "three platforms green" from a PR page would be reporting a reading that does not exist here, which is the failure this note exists to prevent.

    Nothing else in the acceptance changes, and this does not affect the code under review.

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